forked from cgvr/DeltaVR
scale spawned object to match given bounding sphere diameter
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<GameObject> SpawnModel(byte[] modelBinary)
|
||||
public async Task<GameObject> 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<GameObject> SpawnModel(GltfImport gltfImport, string objectName)
|
||||
public async Task<GameObject> 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<MeshRenderer>();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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>();
|
||||
XRGrabInteractable grabComponent = spawnedObject.AddComponent<XRGrabInteractable>();
|
||||
grabComponent.useDynamicAttach = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user