mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.72k stars 35.3k forks source link

My simple cloth simulation using THREE.js #1160

Closed mmmovania closed 12 years ago

mmmovania commented 12 years ago

Hi all, I have done a basic cloth simulation using THREE.js.

This is using simple explicit Euler integration and basic collision with floor. Rendering using the CanvasRenderer so should be even faster with the WebGLRenderer which I am working on. Controls: Left click and drag to rotate. Middle click to zoom. Use GOOGLE chrome for best performance Embedded version here: http://mmmovania.blogspot.com/2012/01/simple-cloth-in-html5-canvas-using.html Direct link: http://www3.ntu.edu.sg/home2007/mova0002/test/CanvasCloth/SimpleCloth.html

C&C Welcomed.

mrdoob commented 12 years ago

Nice! Will be be able to pick any point in the cloth and drag it? ;)

mmmovania commented 12 years ago

sure should not be a problem since I have already implementing this stuff in OpenGL/C++ in my open source project (OpenCloth:http://code.google.com/p/opencloth) so it's just a matter of translation of code from C++ to javascript ;)

rudiedirkx commented 12 years ago

Awesome =) I remember special programs doing this 10 years ago. Now it's in a browser with a few lines of code (and a few thousand more obviously).

I'm getting only 27-39 FPS though... Is that my crappy laptop or the cloth?

mrdoob commented 12 years ago

I bet it's probably CanvasRenderer.

mmmovania commented 12 years ago

Thanks. Well certainly CanvasRenderer is one candidate. The other is obviously my code since it is not optimized. I was just trying to see how well the naive implementation performs and to my surprise it is much better than what I expected.

I will be extending this code further into using WebGL and then we will see how to optimize the code further. I would like to ask mr doob if there are any obvious optimizations that I could do in this code.to make it perform better.

mrdoob commented 12 years ago

Yep. You should use Face4 instead of Face3.

mmmovania commented 12 years ago

Thanks I just did that change and it improves the performance. Could u tell me why its better to use Face4 instead of Face3. Is it due to less number of primitives required for Quads or does it have anything to do with the internals of THREE.js? The reason I used Face3 was because OpenGL3.3 and above only support Triangles in the core profile so I thought I would use triangles.

mrdoob commented 12 years ago

Because CanvasRenderer draws one path per face. By using Face4 instead of Face3 in this case you're reducing the paths by half.

mmmovania commented 12 years ago

Hmm ok that makes sense. Thansk for that information. I just updated the code. Infact it is much simpler now no conditional branch as was required previously to maintain the proper winding.

mmmovania commented 12 years ago

I have just updated the demo to use WebGL renderer instead of CanvasRenderer so it should perform better now. I now get around 51-60 fps during simulation.

rudiedirkx commented 12 years ago

50+ fps for me too.

I thought trangles were the standard... You should use Face4 when applicable and only Face3 if you really need triangles?

chandlerprall commented 12 years ago

I couldn't resist adding UV values and a texture :)

Very nice @mmmovania !!

rudiedirkx commented 12 years ago

Very gangsta hip texture!

How about two cloths interacting? Is that a challenge? Or dropping a ball onto a cloth?

mmmovania commented 12 years ago

Great addition chandlerprall. @rudiedirkx Hmm Dropping a ball should be a piece of cake. Interaction between clothes is a bit more involved thing.

mmmovania commented 12 years ago

@mrdoob Will be be able to pick any point in the cloth and drag it? Now I am on this. For this I need to cast a ray from the cam to the geometry. Since currently, I am rotating the meshes and keeping the camera still, I want to rotate the scene by rotating the camera instead. So far I came up with this but it does not give me the correct output. Any ideas what may be causing this?

function render() {
/*
   //we were rotating the meshes previously
   mesh.position.z = dist;
   mesh.rotation.x = rX*D2R;
   mesh.rotation.z = rY*D2R;

   plane.position.z = dist;
   plane.rotation.x = rX*D2R;
   plane.rotation.z = rY*D2R;
*/
  //we now rotate the camera instead
   var theta = rX*D2R;
   var phi   = rY*D2R;
   var radius = Math.abs(dist);
   camera.position.x = radius * Math.cos(phi) * Math.sin(theta);
   camera.position.y = radius * Math.sin(phi) * Math.sin(theta);
   camera.position.z = radius * Math.cos(theta);
   camera.lookAt(new THREE.Vector3(0,0,0));
   renderer.render( scene, camera );
}
rudiedirkx commented 12 years ago

