Three.js - Wrong Bounding Box importing Blender JSON model - javascript

I am having some problems manipulating the objects I load from Blender. I think the pivot point is always set to 0,0,0 instead of the current object's position. I correctly position and import the objects in the Blender scene, but then I have problems rotating them.
I have used BoundingBoxHelper to see what is happening, but the bounding box is not appearing surrounding the object but centered in the world and with a 1-unit size (I guess that is the default)
This is the code I use to load the alien:
texture6 = THREE.ImageUtils.loadTexture('images/alien1.png', {}, function() {
renderer.render(scene, camera);
});
loader = new THREE.JSONLoader();
loader.load( "models/alien1.js", function( geometry ) {
geometry.computeFaceNormals();
geometry.computeCentroids();
geometry.computeBoundingBox();
var mat = new THREE.MeshBasicMaterial({map: texture6,transparent: true, color:0x00FF00} );
var mesh = new THREE.Mesh( geometry, mat );
scene.add(mesh);
bbHelper = new THREE.BoundingBoxHelper( mesh, 0xff0000 );
scene.add( bbHelper );
});
And this is the result:
(The red bounding box should be surrounding the green alien but is in the center of the scene)
Any suggestions?

You need to call bbHelper.update().
Make the call in the render loop if the object is moving.
three.js r.59

Related

Get geometry and material of 3D Model - Three.js

