In an effort to learn a little bit more about custom geometry in three.js, I tried adapting Paul Bourke's capsule geometry example.
With my custom capsule geometry, I am currently having two issues:
The middle face normals are not oriented properly.
There is a hard seam along the side. (EDIT: fixed by deliberately computing the face normals. updated code in the gist)
And maybe one bonus question that has been lingering on my mind:
What might a general strategy be to add vertex loops in that middle segment?
I'm really happy with the geometry in general, but would anyone be able to give me some direction on how to address these issues? I feel like the normal issue in the middle segment must be the orientation of the faces, and here is the related face construction snippet:
for(let i = 0; i <= N/2; i++){
for(let j = 0; j < N; j++){
let vec = new THREE.Vector4(
i * ( N + 1 ) + j ,
i * ( N + 1 ) + ( j + 1 ) ,
( i + 1 ) * ( N + 1 ) + ( j + 1 ) ,
( i + 1 ) * ( N + 1 ) + j
);
let face_1 = new THREE.Face3(vec.x,vec.y,vec.z);
let face_2 = new THREE.Face3(vec.x,vec.z,vec.w);
geometry.faces.push(face_1);
geometry.faces.push(face_2);
}
}
CapsuleGeometry.js
The shading/normal seam is there because you have probably explicitly defined a hard edge there.
When you run your loops to generate the vertices, you probably duplicate the starting position. If you start at 0, and go all the way to 2PI, 0==2PI. When you weave the triangles, you probably tell the lest one to use the 2PI instead of 0 and even though they are in the same position, as far as triangles are concerned, they point to different vertices, and are thus not connected.
for(let i = 0; i <= N/4; i++){ //change to i < N
for(let j = 0; j <= N; j++){
If you tell the last triangle in the loop to point to the beginning vertex you will make a continous surface that geometry.computeVertexNormals() can smooth out.
You can also just compute these normals directly. All the normals can be obtained in these case from the vertex positions of the original sphere before expanding it.
Related
I'd like to be able to rotate multiple points around a central point. I'm trying to make it so it's sorta "dynamic", as in, when a point is destroyed, the other points update so it's still evenly circling the central point.
Basically for some experimental canvas thingy. I've tried lots of combinations of the math, to no avail
var spinner = undefined;
var angle = 0;
var z = 0;
function spinUser(){
if(spinner) clearInterval(spinner);
spinner = setInterval(function(){
angle = z*(Math.PI/180);
for(var i = 0; i < pointArray.length; i++){
let px = central.x + 3 * Math.cos(angle+i*(pointArray.length-points)) * 9 / 16;
let py = central.y + 3 * Math.sin(angle+i*(pointArray.length-points));
updatePos(px,py,i);
}
z += 2.5;
if(z >= 360) z = 0;
},50);
}
3 = radius
2.5 = speed
Say there should be 5 points, excluding the central point. It should do math, taking the current number of points and subtracting(?) by how many there should be, and updating the points' position like so.
Sorry if this question isn't as good as it should be, I'm kinda new to this question thing.
I currently have a city based on the example of Mr Doob's tutorial: "How to do a procedural city in 100 lines". In the tutorial you can see the that he creates 100 building meshes which then get merged into 1 city mesh for performance reasons. Then one material gets made that is applied to the city mesh, giving every building a texture.
What I want to stop is the clamping and stretching of the building texture. In order to create a more realistic "the windows are the same height on different buildings" look.
What I think would be the solution is to manipulate the face vertex UV's with the scaling values of the geometry.
With the following code I can scale the texture 2x.
let faceVertexUvs = buildingMesh.geometry.faceVertexUvs[0];
for (let k = 0; k < faceVertexUvs.length; k++) {
const uvs = faceVertexUvs[k];
if ( k == 4 || k == 5){
// Make the roof blank
uvs[0].set(0, 0);
uvs[1].set(0, 0);
uvs[2].set(0, 0);
}
else if( k % 2 == 0) {
uvs[0].set(0, 0.5);
uvs[1].set(0, 0);
uvs[2].set(0.5, 0.5);
}
else {
uvs[0].set(0, 0);
uvs[1].set(0.5, 0);
uvs[2].set(0.5, 0.5);
}
}
However I would like to only scale vertically and leave the horizontal scaling alone. But I don't completely understand the relation between the 2 triangles.
Perhaps you should modify the .repeat property of the city model's texture.
document link: https://threejs.org/docs/#api/textures/Texture.repeat
After using a debug image and guessing some values I came to the following code to scale a texture vertically, horizontally or both.
let scale_y = buildingMesh.scale.y/200;
let scale_x = buildingMesh.scale.x/100;
for (let k = 0; k < faceVertexUvs.length; k++) {
const uvs = faceVertexUvs[k];
else if( k % 2 == 0) {
uvs[0].set(0, texture_scale_y); // 0 1
uvs[1].set(0, 0); // 0 0
uvs[2].set(texture_scale_x, texture_scale_y); // 1 1
}
else {
uvs[0].set(0, 0); // 0 0
uvs[1].set(texture_scale_x, 0); // 1 0
uvs[2].set(texture_scale_x, texture_scale_y); // 1 1
}
}
This solves my problem but I still would like to know the explanation. I can see that the X is always first and the Y second but that might be a bad conclusion to make.
I couldn't color my vertices so I can't tell which vertex is which.
I'm trying to implement a wireframe which displays quads instead of tris using this code
var geo = new THREE.EdgesGeometry( _this.geometry ); // or WireframeGeometry
var mat = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } );
var wireframe = new THREE.LineSegments( geo, mat );
_this.scene.add( wireframe );
This produces the following when the model is rendered
As you can see from the image it is not displaying all of the edges, and is still displaying some tris. I need it to be similar to how Maya displays wireframes.
I have read that ThreeJS no longer supports Face4 which is why it always displays tris instead of quads, but i was wondering if there was a way around this? I have also seen some mention of using a pixel shader to display only the edges of a mesh but i havnt been able to understand/get that working.
I would love some assistance on this one, either using existing threejs functionality, or by using a pixel shader somehow.
This is the model source (http://pastebin.com/21XUKYbw)
Cheers
Answering this for anyone who stumbles upon this issue in the future.
Following on from a comment made by WestLangley, i have modified the code within WireframeGeometry.js to ignore rendering the interior diagonals that are present when rendering a wireframe, which gives the appearance of quad faces. Which is more familiar to 3d artists.
This is the change I've made to the bottom of WireframeGeometry.js. This is admittedly a pretty hacky fix. The alternative would be to compute the lines you want to display before threejs performs triangulation. You could store the pre triangluated faces in a separate buffer.
// non-indexed BufferGeometry
position = geometry.attributes.position;
var _i = 0;
for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
for ( j = 0; j < 3; j ++ )
// three edges per triangle, an edge is represented as (index1, index2)
// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
// Added a simple check here to only push the vertices that are not diagonal lines
if(!(j == 2 && _i == 1) || !(j == 1 && _i == 0)){
index1 = 3 * i + j;
vertex.fromBufferAttribute(position, index1);
vertices.push(vertex.x, vertex.y, vertex.z);
index2 = 3 * i + ( ( j + 1 ) % 3 );
vertex.fromBufferAttribute(position, index2);
vertices.push(vertex.x, vertex.y, vertex.z);
}
}
_i++;
if(_i == 2){
_i = 0
}
}
I have a file with sparse elevations. It is based off of gps data. I have been using this data to populate an PlaneBuffer array with elevations.
var vertices = new Float32Array( (grid.NCOL*grid.NROW) * 4 );
for (var i = 0, q = vertices.length; i < q; i++){
vertices[ i*3 + 0 ] = parseInt(i % (grid.NCOL+1)*4);
vertices[ i*3 + 1 ] = parseInt(i / (grid.NCOL+1)*4);
// vertices[ i*3 + 2 ] = null; // makes no difference
}
for (var i = 0, l = grid.NODES.length; i < l; i++) {
var nodeNumber = grid.NODES[i][0];
var elevation= grid.NODES[i][1];
vertices[ nodeNumber*3 + 2 ] = elevation;
}
My problem is that there are nodes that the elevation values are unknown(Vertex array is sparse with elevations) and should be represented by holes/cutouts in the plane. What I end up with is the null elevations being interpreted as 0 not as holes. I have started down the path of using a rawshader, but still not sure that making null values transparent is the correct method.
The below picture shows my issues. The circled area is a high wall that should not be there, because it triangulating to the "null/0" floor. The red-lines area is where we should have a hole.
EDIT:
Maybe this picture will help to. It is from the bottom. The null elevations being set to zero block the view of the plane and cause the edge of the plane to be triangulated to 0 elevation:
Here is what our desktop application displays. Notice the edges of the plane are not triangulated down to zero but instead left sharp?
Plane buffer Geometries take a Float32Array. This array is default set to 0. Using undefined setter allowed me to set the sparse array out of the float32 type. Attempts to set any value to null and NanN did not work.
RTFM:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array
final result as expected:
Your use case seems more appropriate for a point cloud with THREE.Points. potree.org/demo/potree_1.3/showcase/ca13.html – WestLangley 14 mins ago
This example helped:
http://threejs.org/examples/#webgl_buffergeometry_points
This is easier explained with pictures. I have these green points:
And I want to get a few points along this red line:
This is a top view, but I have complete XYZ coordinates for each point. I also have which vertex is connected to which other vertex.
It almost seems like you could just take the midpoint of each of those green edges and draw a line through them but you can see how that wouldn't really work near the end.
Is there an algorithm I can use to find a line of best fit through these 3D points?
I'm using Three.js if that makes a difference.
This task is equal to noise suppression.
the simplest algorithm (end of array will not be filtered):
double array[];
int count, depth;
// 1 < depth < count
for (int i = 0; i < count - depth; i++)
{
double sum = 0;
for (int j = 0; j < depth; j++)
{
sum += array[i + j];
}
array[i] = sum / depth;
}
You can find more info googling Median Filter and Noise Suppression