@mmmovania I made something nice for that (the camera rotating around a position). You can see it at work at http://hotblocks.nl/tests/three/object3d.html

I made a small helper file: http://hotblocks.nl/tests/three/Rudie.Three.js

The rotation part in a DOM listener is super simple using those helpers:

var left = e.layerX,
    dx = left - lastLeft;
lastLeft = left;

var rotate = dx * 0.5 * DEG_TO_RAD;
camera.rotateAround(rotate);

The 0.5 is so you need 720 px to rotate 360 deg.

The next step (for me) is to be able to zoom in. With the camera, without moving the object or the camera's rotation.

chandlerprall commented 12 years ago

Camera zooming is easy. The camera's Z axis is always pointing at where it's looking. camera.translateZ( - distance_to_zoom )

rudiedirkx commented 12 years ago

Huh... .translateZ... Good point! I'm still a n00b =)

Zooming is easy anyway, because all yo have to do is multiply the 3 position dimensions with >1 or <1. That's what I do now:

p.x *= factor;
p.y *= factor;
p.z *= factor;

The difference is, your method zooms by distance. My method zooms by factor (without knowing the distance).

mmmovania commented 12 years ago

Hi @rudiedirkx and @chandlerprall, I now find the answer. My code was almost correct apart from the sin cos mixed up. This gives me the correct output.

camera.position.x = radius * Math.sin(phi) * Math.cos(theta);
camera.position.y = radius * Math.cos(phi);
camera.position.z = radius * Math.sin(phi) * Math.sin(theta);
camera.lookAt(new THREE.Vector3(0, 0, 0));

So now I can move and rotate the camera about the origin. Previously though I was rotating the objects so now this part is done. Now I need to cast a ray from the camera to the object.

One thing I need to ask. I tried to render points but they only show up using the CanvasRenderer, Another thing is does Three.js provide functions to find the nearest intersecting vertex of the given mesh? I am looking through some examples in the package but most of the time the intersection point is returned so I think I would have to manually identify the vertex myself or is there a better way. Is there a standalone (chm style) API documentation of three.js?

rudiedirkx commented 12 years ago

(You can format code by indenting with 4 spaces or 1 tab.)

What's a vertex?

All the intersection info is divided in three objects: object <THREE.Mesh>, face <THREE.Face4> and point <THREE.Vector3>. I get those like this:

mouse2D.x = e.clientX / WIDTH * 2 - 1;
mouse2D.y = e.clientY / HEIGHT * -2 + 1;

var ray = projector.pickingRay(mouse2D.clone(), camera), // THREE.Ray
intersects = ray.intersectScene(scene); // Array of Objects

Is that useful?

mmmovania commented 12 years ago

@rudiedirkx By vertex I mean point. so what would the variable 'intersects' contain? Is it a collection of all intersected faces? or does it also include the points or do i need to index the points myself? Where can I get a list of all these functions like ray.intersectScene?

rudiedirkx commented 12 years ago

ray.intersectScene( <THREE.Scene> ) returns an Array of Objects (simple hashes):

The API specs are very useful: https://github.com/mrdoob/three.js/wiki/API-Reference , but most I get from examples and demo's. And debugging every single variable helps ofcourse. console.log is your very good friend =)

http://hotblocks.nl/tests/three/object3d2.html might be useful. If you click a block, it logs the first intersect to the console:

(in this case (and yours too) only the first intersect is relevant)

mmmovania commented 12 years ago

@rudiedirkx Thanks for the clarifications. I will see if I could finish picking today.

One more thing, what do u use for the cool looking UI? Did you manually create those controls? Are there any free UI libraries (for building sliders/radiobuttons/panels etc.) that go well with THREE.js and WebGL?

rudiedirkx commented 12 years ago

The controls are DAT.GUI (although I'm not sure about the case: the constructor is dat.GUI and the file is dat.gui.js): http://workshop.chromeexperiments.com/examples/gui/

The stats are with Stats.js. Also @mrdoob's: https://github.com/mrdoob/stats.js

Just grab them from the source or search for them on you prefered search engine. Both aren't specifically for THREE.js or WebGL, but both are very useful.