Compute surfaces of objects

@anon81599084 Three consequent vertices define a triangle/face in a non-indexed buffer geometry.

Then the “BufferGeometry, Indexed” - example in three.js confuses me. It has 121 vertices (plane of 11 x 11), but if your right, vertices should be represented more often in the array because they are used for multiple triangles, or what am i missing here…

In an indexed buffer geometry faces are defined with indices of vertices in its .index property.

The simplest thing - quad:
Non-indexed buffer geometry: .index is null, position attribute contains information for 6 vertices (3 vertices per face, as a quad is built with 2 faces)
Indexed buffer geometry: position attribute contains information about 4 vertices and index has 6 indices (3 indices of vertices for each of 2 faces)

[0]------[1]
 |      / |
 |    /   |
 |  /     |
[2]------[3]

4 vertices and .index is [0, 2, 1, 2, 3, 1]

Perhaps the very simple examples help. :slightly_smiling_face:

https://hofk.de/main/discourse.threejs/2017/BufferGeometry/BufferGeometry.html
https://hofk.de/main/discourse.threejs/2017/Indexed%20BufferGeometry/Indexed%20BufferGeometry.html

from
https://hofk.de/main/discourse.threejs/2017/index2017.html

or
https://hofk.de/main/discourse.threejs/2019/ColorStripeChanging2/ColorStripeChanging2.html

see

