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)
Related
I am working on an aframe project that involves loading 3D objects of unknown sizes into my scene. Naturally I would want to resize the object to a certain size (like fixed height) before I put it in the scene. But how do I extract information like width, height and depth from the object's bounding box?
You'll need to use A-Frame's underlying three.js APIs here. That answer has been posted for three.js before, but here's an A-Frame version:
// get three.js object from aframe entity
var el = document.querySelector('#my-element');
var object = el.getObject3D('mesh');
// compute bounding box
var bbox = new THREE.Box3().setFromObject(obj);
console.log(bbox.min, bbox.max)
I have a 3D model that was loaded as an obj file into Three.js. The model itself is a furniture.
The problem is, that furniture material is dynamic and is different in size (thickness). I need to have to able to made thickness of material bigger, but the total size of the model can't be changed. So scaling isn't an option.
Is there a way I can resize parts of the model (few specific meshes) and doesn't compromise the structure of mesh itself ? I need to change thickness of the structure, but internal parts of the model shouldn't change.
The only solution I can think of is to change scale of some of the meshes and then to change global position of the other meshes based on that. Is this the right way ?
object.traverse(function(child) {
if (child instanceof THREE.Mesh) {
// resize and reposition some of the meshes
}
});
Possible ways to solve it:
Bones
Deformation
Well, if all of the meshes are separate primitives, then you can just change the scale of each part you want to change along one axis, and just set up anchor points to constrain to the outside. So for pieces on the border, you scale the empty object that they're attached to so that they maintain the outer shell.
EG:
OOOOOO
OMMMMMMO
OMmmmmMO
OMmmmmMO
OMMMMMMO
OOOOOO
where O is an Object3D carrying the adjacent Mesh-M, and the m's represent meshes that are scaled themselves. This way if you adjust the scale of all 'm's and 'O's, the outer shell stays in place,
But you're on the right track with the traversal. You'll just have to do this.
For an easy way to traverse, I would give everything you want to change some attribute in their .userData object. Because in some cases you'll want to scale empty objects (O) (so that you can effectively move the anchor point) whereas at others you'll want to scale the meshes in place (m). So it's not purely a mesh based operation (since meshes want to scale from their center). Doing some tagging makes the traversal simpler:
object.traverse(function(child){
if(child instanceof THREE.Mesh){
if(child.userData.isScalable){
//do the scaling.
}
}
});
and if you set up the heirarchy and .userData tagging correctly, then you just scale things and you keep the outer shell.
Is this what you're asking? because the question is unclear.
You could use Clara.io, it is built on top of ThreeJS and allows for you to run operators on geometry that you setup in Clara.io scenes. There is a thickness operator in Clara.io that you can use.
Documentation here: http://clara.io/learn/sdk/interactive-experiences
Anything you can do in the Clara.io editor you can do in an interactive-embed.
You can use your method of changing different meshes sizes and other positions, but when you use object.scale.set( x, y, z ); the browser has to change the scale of the model for every frame rendered. So if you use this for lots of meshes, it can decrease your game's performance. The best way to go would be to use a 3d editor like Blender. It is easier and more efficient.
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 );
I'm trying to make cross-sections of an OBJ loaded with the three.js OBJ loader using the threeCSG wrapper for the JavaScript constructive solid geometry library.
When I use a regular mesh (like a sphere/cube), the intersection csg operation works beautifully. I can also make great-looking cross-sections with an obj in its initial position (white object, cross-section displayed in red below):
However, when I rotate the object, the cross-section is the same no matter how I change its rotation:
How can I get the csg intersection operation to take into account the rotation of the object? It works as expected with a normal three.js mesh (cube).
This may have something to do with the way three.js loads OBJ files--it appears to store a bunch of meshes in a parent object that can then be added/manipulated within a scene. This is how I do the csg operations:
threeOBJ.traverse( function ( child ) {
if (child instanceof THREE.Mesh) {
cc = crossSection( child );
scene.add( cc );
}
} );
The crossSection() function performs a csg intersection operation with the blue transparent plane seen in the images and each child mesh. It returns a THREE.Mesh, which I then add to the scene.
I feel like I must be referring to something incorrectly since it's not taking the rotation into account but I have no idea what. Is there a better way to use csg with three.js-loaded OBJs; would it be better/possible to merge all of the child meshes into one parent mesh and then perform boolean operations?
To solve this problem, I rotated the plane instead of the OBJ and it worked perfectly. To see all sides of the object you can simply also rotate the camera, alternating trackball controls and controlling the movement of the plane to get the desired view.
Hi I want to render an interactive 3D sphere in browser. The texture on it will be of a world map, so basically I am trying to create a globe which is rotatable in any direction using map. I am comfortable in rendering 2D images using SVG but not sure how to render 3D shapes in SVG.
Is it possible to render a 3D shape in SVG, if yes, how? If not, is WebGl a better option?
Have a look at three.js which abstracts the implementation a bit (comes with WebGL/SVG/Canvas backends).
SVG is a 2d vector graphics format, but you can project 3d shapes onto 2d, so it's possible to render 3d objects with SVG, it's just a bit of work (best left to javascript libraries).
WebGL is your best bet because of performance. You might be able to leverage (or at least learn from) demos like http://www.chromeexperiments.com/globe (see http://data-arts.appspot.com/globe-search). There are also other globe demos at http://www.chromeexperiments.com.
If you use SVG then shading is going to be a problem. Proper shading is not really possible in SVG, though you might be able to fake it a few select circumstances. For 3D definitely use WebGL if you have more than a dozen or so polygons in the model.
You must transform all point with a projection
USe this to change point2D(x,y) in point3D(x,y,z):
// Language Javascript
// object Point
function Point(x,y,z){
this.x = x;
this.y = y;
this.z = z;
}
// Projection convert point 2D in 3D
function ProjectionPoint(point){
if ( !(point instanceof Point) )
throw new TypeError("ProjectionPoint: incorrect type parameter");
return { x: (point.x<<8)/(point.z+Zorig)+Xorig,
y: (point.y<<8)/(point.z+Zorig)+Yorig,
z:point.z }
}
Make sure, you have defined your origine point under the variable Xorig, Yorig, Zorig