1
0
forked from cgvr/DeltaVR

set up shape detection minigame pieces

This commit is contained in:
2026-01-13 16:06:13 +02:00
parent d2ac917db3
commit 3097c404ba
11 changed files with 149 additions and 75 deletions

View File

@@ -147,7 +147,7 @@ public class ArcheryRange : NetworkBehaviour
{ {
// spawn generated model // spawn generated model
targetObject = Instantiate(modelGenerationController.GeneratedModel, randomPos, Quaternion.identity, null); targetObject = Instantiate(modelGenerationController.GeneratedModel, randomPos, Quaternion.identity, null);
InitializeArcherytargetObject(targetObject); InitializeArcheryTargetObject(targetObject);
} }
ArcheryTarget target = targetObject.GetComponent<ArcheryTarget>(); ArcheryTarget target = targetObject.GetComponent<ArcheryTarget>();
@@ -157,7 +157,7 @@ public class ArcheryRange : NetworkBehaviour
return target; return target;
} }
private void InitializeArcherytargetObject(GameObject targetObject) private void InitializeArcheryTargetObject(GameObject targetObject)
{ {
ArcheryTarget archeryTarget = targetObject.AddComponent<ArcheryTarget>(); ArcheryTarget archeryTarget = targetObject.AddComponent<ArcheryTarget>();
archeryTarget.pointsText = archeryTargetPointsText; archeryTarget.pointsText = archeryTargetPointsText;

View File

@@ -46,8 +46,8 @@ public class ArcheryRangeModelGenerationController : MonoBehaviour
byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(refinedPrompt); byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(refinedPrompt);
GeneratedTexture = CreateTexture(imageBytes); GeneratedTexture = ModelGenerationUtils.CreateTexture(imageBytes);
Sprite sprite = CreateSprite(GeneratedTexture); Sprite sprite = ModelGenerationUtils.CreateSprite(GeneratedTexture);
imageDisplay.sprite = sprite; imageDisplay.sprite = sprite;
imageGenerationButton.Deactivate(); imageGenerationButton.Deactivate();
@@ -63,7 +63,7 @@ public class ArcheryRangeModelGenerationController : MonoBehaviour
string encodedTexture = Convert.ToBase64String(GeneratedTexture.EncodeToJPG()); string encodedTexture = Convert.ToBase64String(GeneratedTexture.EncodeToJPG());
byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture); byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture);
GameObject spawnedObject = await PipelineManager.Instance.SpawnModel(encodedModel); GameObject spawnedObject = await ModelGenerationUtils.Instance.SpawnModel(encodedModel);
// Destroy previous generated object // Destroy previous generated object
Destroy(GeneratedModel); Destroy(GeneratedModel);
spawnedObject.transform.parent = modelDisplay; spawnedObject.transform.parent = modelDisplay;
@@ -75,34 +75,6 @@ public class ArcheryRangeModelGenerationController : MonoBehaviour
modelGenerationInProgress = false; 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() private void OnModelReady()
{ {
foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>()) foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>())

View File

@@ -44,40 +44,12 @@ void Start()
meshRenderer.material = loadingMaterial; meshRenderer.material = loadingMaterial;
byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(refinedPrompt); byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(refinedPrompt);
LastTexture = CreateTexture(imageBytes); LastTexture = ModelGenerationUtils.CreateTexture(imageBytes);
Sprite sprite = CreateSprite(LastTexture); Sprite sprite = ModelGenerationUtils.CreateSprite(LastTexture);
imageDisplay.sprite = sprite; imageDisplay.sprite = sprite;
isLoading = false; isLoading = false;
meshRenderer.material = inactiveMaterial; meshRenderer.material = inactiveMaterial;
} }
} }
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;
}
} }

View File

@@ -42,7 +42,7 @@ public class ModelGenerationBox : MonoBehaviour
string encodedTexture = Convert.ToBase64String(inputTexture.EncodeToJPG()); string encodedTexture = Convert.ToBase64String(inputTexture.EncodeToJPG());
byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture); byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture);
GameObject spawnedObject = await PipelineManager.Instance.SpawnModel(encodedModel); GameObject spawnedObject = await ModelGenerationUtils.Instance.SpawnModel(encodedModel);
spawnedObject.AddComponent<Rigidbody>(); spawnedObject.AddComponent<Rigidbody>();
spawnedObject.transform.parent = modelSpawnPoint; spawnedObject.transform.parent = modelSpawnPoint;
spawnedObject.transform.position = modelSpawnPoint.position; spawnedObject.transform.position = modelSpawnPoint.position;

View File

