Broken light

I've just implemented a simple algorithm to calculate terrain vertex normals and I'm using diffuse and ambient light currently, but for some reason the squares that make up my terrain are visible when I turn on lighting as you can see in the above image. I'm currently calculating the normal for the terrain using the cross product formula between two vectors of the squares that compose the terrain. Is it because I should be using something like the average between the neighbour normals? I'll leave bellow the algorithm I'm using:

        //m_Polygon->Position is the 3D position of the vertex.
        XMVECTOR Vector1 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 4].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 3].Position));   //  .--
        XMVECTOR Vector2 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 4].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 1].Position));   //  |

        XMVECTOR Normal = XMVector3Normalize(XMVector3Cross(Vector1, Vector2));

        m_Polygon[m_Polygon.size() - 4].Normal = XMFLOAT3(XMVectorGetX(Normal), XMVectorGetY(Normal), XMVectorGetZ(Normal));

        Vector1 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 3].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 2].Position));   //  --.
        Vector2 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 3].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 4].Position));   //    |

        Normal = XMVector3Normalize(XMVector3Cross(Vector1, Vector2));

        m_Polygon[m_Polygon.size() - 3].Normal = XMFLOAT3(XMVectorGetX(Normal), XMVectorGetY(Normal), XMVectorGetZ(Normal));

        Vector1 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 2].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 1].Position));   //    |
        Vector2 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 2].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 3].Position));   //  --.

        Normal = XMVector3Normalize(XMVector3Cross(Vector1, Vector2));

        m_Polygon[m_Polygon.size() - 2].Normal = XMFLOAT3(XMVectorGetX(Normal), XMVectorGetY(Normal), XMVectorGetZ(Normal));

        Vector1 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 1].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 4].Position));   //  |
        Vector2 = XMVectorSubtract(XMLoadFloat3(&m_Polygon[m_Polygon.size() - 1].Position), XMLoadFloat3(&m_Polygon[m_Polygon.size() - 2].Position));   //  .--

        Normal = XMVector3Normalize(XMVector3Cross(Vector1, Vector2));

        m_Polygon[m_Polygon.size() - 1].Normal = XMFLOAT3(XMVectorGetX(Normal), XMVectorGetY(Normal), XMVectorGetZ(Normal));

As you can see I'm using DirectXMath Library to calculate everything, I just calculate the normals for the last square(4 vertices distributed in clockwise order).

  • 2
    \$\begingroup\$ Do you have 4 copies of each vertex, one for each quad meeting at that point? That may be 4x more data than you need if you always want smooth blending between quads. \$\endgroup\$
    – DMGregory
    Commented Oct 23, 2021 at 15:20
  • \$\begingroup\$ Yes it is, but I was thinking of solving this later with indexing. \$\endgroup\$ Commented Oct 23, 2021 at 15:42
  • 2
    \$\begingroup\$ Solve it now and it will remove the seams, and cut the work of determining normals down to a quarter. 😉 \$\endgroup\$
    – DMGregory
    Commented Oct 23, 2021 at 15:48
  • \$\begingroup\$ @DMGregory Thanks! \$\endgroup\$ Commented Oct 25, 2021 at 23:03
  • \$\begingroup\$ If you've solved your problem, be sure to share your solution as an Answer below. \$\endgroup\$
    – DMGregory
    Commented Oct 26, 2021 at 1:19

1 Answer 1


There was one mistake in my code and one issue.

The mistake was what DMGregory mentioned in the comments, each vertex in my vertex buffer had four copies of itself, which was causing me issues to calculate normals. So after fixing it to just use one copy of each vertex, I could calculate the normals more clearly.

The issue was that the light wasn't having a smooth transition at all. The reason behind this is that each normal vector needed to be composed from an average of the cross product vectors between neighbour vertices.

This is the current state of my terrain lighting:New ligthing Which also leads me to believe that the amount of averages that one can take between neighbour vertices impacts directly the quality of the ligthing over a mesh.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .