Compute surfaces of objects

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.

@derseitzer
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.

@derseitzer Take a look at this SO answer

I want to thank all of you guys very much!! It works perfectly. A big surface takes some time (max. 20sec.) but i will try to maximize code effiency now, refactor and i will probably show the loading progress somehow. Thank you very much! :slight_smile:

2 Likes

The actual problem is solved but i have one more little thing with this solution where you guys maybe also can help me: When i have two objects now and i computed for both of them a surface, i want these surfaces to get together. So there’s alot of possibilities now. I could put a 3d Box around them and match them together or a more complex approach would be: I calculate the distance of every obj1.vertex.position to every other obj2.vertex.position and find the closest one and translate an object in the direction of the other object this far. It would have a bad calculation time, but it would be stupid to calculate these surfaces to then put a 3d box around it and make it inaccurate again. Do you guys have other ideas then the 2 i described?

EDIT: Calculating the midpoint of the surfaces would be very interesting.

To calculate the midpoint of a mesh you just sum up all the vertices and finally divide the result by the number of points. I.E., you get the average of all .x, .y and .z