8

I have a small problem calculating normals for my heightmap. It has a strange behavior. At the higher and the lower points the normals are fine, but in the middle they seem wrong. They are lighted by a point light. Problem

UNFIXED SOURCE REMOVED

EDIT: Tried 2 new approaches:

This is per-face-normal. It looks fine but you see the single faces.

Position normal = crossP(vectorize(pOL, pUR), vectorize(pOR, pUL));

I also tried to do it per-vertex this way, but also with a strange output.

enter image description here

This is the suggestion Nico made:

It looks also rather odd. Maybe there is a mistake how I calculate the helping points.

UNFIXED SOURCE REMOVED

enter image description here

EDIT 2: Definition of my points: OL,OR,UL,UR are the corner vertices of the plane that is to be drawn.

                postVertPosZ1 postVertPosZ2
preVertPosX1         pOL           pOR         postVertPosX1
preVertPosX2         pUL           pUR         postVertPosX2
                 preVertPosZ1  preVertPosZ2

EDIT3:

I solved it now. It was a stupid mistake: I forgot to multiply the y value of the helping Vertices with the height Multiplier and had to change some values.

It is beautiful now. enter image description here

Eskalior
  • 234
  • 2
  • 12
  • 1
    Possible duplicate of [Calculating normals in a triangle mesh](http://stackoverflow.com/questions/6656358/calculating-normals-in-a-triangle-mesh) – legends2k Nov 16 '15 at 14:57
  • Relevant: https://en.wikipedia.org/wiki/Sobel_operator – sbabbi Nov 16 '15 at 22:01

1 Answers1

12

There are lots of ways to solve this problem. I haven't encountered yours. I suggest using central differences to estimate partial derivatives of the height field. Then use the cross product to get the normal:

Each vertex normal can be calculated from its four neighbors. You don't need the plane plus its neighbors:

  T
L O R
  B

O is the vertex for which you want to calculate the normal. The other vertices (top, right, bottom, left) are its neighbors. Then we want to calculate the central differences in the horizontal and vertical direction:

             /           2           \
horizontal = | height(R) - height(L) |
             \           0           /

             /           0           \
vertical   = | height(B) - height(T) |
             \           2           /

The normal is the cross product of these tangents:

normal = normalize(cross(vertical, horizontal))
                   / / height(L) - height(R) \ \
       = normalize | |           2           | |
                   \ \ height(T) - height(B) / /

Note that these calculations assume that your x-axis is aligned to the right and the z-axis down.

Nico Schertler
  • 31,461
  • 4
  • 36
  • 65
  • I edited my post. Maybe my error lies in determining the helping points (prevVertPosX1, ...) – Eskalior Nov 16 '15 at 14:58
  • Could you add which neighbors they are supposed to be? I can imagine what `postVertPosX2` could be, but your numbering could be anything. So better just put it somewhere. – Nico Schertler Nov 16 '15 at 15:13
  • I edited it. But thanks to you I have noticed that I have switched pre and post positions of the Z-Points. I changed that but the result is the same.. – Eskalior Nov 16 '15 at 15:34
  • Your coordinate system might not match my assumptions. Try negating the normal. Apart from that, the majority of points are wrong (according to your figure). E.g. `nOL` should be `normalize(Position ( preVertPosX1.y - pOR.y, 2, postVertPosZ1.y - pUL.y))`. The point which comes first on the according axes should come first in the equation (left before right (increasing x), top before bottom (increasing z)). – Nico Schertler Nov 16 '15 at 15:48
  • I managed to solve it now. The main problem was a missing multiplication of the height. But thanks for your help and the per-vertex-approach, I implemented it now and it seems to work. – Eskalior Nov 16 '15 at 16:50