1
0
forked from cgvr/DeltaVR

implemented shape scanner

This commit is contained in:
2026-01-11 17:48:58 +02:00
parent 23c89e97ce
commit d2ac917db3
16 changed files with 1027 additions and 4 deletions

View File

@@ -0,0 +1,115 @@
using System;
using UnityEngine;
using UnityEngine.UI;
public class ArcheryRangeModelGenerationController : MonoBehaviour
{
public MicrophoneStand microphoneStand;
public PushableButton imageGenerationButton;
public PushableButton modelGenerationButton;
public string imageGenerationPromptSuffix = ", single object, front and side fully visible, realistic style, plain neutral background, clear details, soft studio lighting, true-to-scale";
public Texture2D GeneratedTexture { get; private set; }
public Image imageDisplay;
public GameObject GeneratedModel { get; private set; }
public float generatedObjectRotationSpeed = 10f;
public Transform modelDisplay;
public Material modelDisplayActiveMaterial;
public Transform wire;
public Material wireActiveMaterial;
private bool modelGenerationInProgress;
// Start is called before the first frame update
void Start()
{
imageGenerationButton.OnButtonPressed += InvokeImageGeneration;
modelGenerationButton.OnButtonPressed += InvokeModelGeneration;
modelGenerationInProgress = false;
}
// Update is called once per frame
void Update()
{
if (GeneratedModel != null)
{
GeneratedModel.transform.Rotate(Vector3.up, generatedObjectRotationSpeed * Time.deltaTime);
}
}
private async void InvokeImageGeneration()
{
string inputPrompt = microphoneStand.GetTextOutput();
string refinedPrompt = inputPrompt + imageGenerationPromptSuffix;
byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(refinedPrompt);
GeneratedTexture = CreateTexture(imageBytes);
Sprite sprite = CreateSprite(GeneratedTexture);
imageDisplay.sprite = sprite;
imageGenerationButton.Deactivate();
if (!modelGenerationInProgress)
{
modelGenerationButton.Deactivate();
}
}
private async void InvokeModelGeneration()
{
modelGenerationInProgress = true;
string encodedTexture = Convert.ToBase64String(GeneratedTexture.EncodeToJPG());
byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture);
GameObject spawnedObject = await PipelineManager.Instance.SpawnModel(encodedModel);
// Destroy previous generated object
Destroy(GeneratedModel);
spawnedObject.transform.parent = modelDisplay;
spawnedObject.transform.position = modelDisplay.position;
GeneratedModel = spawnedObject;
OnModelReady();
modelGenerationButton.Deactivate();
modelGenerationInProgress = false;
}
private Texture2D CreateTexture(byte[] imageBytes)
{
var tex = new Texture2D(2, 2, TextureFormat.RGBA32, false);
// ImageConversion.LoadImage returns bool (true = success)
if (!ImageConversion.LoadImage(tex, imageBytes, markNonReadable: false))
{
Destroy(tex);
throw new InvalidOperationException("Failed to decode image bytes into Texture2D.");
}
tex.filterMode = FilterMode.Bilinear;
tex.wrapMode = TextureWrapMode.Clamp;
return tex;
}
private Sprite CreateSprite(Texture2D tex)
{
var sprite = Sprite.Create(
tex,
new Rect(0, 0, tex.width, tex.height),
new Vector2(0.5f, 0.5f),
pixelsPerUnit: 100f
);
return sprite;
}
private void OnModelReady()
{
foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>())
{
meshRenderer.material = wireActiveMaterial;
}
modelDisplay.GetComponent<MeshRenderer>().material = modelDisplayActiveMaterial;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99e1fdda206b5d04082b6a45593a1e84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using TMPro;
using UnityEngine;
using Whisper;
using Whisper.Utils;
public class MicrophoneStand : MonoBehaviour
{
public WhisperManager whisper;
public MicrophoneRecord microphoneRecord;
public string microphoneDevice;
public TextMeshProUGUI outputText;
private WhisperStream stream;
private string textOutput;
public GameObject microphoneOffStatus;
public GameObject microphoneOnStatus;
// Start is called before the first frame update
async void Start()
{
Debug.Log("Mic devices: " + string.Join(", ", Microphone.devices));
Debug.Log("Using mic device: " + microphoneDevice);
microphoneRecord.SelectedMicDevice = microphoneDevice;
// This causes about 1 sec long freeze, has to be done once at the start of the game
microphoneRecord.StartRecord();
stream = await whisper.CreateStream(microphoneRecord);
stream.OnResultUpdated += OnWhisperResult;
//stream.StartStream();
microphoneOffStatus.SetActive(true);
microphoneOnStatus.SetActive(false);
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter(Collider other)
{
KbmController controller = other.GetComponent<KbmController>();
Debug.Log("Mic stand collided with object " + other.gameObject.name);
if (controller != null || other.gameObject.tag == "Player Head")
{
microphoneOffStatus.SetActive(false);
microphoneOnStatus.SetActive(true);
stream.StartStream();
//microphoneRecord.StartRecord();
Debug.Log("Whisper stream started.");
}
}
private void OnTriggerExit(Collider other)
{
KbmController controller = other.GetComponent<KbmController>();
if (controller != null | other.gameObject.tag == "Player Head")
{
microphoneOffStatus.SetActive(true);
microphoneOnStatus.SetActive(false);
stream.StopStream();
//microphoneRecord.StopRecord();
textOutput = outputText.text;
}
}
private void OnWhisperResult(string result)
{
Debug.Log("Whisper result processed: " + result);
outputText.text = result;
}
private void OnDestroy()
{
microphoneRecord.StopRecord();
Destroy(gameObject);
}
public string GetTextOutput()
{
return textOutput;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 357101b2cface4943b04dfd25d4944e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: