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
Related
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.
I would like to render two canvases as textures on a plane in three.js. I created an array with two MeshBasicMaterial and did the following
texture2 = new THREE.Texture(c1);
texture3 = new THREE.Texture(c3);
var mat1 = new THREE.MeshBasicMaterial({ map: texture2 });
var mat2 = new THREE.MeshBasicMaterial({ map: texture3 });
materials.push(mat1);
materials.push(mat2);
mesh2 = new THREE.Mesh(geometry2, new THREE.MeshFaceMaterial( materials ));
scene2.add(mesh2);
renderer2 = new THREE.WebGLRenderer({canvas:c2});
renderer2.setSize(c2.width, c2.height);
document.body.appendChild(renderer2.domElement);
I created this jsfiddle example to show my actual problem. The second texture isn't rendered on canvas2, but I want to show both textures on it.
Reason
The reason why the second texture is not rendered is because it doesn't know which faces to assign the first or second material to, so by default it gives the first material to all of them.
Solution
Update Three.js to latest build (r76). You're are now running r54
Loop through all faces and assign them a materialIndex(Face3)
Use THREE.MultiMaterial instead of THREE.MeshFaceMaterial:
mesh2 = new THREE.Mesh(geometry2, new THREE.MultiMaterial( materials ));
I'm using a web-worker to load a .json file of an animated 3D model. For each of the big arrays (vertices, normals, etc.), I'm transferring an Float32Array buffer back to the UI thread. Since such buffers are transferable objects, this will take (almost) zero time.
Now, it turns out that WebGL (and therefore, Three.js) use Float32Array buffers internally, too. This means I could probably load this 3D animation without copying anything, spending almost zero time in the main thread. Isn't that nice?
But it's not clear how to do that part: In the main thread, we have array buffers available for the vertices, normals (the main ones, and the 'morph' ones) and faces. How do I create a working Geometry (or BufferGeometry) from these, without translating or copying the data?
var scene,
vertices, normals, faces,
morphVertices, morphNormals; // <-- we have all these as typed arrays
var geometry = ...; // <-- insert code here
var material = new THREE.MeshLambertMaterial({ morphTargets: true });
var object3D = new THREE.MorphAnimMesh(geometry, material);
scene.add(object3D);
This answer gives a hint, but only point 7 seems relevant, it assumes there is already some Geometry instance, and it doesn't handle morph-targets.
Here's an example based on the mesh loading portion of THREE.GLTF2Loader.
// Create BufferGeometry and assign vertices and normals.
var geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
geometry.setIndex( new THREE.BufferAttribute( faces, 3 ) );
// Create material.
var material = new THREE.MeshStandardMaterial({
morphTargets: true,
morphNormals: true
});
// Set up morph target attributes.
var posAttr = new THREE.BufferAttribute( morphVertices, 3 );
var normAttr = new THREE.BufferAttribute( morphNormals, 3 );
for (var i = 0; i < posAttr.array.length; i++) {
posAttr.array[i] += geometry.attributes.position.array[i];
}
for (var j = 0; j < normAttr.array.length; j++) {
normAttr.array[j] += geometry.attributes.normal.array[j];
}
// Assign morph target attributes.
geometry.morphAttributes.position = [ posAttr ];
geometry.morphAttributes.normal = [ normAttr ];
// Create Mesh.
var mesh = new THREE.Mesh(geometry, material);
mesh.updateMorphTargets();
// Apply 50/50 blend of morph targets and default position/normals.
mesh.morphTargetInfluences[0] = 0.5;
three.js r86-dev.
In html, I use JSONLoader to load my obj(.js file exporting from Blender 2.66). After loading my obj, I use ThreeCSG to subtract a cube. The effect I want to achieve is like cross-section. Now csg operations work fine. The problem is that I can't remain the original color after csg operations.
For example, after A subtract B, I hope that the mesh remain the materials of A, somewhat similar to the image(a.subtract(b)) csg.js website shows. The difference is I hope it all red (A's materials). However, it may be more complicated because my obj has several colors and more complex geometry.
Here is a part of my code.
loader.load( "obj/blenderscene/FinFET2.4.js", createScene1 );
function createScene1( geometry, materials ) {
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
var mesh_bsp = new ThreeBSP(mesh);
var cube_geometry = new THREE.CubeGeometry( 2.5,7 , 7 );
cube_geometry = new THREE.Mesh( cube_geometry ,new THREE.MeshLambertMaterial( { color: 0xff11ff, opacity: 0.9, shading: THREE.FlatShading, wireframe: true, wireframeLinewidth: 2, transparent: true } ) );
var cube_bsp = new ThreeBSP( cube_geometry );
var subtract_bsp = mesh_bsp.subtract( cube_bsp );
var result = subtract_bsp.toMesh( new THREE.MeshFaceMaterial(materials) );
result.geometry.computeVertexNormals();
scene.add( result );
}
The version of three.js is R55.
Sorry for my poor English.I really need some help.Hope you can understand what I mean.
Thank you all.
set the material indexes correctly.
How to:
Add the cube material to the materials
loop over result.geometry.faces as searchFace
search for a face with same vertices as searchFace in geometry.faces
if found then add the materialindex of the face to searchFace
if not found, search for a face with 2 of the same vertices as searchFace in geometry.faces
if found then add the materialindex of the face to searchFace
if not found, search for a face with 1 of the same vertices as searchFace in geometry.faces
if found then add the materialindex of the face to searchFace
if not found add the material index of the cube material
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