I have a mesh (verticies, indicies, normals).This mesh uses following world coordinate system:

  • Forward: x
  • Up: z
  • Right: y

I am trying to convert it to a different coordinate system:

  • Forward: z
  • Up: y
  • Right: -x

I swizzled verticies from xzy to zy-x and the geometry looks fine. But the same trick didn't work for normals. What I am missing? Should I use some kind of matrices?

Thank you for any help you can offer!

EDIT Red lines - normals vizualization

enter image description here

Here is a part of code that shows normals:

GLKVector3 up = GLKVector3Make(0, 0, 1); GLKVector3 normalVec = GLKVector3Make(normalBuffer[i * stride + normalOffset], normalBuffer[i * stride + 1 + normalOffset], normalBuffer[i * stride + 2 + normalOffset]); GLKVector3 axis = GLKVector3Normalize(GLKVector3CrossProduct(up, normalVec)); float dotProduct = GLKVector3DotProduct(up, normalVec); normalNode.rotation = SCNVector4Make(axis.x, axis.y, axis.z, acos(dotProduct));


2 Answers 2


Every time you interchange two axes, or negate an axis, you mirror space.

So to go from xzy to zy-x we perform:

  1. Interchange x & z: zxy (mirrored)

  2. Interchange x & y: zyx (unmirrored)

  3. Negate x: zy-x (mirrored)

Because we used an odd number of flips, the mesh we have at the end is a mirror image of the one we started with. (That makes sense, since our starting coordinate system was left-handed but our destination is right-handed)

This mirroring means that any faces that had been wound counter-clockwise are now wound clockwise, or vice versa, flipping which side of the surface the renderer thinks is "outside" versus "inside." This can look like a problem with the normals because it affects how the faces get rendered.

To fix this, you can take a pass through all of your triangles and interchange two vertices to reverse the winding order, or flip the direction of backface culling in your render state.

As an aside, it looks like the conversion formula you'd want would look like this:

output.x = -input.y  // left = -right
output.y = input.z   // up = up
output.z = input.x   // forward = forward
  • \$\begingroup\$ I swapped 2nd and 3rd indicies of every triangle and that fixed the problem with "inverted" surface. But normals are still incorrect. My conversion looks like this GLKVector3Make(-position.y, position.z, position.x). Any ideas? \$\endgroup\$
    – VenoMKO
    Apr 27, 2018 at 13:22
  • \$\begingroup\$ Can you show us an example of these incorrect normals? \$\endgroup\$
    – DMGregory
    Apr 27, 2018 at 13:23
  • \$\begingroup\$ i'v updated my question \$\endgroup\$
    – VenoMKO
    Apr 27, 2018 at 13:34
  • \$\begingroup\$ I had a typo in my code. Now everything is fine. Thanks! One more question. Should i apply same transformation to tangents? \$\endgroup\$
    – VenoMKO
    Apr 28, 2018 at 5:34

Your mesh should not be in world space. It should be in "object space". It can then be scaled/translated/rotated into world space by homogeneous transform matrices on the GPU.

This includes changes in coordinate system (which, mathematically speaking is exactly the same thing, as a translation).

To do this, you create a 4x4 transform matrix, with the scale component being (-1,1,1), then multiply all other operations by this as a final step:

// right to left ordering
mat4 transform = Othercoordinate * Wscale * Wrotation * Wtranslation
vec4 FinalVertex = transform * ObjectVertex;

To transform your normals:

// right to left ordering
mat3 NormalTransform = transpose(inverse(mat3(transform)));
vec3 finalNormal = NormalTransform * ObjectNormal;

I strongly recommend you read this, and this, to better understand how homogeneous coordinate systems work, as it is integral to modern computer graphics.

  • \$\begingroup\$ Thanks a lot for your help and the links! DMGregory's answer fixed my issue with a single operation by just swapping 2 verticies. \$\endgroup\$
    – VenoMKO
    Apr 28, 2018 at 5:37

You must log in to answer this question.

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