Thanks for your effort.
So maybe this means, you recommend Rapier to me?
Rapier looks faster for this objects
It’s also important to use real world scales for the objects you’re simulating, and generally engines assume 1 unit = 1 meter…
so cubes of size 1x1x1 are the ideal primitive size. This matters because the engines math is tuned to work best within these ranges, and there are “margins” used that are on the order of like .1 or .01 that are used to separate objects etc. So if you’re using cubes that are .1 sized, you might see .1 sized gaps between them when stacking, etc.
Setting up robust physics simulations is an art.
Yeah, actually since I won’t use cube directly in project, it’s no matter whether there is a gap or not when stacking.
Box is simulated as bound.
But thanks for giving me tips for understanding physics world better!
Rapier… then I will give it a try.
Ofc I will find it on google, but if you know any good references to start rapier, could you kindly share?
With Physijs (threejs’ed ammo under the hood) I get approx 50 fps for 300 cubes falling onto heightmap – i.e. not flat surface. You may get other fps on your machine.
Oh, yeah…
I get less than 40fps…
I would also be careful judging any single engine with a microbenchmark like cube stacking. It is an important datapoint, but quality physics engines have to do a lot more behind the scenes, like identifying simulation islands, and efficiently managing updates/sleeping… using different techniques for collision based on the types of primitives… managing broadphase (coarse) collision detection vs accurate collision, then also supporting things like constraints, contact callbacks.
For a wall stack of 300 blocks, using Jolt, I’m getting from ~14-40fps ramping up to 60fps once the pile has gone to sleep.
How beautiful your scene is!!!
Actually if I make a character control game and have to choose physics engine for that, I would be more careful.
But today, what I need is falling hundreds of just cube, and one more custom shape - cone.
So, tbh, fps when most of cubes are active is important for me.
Sorry, but Jolt seems less efficient in this case, maybe…
Yeah for a simple sim, most engines will probably work. Have fun!
Yeah, I am gonna try Rapier as @Chaser_Code suggested.
Thanks!
IMHO, explosion comes from dropped frames
: the world step and clock. Objects become advanced beyond an imprecise limit. For a physics experiment you should turn off textures, lower the dpi, etc… then you don’t suffer backlogged event queue for visual aesthetic. You could also advance steps (without a 60fps frame loop) assuming it’s not a game but a physical model.
Necromance Day,
Esk8r mo Kiss
Summary
At risk of spreading opinionated hypothetical contageon, I propose isolating a fingerprint on the normal distribution
of the timeline of device capability stack. From my experience, as I used Physii
bodies would go to sleep in midair… but suddenly Rapier
was an official example and solved everything with the same API!
Concurrently, I followed ongoing battles with: OOM overflows, memory-safe browser upgrades, and degrading performance from prospective memory exploit patches. The design industry dictates a basic proficiency in stack literacy… not to mention bounties. As a generalist I attest to the browser war for whitelisted versioning.
Unsolicited advice: revert to an older stack or slash the bleeding-edge codependencies. ABRISS is a cool game where a slow pace benefits the atmospheric “weight” of blocks.
Could you share your code for Rapier?
I tried it myself, but got 20fps… for 300 cubes, which I got 60fps with cannon.
And also critical issue - some cubes are passing through floor cube…
This is my code
import * as THREE from "three";
import Stats from "three/examples/jsm/libs/stats.module.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
import { GUI } from "lil-gui";
import RAPIER from "@dimforge/rapier3d-compat";
/**
******************************
****** Three.js Initial ******
******************************
*/
/**
* Init
*/
// Canvas
const canvas = document.querySelector("canvas.webgl");
// Scene
const scene = new THREE.Scene();
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// camera
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(5, 5, -5);
scene.add(camera);
/**
* Loaders
*/
// Draco Loader
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("/draco/");
// GLTF Loader
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
/**
* Lights
*/
// Ambient Light
// const ambientLight = new THREE.AmbientLight(0x161e33, 0.8);
// scene.add(ambientLight);
// MODELVIEWER
let pmremGenerator = new THREE.PMREMGenerator(renderer);
scene.environment = pmremGenerator.fromScene(
new RoomEnvironment(),
0.04
).texture;
/**
* Controls
*/
// Controls
const orbitControls = new OrbitControls(camera, canvas);
orbitControls.enableDamping = true;
/**
* Additions
*/
// Axes
const axes = new THREE.AxesHelper(10);
scene.add(axes);
// Stats
const stats = new Stats();
document.body.appendChild(stats.dom);
// GUI
const gui = new GUI();
// Clock
const clock = new THREE.Clock();
/**
****************************
****** Rapier Initial ******
****************************
*/
// Initial
await RAPIER.init();
const gravity = new RAPIER.Vector3(0.0, -9.81, 0.0);
const world = new RAPIER.World(gravity);
const dynamicBodies = [];
/**
******************************
************ Main ************
******************************
*/
/**
* Definitions
*/
let cubeBodies = [];
let count = 300;
let isLoaded = false;
/**
* Models
*/
// Plane Mesh
const planeG = new THREE.PlaneGeometry(1000, 1000);
const planeM = new THREE.MeshStandardMaterial({ color: 0xaaaaaa });
const plane = new THREE.Mesh(planeG, planeM);
plane.rotation.x = -Math.PI / 2;
scene.add(plane);
// Plane Physics
const floorBody = world.createRigidBody(
RAPIER.RigidBodyDesc.fixed().setTranslation(0, 0, 0)
);
const floorShape = RAPIER.ColliderDesc.cuboid(50, 0.5, 50);
world.createCollider(floorShape, floorBody);
// Cube Meshes
const cubeG = new THREE.BoxGeometry(1.86, 0.86, 0.54);
const cubeM = new THREE.MeshStandardMaterial({ color: 0xaaffff });
let cubeMeshes = [];
for (let i = 0; i <= count; i++) {
cubeMeshes[i] = new THREE.Mesh(cubeG, cubeM);
scene.add(cubeMeshes[i]);
}
isLoaded = true;
// Cube Physics
const cubeShape = RAPIER.ColliderDesc.cuboid(0.93, 0.43, 0.27)
.setMass(1)
.setRestitution(0)
.setFriction(0.8);
for (let i = 0; i <= count; i++) {
cubeBodies[i] = world.createRigidBody(
RAPIER.RigidBodyDesc.dynamic()
.setTranslation(5 * Math.random(), 20 + i, 5 * Math.random())
.setCanSleep(false)
);
world.createCollider(cubeShape, cubeBodies[i]);
dynamicBodies.push([cubeMeshes[i], cubeBodies[i]]);
}
/**
* Functions
*/
const updateCubes = () => {
if (!isLoaded) return;
for (let i = 0; i < dynamicBodies.length; i++) {
console.log(dynamicBodies[i]);
dynamicBodies[i][0].position.copy(dynamicBodies[i][1].translation());
dynamicBodies[i][0].quaternion.copy(dynamicBodies[i][1].rotation());
}
};
/**
* Action Listeners
*/
// Auto Resize
window.addEventListener("resize", () => {
// Update camera
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
// Update renderer
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
/**
* Animate
*/
const animate = () => {
// Delta Time
let delta = clock.getDelta();
// Update controls
orbitControls.update();
// Update Rapier World
world.timestep = Math.min(delta, 0.1);
world.step();
updateCubes();
// Stats Update
stats.update();
// Render Scene
renderer.render(scene, camera);
// Call animate again on the next frame
window.requestAnimationFrame(animate);
};
animate();
Super!
I don’t understand why my code performance is so terrible, but this code is super!
But in this example, how can I set restitution and friction?
I dont know what is changed in browser or in my device, but i remember that few months ago ammo.js example shows about 20-30 fps instead 5fps. And code of ammo not changed, and i try it in three.js 140 version, again 5 fps.
hm, im alwys using cannon on my xr n vr, maybe i ll try this one. thanks dude
Oh, hmm…
That’s so strange…
As you can see in my code, I just followed guide of rapier for cubes and floor…
But getting worse result than three.js example.