I am currently using a matrix to mirror my Collada models.
I have posted this question before: Flip Normals Three.JS after flipping geometry
and referenced this one: ThreeJS geometry flipping
The problem is that I can't flip the geometry before adding it to a mesh to avoid the inverted material, since it is a Collada model, which already contains the mesh.
What would be the best way to go about mirroring a Collada model while maintaining its material?
I thought I could do the following, but I didn't know how to target the materials properly to change them (my new geometry does not have a new material applied to it). Also my models are fairly complex and contain a lot of hierarchies. The result is the flipped Collada model, with an inside out material.
var mS = (new THREE.Matrix4()).identity();
var newGroup = new THREE.Object3D();
var newMesh;
mS.elements[5] = -1;
mesh.traverse(function(child){
if (child.geometry!==undefined) {
if (child instanceof THREE.Mesh) {
child.geometry.applyMatrix(mS);
child.geometry.verticesNeedUpdate = true;
child.geometry.normalsNeedUpdate = true;
child.geometry.computeVertexNormals();
child.geometry.computeBoundingSphere();
child.geometry.computeFaceNormals();
child.geometry.computeVertexNormals();
if (child.material.materials!=undefined) {
for (var i; i<child.material.materials.length; i++) {
child.material.materials[i]=newMaterial;
child.material.materials[i].wrapAround = true;
child.material.materials[i].side = THREE.DoubleSide;
}
}
var geom = child.geometry.clone();
newMesh = new THREE.Mesh(geom, child.material);
newMaterial.needsUpdate = true;
newGroup.add( newMesh );
};
};
});
return newGroup;
Thanks!
UPDATE
I had a typo in my code. Everything works.
var i;
should be
var i=0;
Related
I am trying to make a series of cubes that can be clicked to highlight them. This will enable me to change their color or add a texture or manipulate them in some way. I have looked through the source code of all the interactive examples at https://threejs.org/examples/ and it appears that each example uses a slightly different way of creating and selecting objects in the scene. I am not used to using javascript though, so maybe I'm missing something simple.
I create an Object3D class named blocks to store all of the cubes
blocks = new THREE.Object3D()
I am using a for loop to create a 9 x 9 array of cubes starting at (0,0,0) coordinates with a slight gap between them, and add() them to blocks and add() blocks to the scene. example: (cube size 2,2,2)
function stack(mx,my,mz){
for (var i = 0; i < 9; i++){
line(mx,my,mz);
mz += 3;
}
}
function line(mx,my,mz){
for (var i = 0;i<9;i++){
var block = new THREE.Mesh( Geometry, Material);
block.position.x = mx;
block.position.y = my;
block.position.z = mz;
blocks.add(block);
mx+=3;
}
}
stack(mx,my,mz)
scene.add(blocks)
When I run this code, I can see them rendered. I use raycaster to .intersectObjects() which requires an array of objects. This is where I run into the problem of selecting just one object.
function onDocumentMouseDown(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
**var intersects = raycaster.intersectObjects(blocks.children, true);**
if (intersects.length > 0) {
intersects[0].object.material.transparent = true;
other code stuff blah blah blah
{
This will make all children clickable but they have the same .id as the first object created. so if I try to .getObjectById() in order to change something, it doesn't work.
I have tried to generate each element and add them to the scene iteratively instead of creating an object array to hold them and it still has a similar effect. I've tried storing them in a regular array and then using true parameter to recursively search the .intersectObject() array but it selects all of the objects when I click on it.
var intersects = raycaster.intersectObjects(blocks, true);
I have considered creating 81 unique variables to hold each element and statically typing an array of 81 variables (desperate option) but I can't find a secure way to dynamically create variable names in the for loop to hold the objects. This way was posted on stackoverflow as a solution to creating different named variables but it doesn't seem to create variables at all.
for (var i=0, i<9, i++){
var window["cube" + i] = new THREE.Mesh( Geometry, Material)
{
Main Question: How can I iteratively create multiple Mesh's (enough that statically typing each variable would be ill-advised) in a controllable way that I can select them and manipulate them individually and not as a group?
I think the reason why you met this problem is you reference same Material to build your Mesh, you did intersect a single object in blocks.children, but when you change some properties of the material others mesh who use the material would change too.
function line(mx,my,mz){
for (var i = 0;i<9;i++){
material = new THREE.MeshLambertMaterial({color: 0xffffff});
var block = new THREE.Mesh( Geometry, material);
block.position.x = mx;
block.position.y = my;
block.position.z = mz;
blocks.add(block);
mx+=3;
}
}
it works for me.
I want to avoid creating new typed arrays and the consequent gc().
I made my geometry using BufferedGeometry. Upon receiving events, my vertex and the faces indices are updated. I can update the coordinates by setting verticesNeedUpdate but it does not update the faces. The update is called ~20-50 times per second, which can be heavy on the browser. How can I do this by avoiding creating heavy garbage for the JavaScript Garbage Collector? (See method update() below).
function WGeometry77(verts, faces) {
THREE.Geometry.call( this );
this.type = 'WGeometry77';
this.parameters = {};
// Initially create the mesh the easy way, by copying from a BufferGeometry
this.fromBufferGeometry( new MyBufferGeometry77( verts, faces ) );
};
WGeometry77.prototype = Object.create( THREE.Geometry.prototype );
WGeometry77.prototype.constructor = WGeometry77;
WGeometry77.prototype.update = function(verts, faces) {
var geom = this;
var nl = Math.min(geom.vertices.length, verts.length/3);
for ( var vi = 0; vi < nl; vi ++ ) {
geom.vertices[ vi ].x = verts[vi*3+0];
geom.vertices[ vi ].y = verts[vi*3+1];
geom.vertices[ vi ].z = verts[vi*3+2];
}
var nf = Math.min(geom.faces.length, faces.length/3);
for ( var fi = 0; fi < nf; fi ++ ) {
geom.faces[ fi ].a = faces[fi*3+0];
geom.faces[ fi ].b = faces[fi*3+1];
geom.faces[ fi ].c = faces[fi*3+2];
}
geom.verticesNeedUpdate = true; // Does not update the geom.faces
}
PS. My code is written in Emscripten, which does something like this:
var verts = Module.HEAPF32.subarray(verts_address/_FLOAT_SIZE, verts_address/_FLOAT_SIZE + 3*nverts);
What I want to do is almost animating, or a dynamic geometry (calculated using Marching Cubes). But my topology (the graph of the mesh) is also updated. Which ThreeJS class I should use? If there exists no such class, should I create we create a new class like UpdatableBufferedGeometry?
To update THREE.BufferGeometry after it has rendered, you can use this pattern:
geometry.attributes.position.setXYZ( index, x, y, z );
geometry.attributes.position.needsUpdate = true;
For indexed BufferGeometry, you can change the index array like so:
geometry.index.array[ index ] = value;
geometry.index.needsUpdate = true;
You cannot resize buffers -- only change their contents. You can pre-allocate larger arrays and use
geometry.setDrawRange( 0, numVertices );
three.js r.78
If you want efficiency, you should create a BufferGeometry instead of a Geometry.
You can use the source code of this example as reference:
http://threejs.org/examples/#webgl_buffergeometry_uint
I have created a plane and when I click on a vertex, the vertex will move and render as expected . My problem is saving the mesh to a text file.The vertices don't seem to update on the file as expected.
If I move a vertex before the second render the vertex position will reflect on the external text file.
My question is once I have moved around a bunch of vertices x,y,z positions how do I save the result that appears on my screen as it seems to only save the original mesh .
var guiControls = new function () {
var t = ['Test Save File'];
this.save_mesh = function () {
for (var i = 0, j = ground.geometry.vertices.length; i < j; i++) {
t.push('['+ ground.geometry.vertices[i].x+','+ ground.geometry.vertices[i].y+ ','+ objects[0].geometry.vertices[i].z+ '#:'+']');
}
function passMesh(){
var data = {
value: t
};
$.post("./php/savefile.php", data);
}
passMesh();
};
I have tried to use the updates available:
geo.dynamic = true;
geo.computeVertexNormals();
geo.computeFaceNormals();
geo.verticesNeedUpdate = true;
geo.normalsNeedUpdate = true;
Any help is appreciated.
In 3D graphics all changes are only matrix transformations of the original mesh, which do not actually change this mesh. So my guess is that you need to apply the transformations to you objects prior to the export. try: .applyMatrix
I made this function that for each vertices of geometry create a sphere and place it in the same position of vertice.For example if I have a cube,the function place a sphere for each cube vertice.
function makeSphereVertices(){
console.log("makesphere");
spheres = [];
for(var j=0 ; j<geometryContainer.length ; j++) {
for (var i=0 ; i<geometryContainer[j].geometry.vertices.length ; i++){
var sphereGeometry = new THREE.SphereGeometry(0.04,10,10);//relative to dimension object : ToDo
var sphereMaterial = new THREE.MeshBasicMaterial({transparent: false,color: 0x000000 /*opacity: 0.01*/});
spheres = new THREE.Mesh(sphereGeometry,sphereMaterial);
spheres.position.set(geometryContainer[j].geometry.vertices[i].x,
geometryContainer[j].geometry.vertices[i].y,
geometryContainer[j].geometry.vertices[i].z);
console.log(geometryContainer[j].id);
spheres.name = "sphere";
scene.add(spheres);
verticesSphere.push(spheres);
}
}
}
After this,I have created function to move my cube like this Draggable shape. Now the problem is: I can't find a way to move together cube and all spheres. For example if I drag cube all the spheres remains in the old position. Is there a way to chain the spheres to my cube?Thank you.
By placing them all in a new object.
group = new THREE.Object3D();//create an empty container
group.add( mesh );//add a mesh with geometry to it
scene.add( group );//when done, add the group to the scene
three.js - mesh group example? (THREE.Object3D() advanced)
So make sure you place the cube and all the spheres in your newly created group object.
I'd like to render a mesh on top of everything else, this solution works fine:
Three.js - Geometry on top of another
I was wondering if the same could be achievable with mesh.renderDepth, but I couldn't make it work so far. Seems like renderDepth only has an effect if material.depthTest or depthWrite is set to false, but then depth ordering is of course wrong within the same object:
http://jsfiddle.net/SF9tX/22/
var cube = new THREE.Mesh(geometry, material);
cube.renderDepth = 1;
scene.add(cube);
var cube2 = new THREE.Mesh(geometry, material);
cube2.position.x = 1;
cube2.renderDepth = 2;
scene.add(cube2);
// with any one of these lines the renderDepth has an effect
// but then of course the depth test/write is wrong within the same object
// material.depthWrite = false;
// material.depthTest = false;
For r70 is renderDept function removed.
https://github.com/mrdoob/three.js/issues/5496