disable physics test in instancing

This commit is contained in:
Nick Fisher
2025-06-26 08:47:22 +08:00
parent fac0c727e4
commit f4b473b9ae

View File

@@ -77,9 +77,7 @@ void main() async {
var asset = await viewer.loadGltf( var asset = await viewer.loadGltf(
"file://${testHelper.testDir}/assets/cube.glb", "file://${testHelper.testDir}/assets/cube.glb",
addToScene: false, addToScene: false,
numInstances: 2, numInstances: 2, keepData: true);
keepData: true
);
var defaultInstance = await asset.getInstance(0); var defaultInstance = await asset.getInstance(0);
await viewer.addToScene(defaultInstance); await viewer.addToScene(defaultInstance);
await testHelper.capture(viewer.view, "gltf_without_instance"); await testHelper.capture(viewer.view, "gltf_without_instance");
@@ -103,157 +101,157 @@ void main() async {
}, addSkybox: true); }, addSkybox: true);
}); });
test('physics simulation with 100 instances', () async { // test('physics simulation with 100 instances', () async {
await testHelper.withViewer((viewer) async { // await testHelper.withViewer((viewer) async {
// --- Scene Setup --- // // --- Scene Setup ---
await viewer // await viewer
.loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx"); // .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
await viewer.loadSkybox( // await viewer.loadSkybox(
"file://${testHelper.testDir}/assets/default_env_skybox.ktx"); // "file://${testHelper.testDir}/assets/default_env_skybox.ktx");
await viewer.setPostProcessing(true); // await viewer.setPostProcessing(true);
await viewer.setAntiAliasing(false, true, false); // Enable FXAA // await viewer.setAntiAliasing(false, true, false); // Enable FXAA
final camera = await viewer.getActiveCamera(); // final camera = await viewer.getActiveCamera();
final orbitDist = 12.0; // Slightly further back to see spread pattern // final orbitDist = 12.0; // Slightly further back to see spread pattern
final lookAtTarget = Vector3(0, 0.5, 0); // Look at middle of trajectory // final lookAtTarget = Vector3(0, 0.5, 0); // Look at middle of trajectory
// --- Load Asset & Create/Prepare Instances --- // // --- Load Asset & Create/Prepare Instances ---
print("Loading asset..."); // print("Loading asset...");
var numInstances = 100; // var numInstances = 100;
var asset = await viewer.loadGltf( // var asset = await viewer.loadGltf(
"file://${testHelper.testDir}/assets/cube.glb", // "file://${testHelper.testDir}/assets/cube.glb",
numInstances: numInstances, // numInstances: numInstances,
addToScene: false, keepData: true); // addToScene: false, keepData: true);
print("Creating 100 instances..."); // print("Creating 100 instances...");
List<PhysicsState> instanceStates = []; // List<PhysicsState> instanceStates = [];
final rnd = Random(); // final rnd = Random();
for (int i = 0; i < numInstances - 1; i++) { // for (int i = 0; i < numInstances - 1; i++) {
var mi = await FilamentApp.instance! // var mi = await FilamentApp.instance!
.createUbershaderMaterialInstance(unlit: true); // .createUbershaderMaterialInstance(unlit: true);
var instance = await asset.createInstance(materialInstances: [mi]); // var instance = await asset.createInstance(materialInstances: [mi]);
await viewer.removeFromScene(instance); // await viewer.removeFromScene(instance);
await mi.setParameterFloat4("baseColorFactor", rnd.nextDouble(), // await mi.setParameterFloat4("baseColorFactor", rnd.nextDouble(),
rnd.nextDouble(), rnd.nextDouble(), 1.0); // rnd.nextDouble(), rnd.nextDouble(), 1.0);
var scale = max(0.25, rnd.nextDouble()); // var scale = max(0.25, rnd.nextDouble());
instanceStates.add(PhysicsState(instance, scale)); // instanceStates.add(PhysicsState(instance, scale));
} // }
print("Instances created and colored."); // print("Instances created and colored.");
// --- Simulation Parameters --- // // --- Simulation Parameters ---
final gravity = Vector3(0, -9.81, 0); // final gravity = Vector3(0, -9.81, 0);
// Calculate initial velocity to reach 1 meter in 1 second // // Calculate initial velocity to reach 1 meter in 1 second
// Using kinematics: y = v0*t + 0.5*a*t^2 // // Using kinematics: y = v0*t + 0.5*a*t^2
// At t=1s, y=1m, a=-9.81m/s^2 // // At t=1s, y=1m, a=-9.81m/s^2
// Solving for v0: v0 = 1 - 0.5*(-9.81)*1^2 = 1 + 4.905 = 5.905 m/s // // Solving for v0: v0 = 1 - 0.5*(-9.81)*1^2 = 1 + 4.905 = 5.905 m/s
final initialUpwardSpeed = 5.905; // Calculated for 1m height in 1s // final initialUpwardSpeed = 5.905; // Calculated for 1m height in 1s
final timeStep = 1 / 60.0; // Simulate at 60 FPS // final timeStep = 1 / 60.0; // Simulate at 60 FPS
final frameDuration = // final frameDuration =
Duration(microseconds: (timeStep * 1000000).round()); // Duration(microseconds: (timeStep * 1000000).round());
final launchInterval = 0.5; // 100 ms between launches // final launchInterval = 0.5; // 100 ms between launches
final totalSimulationTime = 20.0; // Simulation duration in seconds // final totalSimulationTime = 20.0; // Simulation duration in seconds
final orbitDuration = 10.0; // Time for one full camera orbit // final orbitDuration = 10.0; // Time for one full camera orbit
// --- Simulation Loop --- // // --- Simulation Loop ---
double currentTime = 0.0; // double currentTime = 0.0;
double timeSinceLastLaunch = // double timeSinceLastLaunch =
launchInterval; // Start launching immediately // launchInterval; // Start launching immediately
int launchedCount = 0; // int launchedCount = 0;
int frameCounter = 0; // int frameCounter = 0;
int captureCounter = 0; // int captureCounter = 0;
print("Starting simulation loop (${totalSimulationTime}s)..."); // print("Starting simulation loop (${totalSimulationTime}s)...");
final startTime = DateTime.now(); // final startTime = DateTime.now();
while (currentTime < totalSimulationTime) { // while (currentTime < totalSimulationTime) {
final loopStart = DateTime.now(); // final loopStart = DateTime.now();
// 1. Launch Instance Logic // // 1. Launch Instance Logic
if (launchedCount < instanceStates.length && // if (launchedCount < instanceStates.length &&
timeSinceLastLaunch >= launchInterval) { // timeSinceLastLaunch >= launchInterval) {
final state = instanceStates[launchedCount]; // final state = instanceStates[launchedCount];
if (!state.launched) { // if (!state.launched) {
print("Launching instance ${launchedCount + 1}/100"); // print("Launching instance ${launchedCount + 1}/100");
// Add a slight angle to launch direction // // Add a slight angle to launch direction
// Using a spiral pattern with increasing angle // // Using a spiral pattern with increasing angle
final angle = (launchedCount * 0.2) % // final angle = (launchedCount * 0.2) %
(2 * pi); // Increasing angle creating spiral // (2 * pi); // Increasing angle creating spiral
final horizontalComponent = // final horizontalComponent =
initialUpwardSpeed * 0.15; // 15% horizontal velocity // initialUpwardSpeed * 0.15; // 15% horizontal velocity
state.velocity = Vector3( // state.velocity = Vector3(
horizontalComponent * cos(angle), // horizontalComponent * cos(angle),
initialUpwardSpeed, // initialUpwardSpeed,
horizontalComponent * sin(angle)); // Angled velocity // horizontalComponent * sin(angle)); // Angled velocity
state.position = Vector3(0, 0.1, 0); // Start slightly above origin // state.position = Vector3(0, 0.1, 0); // Start slightly above origin
state.launched = true; // state.launched = true;
await viewer // await viewer
.addToScene(state.instance); // Add to scene ONLY when launched // .addToScene(state.instance); // Add to scene ONLY when launched
state.addedToScene = true; // state.addedToScene = true;
launchedCount++; // launchedCount++;
timeSinceLastLaunch -= launchInterval; // timeSinceLastLaunch -= launchInterval;
} // }
} // }
// 2. Update Physics and Transforms for launched instances // // 2. Update Physics and Transforms for launched instances
List<Future> transformUpdates = []; // List<Future> transformUpdates = [];
for (var state in instanceStates) { // for (var state in instanceStates) {
if (state.launched) { // if (state.launched) {
// Basic Euler integration // // Basic Euler integration
state.velocity.add(gravity * timeStep); // state.velocity.add(gravity * timeStep);
state.position.add(state.velocity * timeStep); // state.position.add(state.velocity * timeStep);
// Queue the asynchronous transform update // // Queue the asynchronous transform update
transformUpdates.add(state.instance.setTransform(Matrix4.compose( // transformUpdates.add(state.instance.setTransform(Matrix4.compose(
state.position, // state.position,
Quaternion.identity(), // Quaternion.identity(),
Vector3.all(state.scale)))); // Vector3.all(state.scale))));
} // }
} // }
// Wait for all instance transforms in this step to complete // // Wait for all instance transforms in this step to complete
if (transformUpdates.isNotEmpty) { // if (transformUpdates.isNotEmpty) {
await Future.wait(transformUpdates); // await Future.wait(transformUpdates);
} // }
// 3. Update Camera Orbit // // 3. Update Camera Orbit
final angle = (currentTime / orbitDuration) * 2 * pi; // final angle = (currentTime / orbitDuration) * 2 * pi;
await camera.lookAt( // await camera.lookAt(
Vector3( // Vector3(
sin(angle) * orbitDist, // sin(angle) * orbitDist,
orbitDist * 0.3, // Lower camera height to see 1-meter trajectories // orbitDist * 0.3, // Lower camera height to see 1-meter trajectories
cos(angle) * orbitDist, // cos(angle) * orbitDist,
), // ),
focus: lookAtTarget, // Point towards the peak of trajectories // focus: lookAtTarget, // Point towards the peak of trajectories
up: Vector3(0, 1, 0), // Keep up vector standard // up: Vector3(0, 1, 0), // Keep up vector standard
); // );
// 4. Capture Frame Periodically (e.g., every 6 physics steps => 10 captures/sec) // // 4. Capture Frame Periodically (e.g., every 6 physics steps => 10 captures/sec)
if (frameCounter % 6 == 0) { // if (frameCounter % 6 == 0) {
await testHelper.capture(viewer.view, // await testHelper.capture(viewer.view,
"capture_physics_orbit_${captureCounter.toString().padLeft(3, '0')}"); // "capture_physics_orbit_${captureCounter.toString().padLeft(3, '0')}");
captureCounter++; // captureCounter++;
} // }
// 5. Advance Time and Wait // // 5. Advance Time and Wait
currentTime += timeStep; // currentTime += timeStep;
timeSinceLastLaunch += timeStep; // timeSinceLastLaunch += timeStep;
frameCounter++; // frameCounter++;
// Ensure the loop doesn't run faster than the desired frame rate // // Ensure the loop doesn't run faster than the desired frame rate
final elapsed = loopStart.difference(loopStart); // final elapsed = loopStart.difference(loopStart);
if (elapsed < frameDuration) { // if (elapsed < frameDuration) {
await Future.delayed(frameDuration - elapsed); // await Future.delayed(frameDuration - elapsed);
} // }
} // }
final endTime = DateTime.now(); // final endTime = DateTime.now();
print( // print(
"Simulation loop finished in ${endTime.difference(startTime).inSeconds} seconds."); // "Simulation loop finished in ${endTime.difference(startTime).inSeconds} seconds.");
print("Captured $captureCounter frames."); // print("Captured $captureCounter frames.");
// Optional: Capture one final frame after simulation ends // // Optional: Capture one final frame after simulation ends
await testHelper.capture(viewer.view, "capture_physics_orbit_final"); // await testHelper.capture(viewer.view, "capture_physics_orbit_final");
}, viewportDimensions: (width: 1024, height: 1024)); // End withViewer // }, viewportDimensions: (width: 1024, height: 1024)); // End withViewer
}); // });
} }