From 7384a21d58ef9bcc23be2c3754f6c2cda013da12 Mon Sep 17 00:00:00 2001 From: henrisel Date: Sat, 7 Feb 2026 14:10:12 +0200 Subject: [PATCH] scale spawned object to match given bounding sphere diameter --- 3d-generation-pipeline/README.md | 6 +- .../ModeGeneration/ModelGenerationUtils.cs | 57 ++++++++++++++++--- .../ModeGeneration/NPCs/CafeWaiterNPC.cs | 6 +- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/3d-generation-pipeline/README.md b/3d-generation-pipeline/README.md index 7154c6a1..f1451fb5 100644 --- a/3d-generation-pipeline/README.md +++ b/3d-generation-pipeline/README.md @@ -1,5 +1,4 @@ ### TODO -* võtta spawnitud mudeli mõõtmed: meshcollideri max x, max y, etc? bounding box? ja kontrollida spawnimisel scale'i * shape scanner: * peenikesemad kiired * mitte lihtsalt ontriggerenter ja -exit, sest kui mitu objekti lähevad samal ajal sisse @@ -19,5 +18,10 @@ Can't/Won't Do: ### Notes +* Functionalities that were implemented using major help from AI: + * animating NPC mouth movement based on voice amplitude + * adjusting spawned gltf objects' scale + * porting InvokeAI client and TRELLIS client to Unity scripts + * Getting Whisper stream to work with FMOD instead of Unity default audio * TRELLIS: added functionality to specify texture baking optimisation total steps as an argument (`texture_opt_total_steps`), to replace the hardcoded 2500. But this is not tracked in Git (because modified this https://github.com/IgorAherne/trellis-stable-projectorz/releases/tag/latest) * Custom Shader Variant Collection to include glTF-pbrMetallicRoughness shader in build diff --git a/Assets/_PROJECT/Scripts/ModeGeneration/ModelGenerationUtils.cs b/Assets/_PROJECT/Scripts/ModeGeneration/ModelGenerationUtils.cs index 52bcd795..a68048c0 100644 --- a/Assets/_PROJECT/Scripts/ModeGeneration/ModelGenerationUtils.cs +++ b/Assets/_PROJECT/Scripts/ModeGeneration/ModelGenerationUtils.cs @@ -76,7 +76,7 @@ public class ModelGenerationUtils : MonoBehaviour } } - throw new System.Exception("Failed to generate 3D model!"); + throw new Exception("Failed to generate 3D model!"); } }); } @@ -96,22 +96,22 @@ public class ModelGenerationUtils : MonoBehaviour return await SpawnModel(gltf, objectName); } - throw new System.Exception("Failed to load GameObject from model" + modelPath); + throw new Exception("Failed to load GameObject from model" + modelPath); } - public async Task SpawnModel(byte[] modelBinary) + public async Task SpawnModel(byte[] modelBinary, float boundingSphereDiameter = 0) { var gltf = new GltfImport(); bool loadSuccess = await gltf.Load(modelBinary); if (loadSuccess) { - return await SpawnModel(gltf, "GeneratedModel"); + return await SpawnModel(gltf, "GeneratedModel", boundingSphereDiameter); } - throw new System.Exception("Failed to load GameObject from binary!"); + throw new Exception("Failed to load GameObject from binary!"); } - public async Task SpawnModel(GltfImport gltfImport, string objectName) + public async Task SpawnModel(GltfImport gltfImport, string objectName, float boundingSphereDiameter = 0) { GameObject spawningParent = new GameObject("Parent-" + objectName); @@ -125,11 +125,54 @@ public class ModelGenerationUtils : MonoBehaviour MeshRenderer renderer = spawnedObjectBody.GetComponent(); renderer.material.SetFloat("metallicFactor", 0); + AdjustScale(spawnedObjectBody, collider, boundingSphereDiameter); + spawnedObjectBody.name = objectName; return spawnedObjectBody; } - throw new System.Exception("Failed to spawn GameObject " + objectName); + throw new Exception("Failed to spawn GameObject " + objectName); + } + + private async void AdjustScale(GameObject obj, MeshCollider collider, float boundingSphereDiameter) + { + + // Wait one frame to ensure collider cooking & bounds are valid + await Task.Yield(); + + // --- Compute current bounding sphere diameter (from world AABB) --- + Bounds b = collider.bounds; // world-space AABB + float currentDiameter = 2f * b.extents.magnitude; + + if (boundingSphereDiameter <= 0f) + { + UnityEngine.Debug.Log("Not adjusting scale"); + return; + } + + if (currentDiameter <= Mathf.Epsilon) + throw new Exception("Spawned mesh has zero-sized bounds; cannot scale to target diameter."); + + // --- Compute and apply uniform scale --- + float scaleFactor = boundingSphereDiameter / currentDiameter; + obj.transform.localScale *= scaleFactor; + + // Give Unity a moment to recompute bounds after scaling, then do a corrective pass + await Task.Yield(); + + // Corrective pass (optional): re-measure and nudge scale to reduce residual error + Bounds b2 = collider.bounds; + float newDiameter = 2f * b2.extents.magnitude; + + // Only correct if off by more than a tiny epsilon (1%) + const float tolerance = 0.01f; // 1% + float err = Mathf.Abs(newDiameter - boundingSphereDiameter) / boundingSphereDiameter; + if (err > tolerance && newDiameter > Mathf.Epsilon) + { + float correction = boundingSphereDiameter / newDiameter; + obj.transform.localScale *= correction; + // No need to wait again unless you need to read back the final diameter immediately + } } diff --git a/Assets/_PROJECT/Scripts/ModeGeneration/NPCs/CafeWaiterNPC.cs b/Assets/_PROJECT/Scripts/ModeGeneration/NPCs/CafeWaiterNPC.cs index 33a8184a..aef4335d 100644 --- a/Assets/_PROJECT/Scripts/ModeGeneration/NPCs/CafeWaiterNPC.cs +++ b/Assets/_PROJECT/Scripts/ModeGeneration/NPCs/CafeWaiterNPC.cs @@ -13,6 +13,7 @@ public class CafeWaiterNPC : NPCController public Transform backRoom; public Transform plate; public float backRoomMovingTime = 5f; + public float spawnedFoodDiameter = 0.5f; public int ignorePlayerCollisionLayer = 2; @@ -135,7 +136,7 @@ public class CafeWaiterNPC : NPCController Sprite sprite = ModelGenerationUtils.CreateSprite(GeneratedTexture); string encodedTexture = Convert.ToBase64String(GeneratedTexture.EncodeToJPG()); byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture); - GameObject spawnedObject = await ModelGenerationUtils.Instance.SpawnModel(encodedModel); + GameObject spawnedObject = await ModelGenerationUtils.Instance.SpawnModel(encodedModel, spawnedFoodDiameter); // Come back transform.DOMove(startingPosition, backRoomMovingTime).OnComplete(() => @@ -160,6 +161,7 @@ public class CafeWaiterNPC : NPCController spawnedObjectCollider.convex = true; spawnedObject.layer = ignorePlayerCollisionLayer; - spawnedObject.AddComponent(); + XRGrabInteractable grabComponent = spawnedObject.AddComponent(); + grabComponent.useDynamicAttach = true; } }