@@ -1,12 +1,13 @@
using GLTFast; using GLTFast;
using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
public class PipelineManager : MonoBehaviour public class ModelGenerationUtils : MonoBehaviour
{ {
public static PipelineManager Instance { get; private set; } public static ModelGenerationUtils Instance { get; private set; }
private void Awake() private void Awake()
{ {
@@ -27,7 +28,7 @@ public class PipelineManager : MonoBehaviour
/** /**
* Generate model by starting a new Python subprocess * Generate model by starting a new Python subprocess
* NOT USED ANYMORE * NOT USED IN LATEST VERSION
**/ **/
public async Task<string> GenerateModelAsync(string inputPrompt) public async Task<string> GenerateModelAsync(string inputPrompt)
{ {
@@ -82,7 +83,7 @@ public class PipelineManager : MonoBehaviour
/** /**
* Spawn model stored on disk * Spawn model stored on disk
* NOT USED ANYMORE * NOT USED IN LATEST VERSION
* *
**/ **/
public async Task<GameObject> SpawnModel(string modelPath) public async Task<GameObject> SpawnModel(string modelPath)
@@ -130,4 +131,33 @@ public class PipelineManager : MonoBehaviour
throw new System.Exception("Failed to spawn GameObject " + objectName); throw new System.Exception("Failed to spawn GameObject " + objectName);
} }
public static 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;
}
public static 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;
}
} }

View File

@@ -58,9 +58,12 @@ public class PushableButton : MonoBehaviour
movableParts.DOLocalMoveY(downPositionY, moveDuration); movableParts.DOLocalMoveY(downPositionY, moveDuration);
isButtonDown = true; isButtonDown = true;
foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>()) if (wire != null)
{ {
meshRenderer.material = wireActiveMaterial; foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>())
{
meshRenderer.material = wireActiveMaterial;
}
} }
} }
@@ -69,9 +72,12 @@ public class PushableButton : MonoBehaviour
movableParts.DOLocalMoveY(upPositionY, moveDuration); movableParts.DOLocalMoveY(upPositionY, moveDuration);
isButtonDown = false; isButtonDown = false;
foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>()) if (wire != null)
{ {
meshRenderer.material = wireInactiveMaterial; foreach (MeshRenderer meshRenderer in wire.GetComponentsInChildren<MeshRenderer>())
{
meshRenderer.material = wireInactiveMaterial;
}
} }
} }
} }

View File

@@ -0,0 +1,82 @@
using FishNet.Component.Transforming;
using FishNet.Object;
using System;
using UnityEngine;
using UnityEngine.UI;
public class ShapeDetectionMinigameController : 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 Transform modelSpawnPoint;
public string shapeScannerTag = "ShapeScannable";
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()
{
}
private async void InvokeImageGeneration()
{
string inputPrompt = microphoneStand.GetTextOutput();
string refinedPrompt = inputPrompt + imageGenerationPromptSuffix;
byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(refinedPrompt);
GeneratedTexture = ModelGenerationUtils.CreateTexture(imageBytes);
Sprite sprite = ModelGenerationUtils.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 ModelGenerationUtils.Instance.SpawnModel(encodedModel);
InitializeSpawnedObject(spawnedObject);
// Destroy previous generated object
Destroy(GeneratedModel);
GeneratedModel = spawnedObject;
modelGenerationButton.Deactivate();
modelGenerationInProgress = false;
}
private void InitializeSpawnedObject(GameObject spawnedObject)
{
Rigidbody rigidbody = spawnedObject.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
spawnedObject.AddComponent<NetworkObject>();
spawnedObject.AddComponent<NetworkTransform>();
spawnedObject.transform.parent = modelSpawnPoint;
spawnedObject.transform.position = modelSpawnPoint.position;
spawnedObject.tag = shapeScannerTag;
}
}

View File

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

View File

@@ -6,6 +6,7 @@ public class ShapeScannerRay : MonoBehaviour
{ {
public Material _activeMaterial; public Material _activeMaterial;
public Material _passiveMaterial; public Material _passiveMaterial;
public string scannableTag = "ShapeScannable";
private ShapeScanner _scanner; private ShapeScanner _scanner;
private MeshRenderer meshRenderer; private MeshRenderer meshRenderer;
@@ -33,7 +34,7 @@ public class ShapeScannerRay : MonoBehaviour
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other)
{ {
if (other.gameObject.tag == "ShapeScannable") if (other.gameObject.tag == scannableTag)
{ {
meshRenderer.material = _activeMaterial; meshRenderer.material = _activeMaterial;
if (_collisionRequired) if (_collisionRequired)