I got a 2D Hexagon in my init()-Code, works well. I push 6 vertices and new faces, but nothing appear. Why?
for-loop:
b.world.grid[x][z].Model.geometry.vertices.push(new THREE.Vector3(b.world.grid[x] [z].Model.geometry.vertices[i].x,b.world.grid[x][z].Model.geometry.vertices[i].y,b.world.grid[x] [z].Model.geometry.vertices[i].z));
b.world.grid[x][z].Model.geometry.faces.push(new THREE.Face3(0, 1, 7));
I already used VerticesNeedUpdate
Have you tried this code:
b.world.grid[x][y].Model.geometry.groupsNeedUpdate = true;
You need to update the group, not the vertices array, because the existing vertices haven't changed — you have just added some more, but you need to update the group of your existing model.
Related
I am working on implementing a custom model importer. The file contains all the necessary info (vertices, vertex normals, vertex uv coordinates, materials, etc.)
It's important to note that the file contains models with multiple materials.
The setup of the vertices is fairly straight forward and is working correctly.
The setup of the faces I'm not 100% sure about. I do the following:
meshDict[name].faces.push(
new THREE.Face3(parseInt(triangles[t]),
parseInt(triangles[t + 1]),
parseInt(triangles[t + 2]),
[normals[parseInt(triangles[t])],
normals[parseInt(triangles[t + 1])],
normals[parseInt(triangles[t + 2])]],
new THREE.Vector3(1, 1, 1), matIndex));
Here: t is the index iterator of the triangles array, normals is an array that holds the normal information of the vertices and matIndex is the material index of the face based on the sub-mesh number from the object file. This also seems to work correctly.
Now for the hard part. I searched all day for a clear explanation and/or good example of how to set-up the faceVertexUvs of a multi material mesh, but every second post I found shows a different method to set this up. After a lot of trial and error I got to this solution that works, but throws a LOT of warnings...
for (var f = 0; f < faces.length; f++)
{
if (currentMesh.faceVertexUvs[faces[f].materialIndex] == undefined)
{
currentMesh.faceVertexUvs[faces[f].materialIndex] = []
faceOffset = (faces[f].materialIndex == 0? 0 : 1) * f;
}
currentMesh.faceVertexUvs[faces[f].materialIndex].push(f);
currentMesh.faceVertexUvs[faces[f].materialIndex][f - faceOffset] = [];
currentMesh.faceVertexUvs[faces[f].materialIndex][f - faceOffset].push(uvs[faces[f].a]);
currentMesh.faceVertexUvs[faces[f].materialIndex][f - faceOffset].push(uvs[faces[f].b]);
currentMesh.faceVertexUvs[faces[f].materialIndex][f - faceOffset].push(uvs[faces[f].c]);
}
Here uvs is an array of Vector2 of the same length as the vertices array.
Basically I am doing:
faceVertexUvs[materialIndex][faceIndex][uvs[a], uvs[b], uvs[c]].
The number of material indexes is equal to the number of sub-meshes that the object has.
So this solution kinda works OK, but some of the textures are not looking correct (I suspect because the UV mapping of that area is not being set correctly), and I am getting a lot of warnings that say:
Important to note that all the models look OK in the exporting program so the issue is not from there.
Any ideas as to what I am doing wrong here?
So I think I finally managed to figure it out and I got it working correctly, and since the documentation is severely lacking in this area, and the examples are not quite clear I'll post my understanding of this topic here for anyone having the same issue.
So it goes like this:
Geometry.faveVertexUvs[UV LAYER][face index][uv[face.a], uv[face.b], uv[face.c]]
As far as I understand unless you have an AO (ambient occlusion) map, you only use UV LAYER 0.
Now, if you define a material index when setting up the faces of the geometry then each face will be rendered with the corresponding material, and there is no need to split the UVs into separate areas like I was doing in my question. So you only have to use:
Geometry.faces.push(new THREE.Face3(v0, v1, v2, [n0, n1, n2], vertexColor, materialIndex));
I'm very new to both three.js & to js in general.
1st I select a polyHedron geometry with a dat.gui checkbox
which renders say a tetrahedron. these selections work.
I also have a dat.gui checkbox to either phongfill or wireframe render.
I initially wanted just a wireframe type mesh but not with all of the internal triangles. I found the edgesgeometry() function which draws pretty much what I want(hard edges only). there is however a known issue with linewidth not working in windows anymore. all lines drawn as strokeweight/width 1.
I'd like to use tubeGeometry() to draw tubes of whatever radius as opposed to 1weight lines. I know I'll have to draw something such as a sphere at/over the connection vertices for it to not look ridiculous.
geo = new THREE.TetrahedronBufferGeometry(controls0.Radius,controls0.Detail);
...
egeo = new THREE.EdgesGeometry( geo );
lmat = new THREE.LineBasicMaterial({ color: 0x0099ff, linewidth: 4 });
ph = new THREE.LineSegments( egeo, lmat );
scene.add(ph);
....
playing around in the console I found some geometry/bufferGeomery arrays that are likely the vertices/indices of my selected X-hedron as their sizes change with type(tetra/icosa etc) selection & detail increase/decrease:
//p = dome.geometry.attributes.uv.array;
p = egeo.attributes.position.array
//p = geo.attributes.uv.array
...
var path = new THREE.Curve();
path.getPoint = function (t) {
// trace the arc as t ranges from 0 to 1
var segment = (0 - Math.PI*2) *t;
return new THREE.Vector3( Math.cos(segment), Math.sin(segment), 0);
};
var geomet = new THREE.TubeBufferGeometry( path, 10, 0.2, 12, false );
var mesh = new THREE.Mesh( geomet, mat );
scene.add( mesh );
from above the tubeGeometry() draws fine separately as well but with the "path" made by that curve example. How can I use the vertices from my tetrahedron for example to create that "path" to pass to tubegeometry() ?
maybe a function that creates "segment vectors" from the vertices ?
I think it needs other properties of curve/path as well ?
I'm quite stuck at this point.
ANY Help, suggestions or examples would be greatly appreciated !
thanks.
You can try to create a TubeGeometry for each edge. Generate a LineCurve3 as the input path. Use the vertices of the edge as the start and end vector for the line.
Consider to use something like "triangulated lines" as an alternative in order to visualize the wireframe of a mesh with a linewidth greater than 1. With the next release of three.js(R91) there are new line primitives for this. Demo:
https://rawgit.com/mrdoob/three.js/dev/examples/webgl_lines_fat.html
This approach is much more performant than drawing a bunch of meshes with a TubeGeometry.
I am trying to write a function that creates a point cloud from mesh. I also want to control colors of every vertex of that point cloud. So far I tried to assign colors of geometry but colors doesnt being updated.
InteractablePointCloud_simug=function(object, editor){
var signals=editor.signals;
var vertexSize=0.3;
var pointMat= new THREE.PointsMaterial({size:vertexSize , vertexColors:THREE.VertexColors});
var colors=[];
var colorStep=0.1;
for (var i = 0; i < object.geometry.vertices.length; i++) {
colors.push(new
THREE.Color(colorStep*i,colorStep*i,colorStep*i));
};
//get points from mesh of original object
var points=new THREE.Points(object.geometry,pointMat);
//Update colors
points.geometry.colors=colors;
points.geometry.colorsNeedUpdate=true;
updatePosition();
//Add points object to scene
editor.addNoneObjectMesh(points);
}
I think this is probably doable on other video cards, but mine does not seem to like it.
Theoretically.. if your material color is white.. it should multiply times the vertex color ( which is basically like using the vertex color ), but since you did not specify black as your color, this is not the problem ).
If your code is not working on your computer ( not on mine either ), you will have to go nuclear... and just create a new selectedPointsGeometry and a new selectedPointsMesh
Grab a couple of vertices from the original.. copy them.. put them in a vertices array.. and run an update method ( you have to recreate the geo and mesh every time.. at least on my PC, I tried calling every single update method, and had to resort to recreating )
mind the coffee script. #anchor is the container
updateSelectedVertices: (vertices) ->
if #selectedParticles
#anchor.remove #selectedParticles
#pointGeometry = new THREE.Geometry()
#pointGeometry.vertices = vertices
#selectedParticles = new (THREE.PointCloud)(
#pointGeometry,
#selectedPointMaterial
)
#pointGeometry.verticesNeedUpdate = true
#pointGeometry.computeLineDistances()
#selectedParticles.scale.copy #particles.scale
#selectedParticles.sortParticles = true
#anchor.add #selectedParticles
selectedPointMaterial is defined elsewhere. Just use a different color ( and different size ).. than your non selected point cloud.
IE.. use black and size 5 for non selected point cloud , and use yellow and 10 for the selected one.
My other mesh is called #particles.. and I just have to copy the scale. (this is the non-selected point cloud)
Now my selected points show as yellow
I'm trying to update an arrowHelper. I've tried manipulating the vertices in the arrow object's line, setting everything dynamic = true and so on, but the only way I can seem to do it is by removing the old line and drawing a new one. Is there a way to update an arrowHelper?
So you can't update an arrowHelper per se in the usual way you update something, by changing the values you used to create the object.
However: you can move the arrow's position, which moves its apparent start point, and you can give it a new direction and length, which moves its apparent end point.
Here's how to do it:
// new arrowHelper
var sourcePos = new THREE.Vector3(0, 0, 0);
var targetPos = new THREE.Vector3(0, 50, 0);
var direction = new THREE.Vector3().sub(targetPos, sourcePos);
var arrow = new THREE.ArrowHelper(direction.clone().normalize(), sourcePos, direction.length(), 0x00ff00);
scene.add(arrow);
// update the arrow
var newSourcePos = new THREE.Vector3(10, 10, 10);
var newTargetPos = new THREE.Vector3(60, 10, 10);
arrow.position.set(newSourcePos);
direction = new THREE.Vector3().sub(newTargetPos, newSourcePos);
arrow.setDirection(direction.normalize());
arrow.setLength(direction.length());
Thanks to the folks who answered this question, it certainly helped me. There are a couple of small problems with it that folks will want to avoid:
Calling direction.normalize() in the penultimate line of code changes the direction vector to a unit vector and thus the original length is lost. You can change the order of the last two lines, setting the arrow length from the unmodified direction vector, or (perhaps clearer) you can save its length in a separate variable. Without some such modification, though, the arrow will always be set to unit length.
In addition, the function arrow.setLength(length, headLength, headWidth) accepts two arguments beyond those shown in the answer (perhaps this has changed since this was written?). Accepting defaults for headLength and headWidth by not supplying explicit values in the call will result in overwriting any non-default values that might have been supplied in the constructor (rather than keeping the values as they are set).
I have some countries polygon. I want to draw them on top of my sphere with three js, but when I'm trying to draw these polygons, fps drop down, at 3fps....
Someone told me to create juste ONE geometry and include all the polygons into it, did you have an example?
What I'm doing:
foreach countrie in countries
geometry = new THREE.shapeGeometry();
geometry.push(vectorArray);
var mesh = new Mesh(geometry);
globe.Add(mesh);
With over 250 countries, Three js just creates over 38k buffer. Strange behaviour, without any control, we shouldn't be able to create such buffers... so where am I wrong? I need help.
The three.js class THREE.GeometryUtils has a number of helpful methods for situations like these...
In particular, there is a merge method that will combine two Geometry objects into one. Assume that you have three geometry objects, country1, country2, country3. Then you could do something like:
temp = THREE.GeometryUtils.merge( country1, country2 );
allCountries = THREE.GeometryUtils.merge( temp, country3 );
Hope this helps!