I am migrating my geometry to buffergeometry, but I have came to something preventing me to make progress. I can’t find a way to retrieve the normal of a triangle/face. I need to determine the direction a polygon is pointing… How can I accomplish this?
With geometry I was able to do
geometry.faces[f].normal
but I’m lost now with buffergeometry. How do I calculate the direction of a triangle?
var posAttribute = this.face.geometry.attributes.position;
var indexAttribute = this.face.geometry.index;
for(var f=0; f<2; f++){
var triangle = new THREE.Triangle( new THREE.Vector3(posAttribute.getX(indexAttribute[0+(f*3)]),posAttribute.getY(indexAttribute[0+(f*3)]),posAttribute.getZ(indexAttribute[0+(f*3)])),
new THREE.Vector3(posAttribute.getX(indexAttribute[1+(f*3)]),posAttribute.getY(indexAttribute[1+(f*3)]),posAttribute.getZ(indexAttribute[1+(f*3)])),
new THREE.Vector3(posAttribute.getX(indexAttribute[2+(f*3)]),posAttribute.getY(indexAttribute[2+(f*3)]),posAttribute.getZ(indexAttribute[2+(f*3)])), );
triangle.getNormal( copytoavector3 );
//otherstuff
}
I think I can do something like this… Let me know if there’s a better way.
Okay, there’s something, that can be simplified/optimized:
let pos = this.face.geometry.attributes.position;
let idx = this.face.geometry.index;
let tri = new THREE.Triangle(); // for re-use
let a = new THREE.Vector3(),
b = new THREE.Vector3(),
c = new THREE.Vector3(); // for re-use
for( let f = 0; f < 2; f++ ){
let idxBase = f * 3;
a.fromBufferAttribute( pos, idx.getX( idxBase + 0 ) );
b.fromBufferAttribute( pos, idx.getX( idxBase + 1 ) );
c.fromBufferAttribute( pos, idx.getX( idxBase + 2 ) );
tri.set( a, b, c );
tri.getNormal( copytoavector3 );
//otherstuff
}
How I can translate that to the bufferGeometry? I have tried the next code, but i got undefined “idx”
let pos = this.sourceGeometry.geometry.attributes.position;
let idx = this.sourceGeometry.geometry.index;
let tri = new THREE.Triangle();
let a = new THREE.Vector3(),
b = new THREE.Vector3(),
c = new THREE.Vector3();
for (let f = 0; f < 2; f++) {
let idxBase = f * 3;
a.fromBufferAttribute(pos, idx.getX(idxBase + 0));
b.fromBufferAttribute(pos, idx.getX(idxBase + 1));
c.fromBufferAttribute(pos, idx.getX(idxBase + 2));
tri.set(a, b, c);
}
It means, that your model has a non-indexed buffer geometry, as it has no .index property. They call it “triangle soup”, when faces defined with triplets of consequential vertices. So, there’s no need to use .index, work with geometry.attributes.position;.
Triangle has a setFromAttributeAndIndices method to simplify things:
const tri = new THREE.Triangle(); // for re-use
const indices = new THREE.Vector3(); // for re-use
const outNormal = new THREE.Vector3(); // this is the output normal you need
indices.fromArray(geometry.index.array, faceIndex * 3);
tri.setFromAttributeAndIndices(geometry.attributes.position,
indices.x,
indices.y,
indices.z);
tri.getNormal(outNormal);
Can @prominent or anyone post the working code? I’m trying to achiveve the same question but none of the code above is working. I want to draw normals of geometry faces’ center of gravity…
I could be able to draw a triangle, and could be able to draw a face normal from center of gravity but i want to do the same for the BoxGeomety faces.
What exactly isn’t working in your code? Maybe you can post the code for us.
It should be fairly straightforward- you’d just have to cycle through the faces in the box.
Hi @prominent, actually i’m stuck with the same thing with you. I made some research and found out that geometry.faces is deprecated because THREE.js is now using BufferGeometries now. I couldnt figure out how to iterate a triange on geometry’s faces. I tried erasta’s solution at the top but its giving some errors like, “faceIndex is not defined”, “geometry.index is possibly null” (I’m using typescript btw)
const tri = new THREE.Triangle(); // for re-use
const indices = new THREE.Vector3(); // for re-use
const outNormal = new THREE.Vector3(); // this is the output normal you need
for(let f=0; f<geometry.index.count; f++){
indices.fromArray(geometry.index.array, f * 3);
tri.setFromAttributeAndIndices(geometry.attributes.position,
indices.x,
indices.y,
indices.z);
tri.getNormal(outNormal);
//do something with the normal for this face
}
You’ll need to iterate through the faces. That’s what the faceIndex variable was for- to specify which index in the array. The attributes put the data into a 1 dimensional array, so that’s why it is multiplied by 3, because each position takes 3 values (x, y, and z).
You can read more about it here in the bufferAttributes section: three.js docs
Thank you @prominent for helping out. I could be able to create something working.
Out normals are looking to midpoints of square faces which is weird. i added a video
Here is my working code:
const boxMesh: THREE.Mesh = new THREE.Mesh(boxGeometry, boxMaterial)
scene.add(boxMesh)
boxMesh.position.x = 3
const tri = new THREE.Triangle(); // for re-use
const indices = new THREE.Vector3(); // for re-use
const outNormal = new THREE.Vector3(); // this is the output normal you need
const midPoint = new THREE.Vector3()
function getTriangles() {
for(let f = 0; f < boxGeometry.index!.count; f++){
indices.fromArray(boxGeometry.index!.array, f * 3)
tri.setFromAttributeAndIndices(boxGeometry.attributes.position,indices.x,indices.y,indices.z)
console.log(tri.getNormal(outNormal), " << OutNormal")
console.log(tri.getMidpoint(midPoint), " << Midpoint")
if(isNaN(midPoint.x) || isNaN(midPoint.y) || isNaN(midPoint.z)) return
const lineMaterial = new THREE.LineBasicMaterial( { color: 0x00ff00 } )
const linePoints = []
linePoints.push( tri.getMidpoint(midPoint) )
linePoints.push( tri.getNormal(outNormal) )
const lineGeometry = new THREE.BufferGeometry().setFromPoints( linePoints )
const line = new THREE.Line( lineGeometry, lineMaterial )
boxMesh.add(line)
}
}
getTriangles()
Your outNormal is a normalised vector3 meaning for example your top two out normals are (0,1,0) your line geometry is therefore going from your midPoint which is correct, to 0,1,0 in world space. Try making your second point in your line geometry outNormal + midPoint using vector3.add()