I have an large array (50,000 to 100,000 elements) with each element containing another array of 3 points that define the vertices of a polygon. Some vertices have a parameter addition built in to the array, e.g;
var array = [
[[967.6719, 657.401, -1008.1],[967.6719, 657.401, -1001.1],[967.1551, 657.4806, -1008.1]],
[[967.1551, 657.4806, -1008.1 + LENGTH],[967.6719, 657.401, -1001.1],[967.1551, 657.4806, -1001.1]],
...etc
];
The length parameter is controlled by a slider bar. Currently the initial load time is way too long and any changes to the parameter also takes ages to update. Is there a way to optimise this?
I am currently rendering the polygons with this code;
function drawShapes(array) {
scene.remove( all_shapes );
all_shapes = new THREE.Object3D();
var LENGTH = inpLength.valueAsNumber;
var material = new THREE.LineBasicMaterial( { color: 0x02B700, linewidth: 2 } );
var triangleGeometry = new THREE.Geometry();
for (var i=0; i < array.length; i++){
for (var n=0; n<3; n++){
triangleGeometry.vertices.push(new THREE.Vector3( array[i][n][0], array[i][n][1], array[i][n][2]));
}
triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));
triangleMesh = new THREE.Mesh(triangleGeometry, material);
all_shapes.add(triangleMesh)
var triangleGeometry = new THREE.Geometry();
}
scene.add( all_shapes );
}
I'm using the ExplodeModifier to duplicate the vertices so I can have individual control over Face3 objects.
For my specific example, this alone looks visually poor, so I decided to add 3 extra faces (per existing face) so I can have a pyramid shape pointing inwards the geometry.
I managed to modify the ExplodeModifier and create the extra faces, however I get several errors:
THREE.DirectGeometry.fromGeometry(): Undefined vertexUv and THREE.BufferAttribute.copyVector3sArray(): vector is undefined
I understand that now I have 9 extra vertices per face, so I need according uv's, and since I don't need a texture but a solid color I don't mind having the wrong uvs... So, I also duplicated the uvs and avoid the first warning but I can't get rid of the copyVector2sArray...
pseudo code:
var geometry = new THREE.IcosahedronGeometry( 200, 1 );
var material = new THREE.MeshPhongMaterial( { shading: THREE.FlatShading } );
var explodeModifier = new THREE.ExplodeModifier();
explodeModifier.modify( geometry );
var mesh = new THREE.Mesh( geometry, material );
scene.addChild( mesh );
The Explode Modifier has this pseudo code:
var vertices = [];
var faces = [];
for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
(...)
var extraFace1 = new THREE.Face3().copy(face)
extraFace1.c = geometry.vertices[0]
var extraFace2 = new THREE.Face3().copy(face)
extraFace2.b = geometry.vertices[0]
var extraFace3 = new THREE.Face3().copy(face)
extraFace3.a = geometry.vertices[0]
faces.push( extraFace1 );
faces.push( extraFace2 );
faces.push( extraFace3 );
}
geometry.vertices = vertices;
geometry.faces = faces;
```
I added an example HERE. It works, but I want to avoid the console warnings...
As pointed out by #mrdoob I was assigning a THREE.Vector3 and not an index to the added THREE.Face3.
var extraFace1 = new THREE.Face3().copy(face)
extraFace1.a = geometry.faces.length * 3 - 1
var extraFace2 = new THREE.Face3().copy(face)
extraFace2.b = geometry.faces.length * 3 - 1
var extraFace3 = new THREE.Face3().copy(face)
extraFace3.c = geometry.faces.length * 3 - 1
jsfiddle updated
I'm trying to add a line(s) between animated sprites, like in this example. I tryed different solutions. But I couldn't make a dynamic line and not even a static line between sprites that are animated. Is it possible to create a dymanic line between those sprites from that example. If yes, how can I do it?
This is the code I used:
for ( var i = 0; i < objects.length; i ++ ) {
var geometry = new THREE.Geometry();
geometry.vertices.push(objects.position);
var material = new THREE.LineBasicMaterial( {
color: 0x0000FF,
transparent: true,
opacity: 1
} );
var line = new THREE.Line( geometry, material, THREE.LinePieces );
scene.add( line );
}
On ...jsfiddle.net/LxpmN/40/ u can see what I'm try to achieve, but he used two meshes instead of sprites. I understand that I need to put line.geometry.verticesNeedUpdate = true;, but I can't even make a static line from objects, like in that previous example.
If you want to add a collection of line segments to your scene, create one THREE.Line instead of many. Use a pattern like this one:
var geometry = new THREE.Geometry();
for ( var i = 0; i < objects.length - 1; i ++ ) { // stop one short of end
geometry.vertices.push( objects[ i ].position );
geometry.vertices.push( objects[ i + 1 ].position );
}
var material = new THREE.LineBasicMaterial( { color: 0x0000FF } );
var line = new THREE.Line( geometry, material, THREE.LinePieces );
scene.add( line );
If you modify any of the object's positions, you will have to add the following line in the render loop:
line.geometry.verticesNeedUpdate = true;
three.js r.71
Is it possible in Three.js to merge two or more meshes, with different materials?
The solutions I've found, merges geometry only, or just puts the Meshes into one Object3D or Group.
Yes: Kind-of (see the comments attached to the question and this answer post):
var blueMaterial = new THREE.MeshPhongMaterial( {color: 0x0000FF } );
var redMaterial = new THREE.MeshPhongMaterial({ color:0xFF0000 });
var meshFaceMaterial = new THREE.MeshFaceMaterial( [ blueMaterial, redMaterial ] );
var boxGeometry = new THREE.BoxGeometry( 10, 10, 10 );
for ( var face in boxGeometry.faces ) {
boxGeometry.faces[ face ].materialIndex = 0;
}
var sphereGeometry = new THREE.SphereGeometry( 5, 16, 16 );
sphereGeometry.applyMatrix( new THREE.Matrix4().makeTranslation(0, 5, 0) );
var mergeGeometry = new THREE.Geometry();
mergeGeometry.merge( boxGeometry, boxGeometry.matrix );
mergeGeometry.merge( sphereGeometry, sphereGeometry.matrix, 1 );
var mesh = new THREE.Mesh( mergeGeometry, meshFaceMaterial );
scene.add( mesh );
I went with a cube and a sphere because a box for example wants to know a material id for each of its faces.
http://jsfiddle.net/v49ntxfo/
i have an output date like this:
geom[0] = {
texturesindexT: new Int16Array([0,1,2,3]),
texturesindexS: new Int16Array([-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,...]),
materialsindexT: new Int16Array([-1,-1,-1,-1]),
materialsindexS: new Int16Array([-1,0,1,2,3,4,5,0,6,2,7,8,-1,0,...]),
startIndicesT: new Uint32Array([0,288,606,897,1380]),
startIndicesS: new Uint32Array([1380,1431,1479,1485,1497,1515,1659,...]),
m_indices: new Uint16Array([0,1,2,3,0,2,4,2,5,4,6,2,7,3,2,8,9,10,...]),
m_vertices: new Float32Array([-81.93996,25.7185,-85.53822,-81.93996,...]),
m_normals: new Float32Array([-0.004215205,0.9999894,-0.001817489,-0.004215205,...]),
m_texCoords: new Float32Array([0,0.04391319,0,0.2671326,0.009521127,0.03514284,...]),
}
var textures = new Array("-1_-1/t0.jpg","-1_-1/t1.jpg","-1_-1/t2.jpg",...);
The Data is in order for an Index, Vertex and Normal-Buffer but sections have to be rendered with other Textures and Maretials.
I have tried to make a THREE.Geometry out of the indices, vertices and texCoords/UVCoords but that didn't work.
Now i am trying use a THREE.BufferGeometry() and this work BUT i need to render index 0 to 287 with Texture "textures[0]" and index 288 to 605 with "textures[1]" and so on.
My first attempt was to make a BufferGeometry for each part with index 288 to 605 , but since the Indices are in order for the hole model, i have to put the complete vertices, normales and UVCoords in the Buffer for just a couple of faces.
Is there a way to render sections of the BufferGeometry with other Textures or to set the Texture Index for each Face?
Or is it possible to create a Material, that renders the first X faces with Texture A and the next with Texture B???
If you want to use two different textures with a single BufferGeometry, you can use this pattern, which sets drawcalls:
var geometry1 = new THREE.BufferGeometry();
// ...and set the data...
var geometry2 = geometry1.clone();
// set drawcalls
geometry1.offsets = geometry1.drawcalls = []; // currently required
geometry1.addDrawCall( start1, count1, 0 );
geometry2.offsets = geometry2.drawcalls = []; // currently required
geometry2.addDrawCall( start2, count2, 0 );
var material1 = new THREE.MeshPhongMaterial( { map: map1 } );
var material2 = new THREE.MeshPhongMaterial( { map: map2 } );
var mesh1 = new THREE.Mesh( geometry1, material1 );
var mesh2 = new THREE.Mesh( geometry2, material2 );
three.js r.70
You can create two geometries with same vertex buffers and different indexes:
var position = new THREE.BufferAttribute(positionArray, 3);
var normal = new THREE.BufferAttribute(normalArray, 3);
var uv = new THREE.BufferAttribute(uvArray, 2);
var indices1 = new THREE.BufferAttribute(indexArray1, 1);
var geometry1 = new THREE.BufferGeometry();
geometry1.addAttribute('position', position);
geometry1.addAttribute('normal', normal);
geometry1.addAttribute('uv', uv);
geometry1.addAttribute('index', indices1);
var indices2 = new THREE.BufferAttribute(indexArray2, 1);
var geometry2 = new THREE.BufferGeometry();
geometry2.addAttribute('position', position);
geometry2.addAttribute('normal', normal);
geometry2.addAttribute('uv', uv);
geometry2.addAttribute('index', indices2);
and then create 2 meshes with different materials as you normally would. As far as I understand, this will re-use same data in both meshes.