1
\$\begingroup\$

I understand how to generate geometry using marching cubes at an isosurface, but I haven't been able to find a clear explanation on how to calculate the vertex normals for a mesh produced using marching cubes.

Right now, for each triangle generated during the lookup phase, I can calculate a face (not vertex) normal simply by taking the cross product of two of the vectors in the triangle ie:

Triangle = [p1, p2, p3];
normal[face] = (p2 - p1).cross(p3 - p1).normalized();

But how do I compute the vertex normals at p1 p2 and p3 to allow for smooth shading? The only way I can think of is to sample the density function to produce an estimate of its gradient -- but is there a faster way?

\$\endgroup\$
  • \$\begingroup\$ FYI I decided to just use finite differencing on the field for now instead of doing the more usual thing and storing an index buffer + adjacent face calculations. \$\endgroup\$ – mklingen Apr 7 '15 at 16:23
  • \$\begingroup\$ How is your isosurface defined? If the underlying potential function is differentiable, you could compute its gradient vector, which will point perpendicular to the isosurface (ie. along the surface normal) at every point, including at the vertex positions you've chosen. \$\endgroup\$ – DMGregory Aug 9 at 11:49
3
\$\begingroup\$

Essentially, the normal of the vertex would be the average of the adjacent faces' (triangles) normals.

In pseudocode:

for each face adjacent to vertex[n]
    sum = sum + face.normal
normal[n] = NORMALIZE(sum / COUNT(adjacent faces))

Repeat for each vertex.

\$\endgroup\$
  • \$\begingroup\$ Okay, but without creating a face graph, how do I know which faces are adjacent to which vertex? I guess the answer is I need to make an index buffer? \$\endgroup\$ – mklingen Apr 2 '15 at 1:03
  • \$\begingroup\$ That sortof depends on how you're storing your triangles and the order your implementation creates them in, but if it's unindexed, ungraphed, and unordered then you'll have to iterate through the list of triangles to find each face containing each vertex. I recommend entering the triangles into some kind of structure as you create them in the marching cubes part, then calculating the normals. \$\endgroup\$ – jzx Apr 2 '15 at 1:10
  • \$\begingroup\$ I should probably stop using triangle and face interchangeably. To be clear, that's what I'm doing. =P \$\endgroup\$ – jzx Apr 2 '15 at 1:11
  • \$\begingroup\$ Yes, I guess its time to stop being lazy and using a mesh representation that's just a big mash of vertexes representing triangles with no other structure. \$\endgroup\$ – mklingen Apr 2 '15 at 1:12
  • \$\begingroup\$ Half-edge mesh is rather convenient for those kind of things. \$\endgroup\$ – Roman Reiner Apr 2 '15 at 5:35
0
\$\begingroup\$

Calculate normals at the grid vertices as following:

Grid[cx,cy,cz].Normal.X := (Grid[cx-1, cy, cz].Value-Grid[cx+1, cy, cz].Value)
Grid[cx,cy,cz].Normal.Y := (Grid[cx, cy-1, cz].Value-Grid[cx, cy+1, cz].Value)
Grid[cx,cy,cz].Normal.Z := (Grid[cx, cy, cz-1].Value-Grid[cx, cy, cz+1].Value)

NormalizeVector(Grid[cx,cy,cz].Normal);

then interpolate along the segment...

\$\endgroup\$
0
\$\begingroup\$

If you have indices, vertices and triangles you can do the following:

  • Create a struct of vertexes_ and put inside a Vector3 normal and an int faceCount
  • Create a dynamic list of vertexes_ and whenever you add a vertex to your mesh add also an empty element of vertexes_
  • In your Triangle class besides storing the vertices v1, v2, v3, store also their indices i1, i2, i3
  • Now iterate through your triangles ti and add to the vertexes_[i1].normal, vertexes_[i2].normal, vertexes_[i3].normal the face normal and increase the vertexes_[i1].faceCount, vertexes_[i2].faceCount, vertexes_[i3].faceCount by 1
  • Then iterate through your vertices vi and divide every vertexes_[vi].normal by the vertexes_[vi].faceCount

Hope this helps!

\$\endgroup\$
  • \$\begingroup\$ Dont forget to clear the normal to Vector3(0,0,0) and the faceCount to 0 before that \$\endgroup\$ – user1475834 Aug 9 at 8:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.