Color/normal interpolation artifact with triangles

Hi all, my project has a lot of quads represented with 2 triangles and I’m getting some unsightly seams with color and normal interpolation. I figured I may as well see if there’s a quick fix, but based on what I’ve seen from Google I may just need to store these attributes differently or even add more faces to smooth things out.

Here we see an example with color on a simple quad. I want to eliminate the clearly visible diagonal, though it may be a “human eye” thing. I remembered barycentric coordinates from graphics class a few years ago but I feel the shader pipeline does that correctly, so probably not related to this issue.

Here is an example with the Phong reflection model exponent set way high. This time it’s the normals that are not quite right.

So, to smooth things out am I right in suspecting I will just have to subdivide more until there’s enough points to make it unnoticeable? Or is it likely I’ve messed something up? I’ll be happy to post any code if needed.

You have a continuity problem based on the triangle interpolation. The following statements are not necessarily true for all interpolation models, but should be for the basic linear interpolations done by the GPU:

If you have a triangle with 3 colours at the nodes, than each node will contribute to the final colour as long as you are not on the boundary. If you are on the boundary, only the 2 nodes that form that boundary will contribute.
If you have a rectangle with 4 colours at the nodes, than each node will contribute to the final colour as long as you are not on the boundary. If you are on the boundary, only the 2 nodes that form that boundary will contribute.

Comparing these two statements gives the following conclusion:

If you split up a rectangle into two triangles, the interpolated values on the outer boundaries stay the same. However, the surface in each triangle is only interpolated with 3 values instead of 4. Additionally you create another boundary (the diagonal), which means that you interpolate only two points there, while the rectangle uses 4. So in your picture the diagonal values are only composed of green and blue instead of red, green, black and blue. The same problem holds for the normal interpolation.

As said before, this is a continuity problem. The interpolation you (or the GPU) use has C0 continuity. This means that if you would do a mathematical plot of the interpolated values the resulting curve has no gaps/jumps in it, but it might contain visible kinks (located were the boundaries are) because its first derivative can have gaps/jumps. Its like a car that drives with 10km/h and its speed suddenly jumps to 30km/h with no acceleration phase in between as soon as it passes the boundary. Even though its position (C0) does not jump, its velocity (C1) does which would result in a kink in a time-position plot.

So how to solve that?

The best solution would be to use an interpolation that is C1 contiguous. This can normally be achieved with splines/NURBS. I am not sure if this is possible here, since it requires higher order interpolations of triangles, which is not possible to my knowledge. Maybe one of the more experienced users can give a statement on that (Curious if it is possible in Vulkan…).
The second possibility woul be to use higher order triangle interpolation without splines/NURBS, but the same question as before remains.
The third and last option I know is to simply subdivide your mesh (as you suggested), until the the kinks are barely noticeable.

The combination of the second and third solution is known as h-p-refinement in case you want to know more about it.

Hope I could help you a little to understand what’s going on.


Hard to say.

Interpolating normals then performing normalisation and a dot product for each fragment (Phong shading) will give better results than calculating colours at the vertices and interpolating colours (Gouraud shading). More vertices will give better results than fewer vertices. If you’re calculating vertex normals from face normals, averaging un-normalised face normals (so the weight is proportional to the area of the face) will give better results than normalising the face normals prior to averaging. If the vertices are obtained by sampling a smooth surface, calculating the normals from the surface’s derivatives will be better than calculating them from the sampled mesh. Also, vertex normals don’t need to have unit length; you can scale them in proportion to their weight (which should be inversely proportional to the curvature at the vertex).

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.