views:

385

answers:

2

Is it possible to access the surface normal - the normal associated with the plane of a fragment - from within a fragment shader? Or perhaps this can be done in the vertex shader?

Is all knowledge of the associated geometry lost when we go down the shader pipeline or is there some clever way of recovering that information in either the vertex of fragment shader?

Thanks in advance.

Cheers,
Doug
twitter: @dugla

A: 

If you pass the vertex normal through to the fragment shader in a "varying" then you will get an interpolated fragment normal.

EDIT: You will have to calculate the normals in your application, and pass them into your shader as an attribute for each vertex of your triangle.

The usual way to calculate the normal for a triangle is with a cross product.

  1. Call the three points making up the triangle P1, P2, and P3.
  2. Calculate V1, the vector from P1 to P2.
  3. Calculate V2, the vector from P1 to P3.
  4. Calculate the cross product of V1 and V2.

This will give you the normal to the plane of the triangle. V2 should be "to the left of" V1, or your normal will point "in" instead of "out". See the Wikipedia article on cross products for details.

FURTHER EDIT: Right, I understand your problem now. Yes, it's true that with shared vertices you can't really have more than one normal per vertex.

The only other thing that I can think of is that maybe a geometry shader could help, because it gets passed all three vertices for a triangle. I don't have any experience with them though.

Incredulous Monk
What I am looking for is the normal to the plane of the triangle across which interpolation is taking place. Each triangle that tesselates a surface by definition lines in a plane. I am after the normal to that plane.
dugla
This will not work in my case because I have shared vertices (vertex arrays). If I were sending triangles to the GPU one at a time I could simple attach plane coefficients to each vertex (redundant, I know) and I'm good. With a vertex array how can a shader (vertex or fragment, doesn't matter) disambiguate between triangles that share a vertex? The plane equations differ and there is no way I am aware of to signal to the shader which plane equation coefficients to use.
dugla
+1  A: 

You can get per-pixel normals interpolated from vertex normales by just using a "varying" (in newer OpenGL it is just in/out) variable. But do not forget to normalize this normal! Interpolated normals must not have a length of 1 any longer. These normals also give bad results on sharp edges.

If you want to use custom normals with a higher resolution a commonly used technique are normal maps. You create a texture with baked normals for your object. Then you can access the normal in the fragment texture using a textur look-up.

Danvil
Good point! I forgot to mention the need to renormalise the normals in the fragment shader. +1
Incredulous Monk