I am attempting to make one 3D model orbit another, but as soon as I change my mesh from a wireframe box to a 3D Model's geometry it disappears.
//this is inside a GLTFLoader.load (glftLoader.load('<model path>', (gltfScene) => {)
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial( {
color: 0xffffff,
wireframe: true
});
let pivot = new THREE.Object3D()
pivot.rotation.z = 0;
gltfScene.scene.add(pivot);
//let mesh = new THREE.Mesh(geometry, material); WORKING LINE
let mesh = new THREE.Mesh(gltfScene.scene.geometry, gltfScene.scene.material);
mesh.position.y = 2;
pivot.add(mesh);
What am I doing wrong? I get no errors, I have a feeling it may be to do with the scale of the 3D model but I'm unsure. Am I getting the geometry and material properties correctly?
let mesh = new THREE.Mesh(gltfScene.scene.geometry, gltfScene.scene.material);
I suppose this line breaks your code since gltfScene.scene (the result of GLTFLoader's onLoad() callback) is an instance of THREE.Group which has no material or geometry property.
A glTF asset can hold more than one mesh so if you really want to extract the geometries and materials from it, you have to traverse through gltfScene.scene and process all meshes.

Creating BoxBufferGeometry from Box3

I want to create a box mesh on the three.js scene, where points of the box mesh will be the same as bounding box of some existing object on the scene.
I have tried to create box mesh from box3 in the way displayed bellow, but i dont get the right result:
var threeObject = existing object on the scene;
var boundingBox = new THREE.Box3();
boundingBox.setFromObject(threeObject);
var geometry = new THREE.BufferGeometry();
var vertices = new Float32Array( [
boundingBox.min.x, boundingBox.min.y, boundingBox.min.z,
boundingBox.min.x, boundingBox.max.y, boundingBox.min.z,
boundingBox.min.x, boundingBox.min.y, boundingBox.max.z,
boundingBox.min.x, boundingBox.max.y, boundingBox.max.z,
boundingBox.max.x, boundingBox.min.y, boundingBox.min.z,
boundingBox.max.x, boundingBox.max.y, boundingBox.min.z,
boundingBox.max.x, boundingBox.min.y, boundingBox.max.z,
boundingBox.max.x, boundingBox.max.y, boundingBox.max.z,
] );
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var mesh = new THREE.Mesh( geometry, material );
viewer.scene.add(mesh);
How can I create mesh box from box3? Thank you very much for your help!
In Three.js there's no automatic way to turn Box3 into a regular BoxBufferGeometry but here's how it worked for me
const threeObject = existing object on the scene;
const box3 = new THREE.Box3();
// conform to the object size like it's a boundingBox
box3.setFromObject(threeObject);
// make a BoxBufferGeometry of the same size as Box3
const dimensions = new THREE.Vector3().subVectors( box3.max, box3.min );
const boxGeo = new THREE.BoxBufferGeometry(dimensions.x, dimensions.y, dimensions.z);
// move new mesh center so it's aligned with the original object
const matrix = new THREE.Matrix4().setPosition(dimensions.addVectors(box3.min, box3.max).multiplyScalar( 0.5 ));
boxGeo.applyMatrix(matrix);
// make a mesh
const mesh = new THREE.Mesh(boxGeo, new THREE.MeshBasicMaterial( { color: 0xffcc55 } ));
The vertices array in your code holds vertex data but they actually represent face/triangle definitions. Hence, rendering just this geometry data results in a few random triangles (not visualizing a box).
You can solve this problem by adding an index to your geometry which will represent the face definitions based on your vertices. To understand this topic, you have to know the difference between indexed and non-indexed geometries. I suggest you study the official documentation page of THREE.BufferGeometry. There are for each type of geometry official code examples.
three.js R107

Three.js with instancing - can't get it to work without FrustumCulling = false

I'm using three.js and instancing (as in this example), but I'm having the same problem others have reported: the objects are randomly clipped and keep disappearing from the camera
Mesh suddenly disappears in three.js. Clipping?
Three.js buffergeometry disappears after moving camera to close
The proposed workarounds are to set
my_instanced_object.frustumCulled = false;
but this means rendering every single object per each frame, and with a lot of objects this is killing my framerate.
What are my alternatives to this? How can I have proper frustum culling if I'm using instancing?
I'm adding the code I'm using in case someone wanted to take a look
var geometry = new THREE.InstancedBufferGeometry();
geometry.maxInstancedCount = all_meshes_data.length;
geometry.addAttribute( 'position', mesh.geometry.attributes.position );
geometry.addAttribute( 'normal', mesh.geometry.attributes.normal );
geometry.addAttribute( 'uv', mesh.geometry.attributes.uv );
var offsets = new THREE.InstancedBufferAttribute( new Float32Array( all_meshes_data.length * 3 ), 3, 1 );
for ( var i = 0, ul = all_meshes_data.length; i < ul; i++ ) { // Populate all instancing positions (where to spawn instances)
offsets.setXYZ( i, all_meshes_data[i].x, all_meshes_data[i].y, all_meshes_data[i].z );
}
geometry.addAttribute( 'offset', offsets );
var instanceMaterial = new THREE.RawShaderMaterial( {
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
transparent: true
} );
geometry.computeVertexNormals();
geometry.boundingSphere = new THREE.Sphere( new THREE.Vector3(), 50 ); // Not working, it works just for a 0;0;0 world positioned mesh that is the 'base' of all of the instanced ones
var instanced_mesh = new THREE.Mesh( geometry, instanceMaterial );
//instanced_mesh.frustumCulled = false; // Works, but the scene becomes very slow (rendering everything even if not in sight)
scene.add( instanced_mesh );
If you are using instancing, there are two ways to handle frustum culling.
One is to turn frustum culling off for the object:
object.frustumCulled = false;
The other option is to set the bounding sphere of the geometry manually -- if you know it, or can estimate it:
geometry.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
three.js r.86

Three.js: How to match EdgesHelper to Mesh

In a scene I have added several mesh objects (cubes). An EdgeHelper has been made for each cube. The cubes move and rotate and the Edgehelpers move and rotate with them.
I would like to change the color of an EdgeHelper when it's associated cube mesh is selected. (The selection method is not important).
So, given a particular cube mesh, how do I find the associated EdgeHelper object?
When you create an edgesHelper for a given mesh, all you have to do is add a new property to the mesh:
var mesh = new THREE.Mesh( ... );
var edgesHelper = new THREE.EdgesHelper( mesh );
mesh.edgesHelper = edgesHelper;
Now you can change the helper color like so:
mesh.edgesHelper.material.color.set( 0xff0000 );
three.js r.76
When you create meshes and EdgeHelpers you can assign them the same .name attribute:
mesh0.name = 0;
edgeHelper0.name = 0;
mesh1.name = 1;
edgeHelper1.name = 1;
...and so on
**if you wrap this in a loop even better
so when a mesh is selected you can read its .nameattribute and pick the corresponding edgeHelper.

Model illumination

After loading a model with OBJMTLLoader it is automatically set as a MeshLambertMaterial and unfortunatelly i can't get it to be in full color and textures look much darker. I have some problems with setting the correct light in the scene.
I have added an ambient light but its not enough:
scene.add(new THREE.AmbientLight( 0xffffff ));
Is it possible to turn off the 'luminance' and make the mesh lambert material visible without any light in the scene?
Two ways to recreate material, one is open your model file and change material here in source file manually. Or when usilg object loader or json loader, use "for" syntax to go trough each material and set another values
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load(model, addthree1ToScene);
function addthree1ToScene( geometry, materials )
{
var materiall = new THREE.MeshFaceMaterial( materials );
for ( var i = 0; i < materials.length; i ++ )
{
var material = materials[i];
material.side = THREE.DoubleSide; /// there you can set attributes
}
three1 = new THREE.Mesh( geometry, materiall );
three1.position.set(x,y,z);
scene.add( three1 );
console.log(three1);
}

Categories

Resources