Collision detection with boundingSphere - javascript

For each mesh (THREE.Object3D) Three.js provide a very handy properties - boundingSphere and boundingSphere that have intersectsSphere and isIntersectionBox methods.
With all this I thought I can use it for simple collision detection but when I try it appears that collision happens all the time because (I tried boundingSphere) boundingSphere.center is always in (0, 0, 0); So If I want to check collisions between 2 meshes I should for each object - clone boundingSphere object and then get it world coordinates and only then to use intersectsSphere.
something like this:
var bs = component.object.geometry.boundingSphere.clone();
bs.center.setFromMatrixPosition(component.object.matrixWorld);
...
if (_bs.intersectsSphere(bs)){
is this how it suppose to be used or am I missing something and there are more convenient way of doing collisions detection based on boundingBox/boundingSphere?

If you want to do collision detection with bounding boxes you need the boxes in the world coordinate system. The bounding volumes in the intersectsSphere and isIntersectionBox properties of the mesh are in the local coordinate system of the object.
You can do like you did: clone the volumes and move them to the correct position in the world coordinate system, that is a good solution.
Otherwise you can also set a new box from your meshes and do collision using those boxes. Let's say you have a THREE.Mesh called mesh then you can do:
sphere = new THREE.Sphere.setFromPoints( mesh.vertices );
box = new THREE.Box3.setFromObject( mesh );
A little tip. During development it can be nice to see the bounding boxes in your scene, for this you can use the THREE.BoundingBoxHelper:
var helper = new THREE.BoundingBoxHelper( mesh );
scene.add( helper );

Related

Three.js: how to use a plane to cut objects in 2 parts?

I have a complex object, i.e. a box, and I would like to cut it dynamically. This jsFiddle is a very simple example:jsFiddle
Very simple plane
var plane = new THREE.Mesh( geometry, material3 );
plane.rotation.x =1.3; // -Math.PI / 2;
gui.add(plane.rotation, "x", 0.1, Math.PI / 2).name("angle");
gui.add(plane.position, "y", -1, 1).name("h");
scene.add( plane );
I would like to remove from my object the upper part. Just like to cut off a piece from an apple using a knife.
The plane is the knife: In my example, you can play with 2 controls to move the plane up and down or change the angle.
Can you help me to hide the removed part from the object?
You've got two options:
You could use clipping as WestLangley mentioned above.
Clipping does not modify the vertex geometry, it's only visual.
Is non-destructive, so it's good for animating or making constant updates.
Clipping is mostly done with a few planes instead of complex geometry.
You could use a boolean operation with Constructive Solid Geometry.
Boolean does affect the vertex geometry, which can be exported.
Operation is "destructive", so you can't make updates once it's done.
Boolean can be performed with complex geometries, as long as they're "manifold".
Boolean operations require both geometries to be manifold geometries in order to work. This means both meshes have to be closed, without open faces. You cannot use infinitely thin planes, so the example in your JSFiddle wouldn't work. You would need to give each side a little bit of thickness, like using a box with a width of 0.0001 instead of a plane.

three.js box3 of a imported sphere

i have a short question:
I know how to calculate the boxes of my (imported) 3dobjects f.e.
var box = new THREE.Box3().setFromObject(obj);
With this i can compute boxes for my objects and i can merge them together if i want.
The problem is, now i have these 2 objects https://imgur.com/gallery/NbPwcmB
The solution seems quite simple: i need to compute the left and right spherebox and put them together, but both of these 2 objects are imported with stlloader. I'm not sure how stlloader exactly works, (it seems for me like its all 1 huge mesh) so i'm not even sure if this is possible.
so my questions:
1. how can i compute a box with the shape of a sphere of my sphere object.
2. Is this even possible for my stl object? (I will try when i get the answer for question 1)
Edit: Question 1 should somehow be working with .computeBoundingSphere..
is there a way to make this visible?
how can i compute a box with the shape of a sphere of my sphere object.
Well, in three.js you have the choice between two bounding volumes. THREE.Box3 represents an axis-aligned bounding box (AABB) whereas THREE.Sphere represents a bounding sphere. If you need a box with the shape of a sphere, use THREE.Sphere.
Is this even possible for my stl object?
The method setFromObject() does only exist for THREE.Box3. However, you can compute the bounding sphere via THREE.BufferGeometry.computeBoundingSphere(). This sphere is defined in local space, however. You can use THREE.Sphere.applyMatrix4() to transform it into world space by passing in the world matrix of the 3D object.
is there a way to make this visible?
There is no helper class for bounding spheres. But you can easily create a helper mesh based on THREE.SphereBufferGeometry. Something like:
const geometry = new THREE.SphereBufferGeometry( boundingSphere.radius );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
const mesh = new THREE.Mesh( geometry, material );
mesh.position.copy( boundingSphere.center );
scene.add( mesh );
three.js R109

JavaScript - Three.js compute bounding box of Object3D with BufferGeometry

I have an Object3D with many levels of children (more Object3Ds or Meshes/Lines). The Box3 class has a setFromObject() method which will compute a bounding box of an object and all of its descendants. This is the behavior I am looking for.
I can't use the setFromObject() method of Box3, however, because I am not using Geometry objects. Instead, the project I'm working on uses BufferGeometry exclusively. BufferGeometry objects do not have a .vertices property, which is what the setFromObject() function looks for when computing a bounding box.
var bbox = new THREE.Box3().setFromObject(object);
console.log(bbox.min); // x, y, and z are all Infinity.
console.log(bbox.max); // x, y, and z are all -Infinity.
I have also been experimenting with using the computeBoundingBox() method of BufferGeometry, but it does not seem to update the bounding box when the geometry is manipulated. I think it might be related to matrixAutoUpdate being false, but I've also tried explicitly calling updateMatrix() to no avail.
Is there a way to compute a bounding box on an Object3D and all of its descendants if using the BufferGeometry class? I'm new to Three.js, so any help would be appreciated!
I am using Three.js r66.
Box3.setFromObject( object ) now supports BufferGeometry.
three.js r.69dev (dev version)

How do I 'wrap' a plane over a sphere with three.js?

I am relatively new to three.js and am trying to position and manipulate a plane object to have the effect of laying over the surface of a sphere object (or any for that matter), so that the plane takes the form of the object surface. The intention is to be able to move the plane on the surface later on.
I position the plane in front of the sphere and index through the plane's vertices casting a ray towards the sphere to detect the intersection with the sphere. I then try to change the z position of said vertices, but it does not achieve the desired result. Can anyone give me some guidance on how to get this working, or indeed suggest another method?
This is how I attempt to change the vertices (with an offset of 1 to be visible 'on' the sphere surface);
planeMesh.geometry.vertices[vertexIndex].z = collisionResults[0].distance - 1;
Making sure to set the following before rendering;
planeMesh.geometry.verticesNeedUpdate = true;
planeMesh.geometry.normalsNeedUpdate = true;
I have a fiddle that shows where I am, here I cast my rays in z and I do not get intersections (collisions) with the sphere, and cannot change the plane in the manner I wish.
http://jsfiddle.net/stokewoggle/vuezL/
You can rotate the camera around the scene with the left and right arrows (in chrome anyway) to see the shape of the plane. I have made the sphere see through as I find it useful to see the plane better.
EDIT: Updated fiddle and corrected description mistake.
Sorry for the delay, but it took me a couple of days to figure this one out. The reason why the collisions were not working was because (like we had suspected) the planeMesh vertices are in local space, which is essentially the same as starting in the center of the sphere and not what you're expecting. At first, I thought a quick-fix would be to apply the worldMatrix like stemkoski did on his github three.js collision example I linked to, but that didn't end up working either because the plane itself is defined in x and y coordinates, up and down, left and right - but no z information (depth) is made locally when you create a flat 2D planeMesh.
What ended up working is manually setting the z component of each vertex of the plane. You had originaly wanted the plane to be at z = 201, so I just moved that code inside the loop that goes through each vertex and I manually set each vertex to z = 201; Now, all the ray start-positions were correct (globally) and having a ray direction of (0,0,-1) resulted in correct collisions.
var localVertex = planeMesh.geometry.vertices[vertexIndex].clone();
localVertex.z = 201;
One more thing was in order to make the plane-wrap absolutely perfect in shape, instead of using (0,0,-1) as each ray direction, I manually calculated each ray direction by subtracting each vertex from the sphere's center position location and normalizing the resulting vector. Now, the collisionResult intersection point will be even better.
var directionVector = new THREE.Vector3();
directionVector.subVectors(sphereMesh.position, localVertex);
directionVector.normalize();
var ray = new THREE.Raycaster(localVertex, directionVector);
Here is a working example:
http://jsfiddle.net/FLyaY/1/
As you can see, the planeMesh fits snugly on the sphere, kind of like a patch or a band-aid. :)
Hope this helps. Thanks for posting the question on three.js's github page - I wouldn't have seen it here. At first I thought it was a bug in THREE.Raycaster but in the end it was just user (mine) error. I learned a lot about collision code from working on this problem and I will be using it later down the line in my own 3D game projects. You can check out one of my games at: https://github.com/erichlof/SpacePong3D
Best of luck to you!
-Erich
Your ray start position is not good. Probably due to vertex coordinates being local to the plane. You start the raycast from inside the sphere so it never hits anything.
I changed the ray start position like this as a test and get 726 collisions:
var rayStart = new THREE.Vector3(0, 0, 500);
var ray = new THREE.Raycaster(rayStart, new THREE.Vector3(0, 0, -1));
Forked jsfiddle: http://jsfiddle.net/H5YSL/
I think you need to transform the vertex coordinates to world coordinates to get the position correctly. That should be easy to figure out from docs and examples.

Making a rotation around a point

I'm using THREE API in order to realize some animations in my app. Now i have a real problem : i'd like making spherical rotation around a specific point. The "rotate" method included in mesh objects allow me to make them, but the center of the rotation is (by default i guess) the center of the mesh.
Then, i only rotate my objects around themself...
I have already found some examples, but they don't solve my problem. I tried to create objects 3D parents like groups, and tried to make the rotation around this groups after having translated them, but this still does not work...
Can you please give me a hand about that ?
I'm so sorry, i found my problem... Making a jsfiddle made me realize i forgot to instanciate my parent as " a new Object 3D() ", that was why i didn't see any objects in my scene when i used animation on my parent... i give you a short part of my code anyway dedicated to interested people finding any help :
// mesh
mesh = new THREE.Mesh( geometry, material );
parent = new THREE.Object3D();
parent.add(mesh);
// if i want my rotation point situated at (300;0;0)
parent.position.set(300,0,0);
mesh.position.set(-300, 0, 0);
scene.add(parent);
http://jsfiddle.net/KqTg8/6/
Thank you

Categories