Okay thank you very much. So i have my non-indexed mesh and want to compute the facenormals now (i read that attributes.normal of a non-indexed mesh are usually vertexnormals https://github.com/mrdoob/three.js/issues/12559). But there’s sadly no function for that. Do i have to filter out the vertex normals manually and compute face normals myself?

Edit. copied this from THREE.Geometry, so i should have my facenormals

cb.subVectors( vC, vB );
ab.subVectors( vA, vB );
cb.cross( ab );

cb.normalize();

It’s just a matter of practice. One can work with Geometry, indexed BufferGeometry and non-indexed Buffergeometry

But Geometry is no longer recommended. See e.g. Will Geometry be deprecated or maintained along BufferGeometry?

In my addon THREEf.js I used all three possibilities in parallel. There you can compare well. But the thing there is quite complex.
Addon. Produces almost infinite many time-varying geometries with functions
https://github.com/hofk/THREEf.js/blob/b263d88d9b783b5dca4f5008e718997b6a3e75f0/THREEf_90/THREEf.js
There you can see what is achievable. https://hofk.de/main/threejs/sandboxthreef/

Maybe there’s something for you? https://github.com/hofk/THREEg.js

i actually have to use Buffergeometry, because my imported stl-object is one by default. So by calculating face normals i think i have all i want.

Good luck to you. :slightly_smiling_face:

Using of THREE.Triangle() can be helpful.
Something like this:

var pos = geometry.attributes.position;
var tri = new THREE.Triangle(); // for re-use
var a = new THREE.Vector3(); // for re-use
var b = new THREE.Vector3(); // for re-use
var c = new THREE.Vector3(); // for re-use
var normals = [];
var faces = pos.count / 3;

for (let i = 0; i < faces; i++){
  a.fromBufferAttribute(pos, i * 3 + 0);
  b.fromBufferAttribute(pos, i * 3 + 1);
  c.fromBufferAttribute(pos, i * 3 + 2);
  tri.set(a, b, c);
  let n = new THREE.Vector3();
  tri.getNormal(n);
  normals.push(n);
}
2 Likes

There has to be something wrong with this code. a, b and c are on every loop cycle the same.
I tested with:
if (i==0 |i==5 | i==123 || i==227 …)
console.log(tri);
Everytime the same numbers for a, b and c (f.e. for a.x = 1, a.y=2 a.z=3, b.x=4, b.y = 5…). Same for every i

EDIT:
Ok i found it… it works when the triangle is declared inside the for loop like this:
let tri = new THREE.Triangle();
Probably something strange happens when a triangles a,b and c is already declared and set to new vectors…

I guess that all the logged values are equal to the values of the last triangle.
And I hope you didn’t put instantiating of triangle inside the loop.

var mytri = new THREE.Triangle();
var vectorA = new THREE.Vector3();
var vectorB = new THREE.Vector3();
var vectorC = new THREE.Vector3();
vectorA.x = 1;
vectorA.y = 1;
vectorA.z = 1;
vectorB.x = 1;
vectorB.y = 1;
vectorB.z = 1;
vectorC.x = 1;
vectorC.y = 1;
vectorC.z = 1;
mytri.set (vectorA, vectorB, vectorC);
console.log(mytri);
vectorA.x = 2;
vectorA.y = 2;
vectorA.z = 2;
vectorB.x = 2;
vectorB.y = 2;
vectorB.z = 2;
vectorC.x = 2;
vectorC.y = 2;
vectorC.z = 2;
mytri.set (vectorA, vectorB, vectorC);
console.log(mytri);

This code outputs 2 triangles, both consist only of 2s, not a single 1.

This code doesnt work:
var pos = geometry.attributes.position;
var tri = new THREE.Triangle(); // for re-use
var a = new THREE.Vector3(); // for re-use
var b = new THREE.Vector3(); // for re-use
var c = new THREE.Vector3(); // for re-use
var normals = [];
var faces = pos.count / 3;

for (let i = 0; i < faces; i++){
a.fromBufferAttribute(pos, i * 3 + 0);
b.fromBufferAttribute(pos, i * 3 + 1);
c.fromBufferAttribute(pos, i * 3 + 2);
tri.set(a, b, c);
let n = new THREE.Vector3();
tri.getNormal(n);
normals.push(n);
}

But this code does:

var pos = geometry.attributes.position;
var a = new THREE.Vector3(); // for re-use
var b = new THREE.Vector3(); // for re-use
var c = new THREE.Vector3(); // for re-use
var normals = [];
var faces = pos.count / 3;

for (let i = 0; i < faces; i++){
let tri = new THREE.Triangle(); // for re-use
a.fromBufferAttribute(pos, i * 3 + 0);
b.fromBufferAttribute(pos, i * 3 + 1);
c.fromBufferAttribute(pos, i * 3 + 2);
tri.set(a, b, c);
let n = new THREE.Vector3();
tri.getNormal(n);
normals.push(n);
}

Shouldn’ it be…?

a.fromBufferAttribute(pos, ( i * 3 + 0 ) * 3 );
b.fromBufferAttribute(pos, ( i * 3 + 1 ) * 3 );
c.fromBufferAttribute(pos, ( i * 3 + 2 ) * 3 );

Each face has 9 floats.

@anon81599084
This code is indended to calculate normals. Have you tried to log result normals?
When you log the triangle, when it’s outside of the loop, you log the same object.

@yombo
i comes from the number of faces, which is amount of vertices (.count) divided by 3. But maybe I’m wrong with my suggestion as I wrote that code from the scratch, thus it’s not tested :slight_smile:

@prisoner849 i know its intended to calculate normals, but if all triangles are the same, all normal are the same, too. It actually doesn’t matter that much anymore, because i just use the second code where every triangle is defined in the loop (let tri) and it works like this for me. I was just unsure if its normal when you code: tri.set(v1,v2,v3) and log that and then tri.set(v4, v5, v6) and log that again, its always the same.

@yombo the code works almost like prisoner849 said. yes every face has 9 floats, but here you just want the 3 vectors :slight_smile:

my code atm works without errors, i have to code colors now and then debug. (already debugged some parts) and i think it looks quite good. I will keep you up to date

1 Like

Are you sure that all normals are the same? Have you tried console.log(n) in the loop?

Yes i tried. All normals were the same and all triangles until i changed “var tri” to “let tri” and put it in the loop. After that i was curious about it, why this happens and tried the code on post 24 and i still don’t understand why it works like that (maybe a bug or maybe i’m a stupid, both could be true) but whatever, its working now x)

I just made a quick example and tried it with my initial code, it works as expected.
https://jsfiddle.net/prisoner849/wz6ymo8d/
See console log of normals.

@anon81599084 Take a look at this SO answer