I have an issue with back face culling in my engine on the monkey model from Blender exported as .obj format. However, with the box model from Blender exported the same way all is good.

My first assumption is that something's wrong with the winding order of certain faces in the monkey model. So I've tried to check order by calculating normals on each face by myself using the cross product cross(v2-v1,v3-v1).

I expected that all normals would have Z-coordinate with the same sign, but got different results on different faces.

But why is the box, which I exported the same way, rendered correctly? So, I tried to calculate normals the same way on the box model–and wow!–I still get different Z signs on two faces out of twelve...

But I see that the box is rendered correctly, then I checked my method to calculate the faces' normals. And they calculated correctly–you can see them in the box GIF.

So the question is: did I correctly understood winding order? A I use the correct way to check the winding? Should all faces in the model have the same sign of Z for normals? Should I do additional geometry preparation for object models to render them all correctly?

  • The engine follows the left-handed rule.
  • Render API: Metal.
  • All draws happen with backface culling and in clockwise order.

P.S.: online renderers of .obj models renders my monkey model correctly. I don't understand what to fix in my engine, cause my assumptions that normals should all have the same Z sign seems to be wrong.


<iframe src="https://giphy.com/embed/8Rtq2jXCowwkCIkFoK" width="480" height="400" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/8Rtq2jXCowwkCIkFoK">via GIPHY</a></p>


<iframe src="https://giphy.com/embed/Hvbi2wmktmfziLavii" width="480" height="400" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/Hvbi2wmktmfziLavii">via GIPHY</a></p>

  • \$\begingroup\$ A also draw calculated normals for monkey's faces. They all seems to point out of face, that is correct. That means that winding order is correct, right? But why they still can be rendered incorrectly?(like on monkey gif) \$\endgroup\$
    – justix
    Feb 9, 2022 at 17:59
  • 1
    \$\begingroup\$ This looks to me as if the problem isn't with the normals. The problem appears to be that you didn't implement Z-buffering properly. So you draw polygons which should be hidden behind other polygons. You don't notice with the cube because a cube is a convex shape. So any polygons which are obscured by other polygons also face away from the camera. \$\endgroup\$
    – Philipp
    Feb 10, 2022 at 17:12
  • \$\begingroup\$ @Philipp Yes, you are right. It's about z-buffering. I've posted an answer. \$\endgroup\$
    – justix
    Feb 10, 2022 at 18:31

1 Answer 1


After rotating that monkey a thousand times I noticed, that it actually hides back face triangles! Back face culling actually works fine. It's all about hiding polygons that covered by another polygons in front (depth test).

I didn't know that in Metal depth test is disabled by default. So after setup a depth buffer and adding a depth state to pipeline all works great.

Don't forget to check a depth test in those kind of cases =)


You must log in to answer this question.

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