Overv / VulkanTutorial

Tutorial for the Vulkan graphics and compute API
https://vulkan-tutorial.com
Creative Commons Attribution Share Alike 4.0 International
3.06k stars 511 forks source link

GLM_FORCE_LEFT_HANDED #244

Open jjYBdx4IL opened 3 years ago

jjYBdx4IL commented 3 years ago

Is this explained?:

https://github.com/Overv/VulkanTutorial/blob/master/code/27_model_loading.cpp#L1331

I think you need to add

#define GLM_FORCE_LEFT_HANDED

to avoid that "fix".

Krenodeno commented 3 years ago

I can't remember where it is explained, but if I recall correctly, this is because OpenGL has not the same image coordinates convention as Vulkan, and GLM was made for GL, so we need to inverse the image coordinate to avoid having an upside-down result

Krenodeno commented 3 years ago

Found the explanation: https://github.com/Overv/VulkanTutorial/blob/master/en/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md near the end

jjYBdx4IL commented 3 years ago

Exactly. That's what the left hand macro is for.

jjYBdx4IL commented 3 years ago

https://chromium.googlesource.com/external/github.com/g-truc/glm/+/HEAD/manual.md#section2_16

Overv commented 3 years ago

That can't be the only thing, because if I define GLM_FORCE_LEFT_HANDED and remove the -1 multiplication, I get an upside down image. It's only upright if I proceed to flip the up axis in the glm::lookAt.

jjYBdx4IL commented 3 years ago

For example 27 I have reconstructed 3 changes from my own implementation:

Header section:

#define GLM_FORCE_LEFT_HANDED
#include <glm/ext.hpp> // for glm::rotate

At end of loadModel:

    // fix model coordinates
    glm::mat4 rot = glm::rotate(glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f))
        * glm::rotate(glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
    for (Vertex& v : vertices) {
        v.pos = rot * glm::vec4(v.pos, 1.0f);
    }

updateUniformBuffer:

    ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    ubo.view = glm::lookAt(glm::vec3(2.0f, -2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

Though I have to admit that I'm not quite sure why the up-vector has a positive y component. Shouldn't that be negative in Vulkan coords? Probably because the model coords are still upside down in Vulkan coords? I did only rotate the model after import after all.

jjYBdx4IL commented 3 years ago

The proper import of the object model and its proper alignment along Vulkan coordinates probably warrants a separate chapter.

Overv commented 3 years ago

The model was exported with positive Y coordinates meaning up, so that would be the convention for the view transform in this case.

crud89 commented 3 years ago

The proper fix to this issue is not to do this at run-time, but instead using a compiler switch for the shaders:

The compiler switches will add code that inverts the y-coordinate for outputs of the VS/GS/TE shader stages to comply with the Vulkan coordinate system.

Overv commented 3 years ago

@crud89 Assuming that you mean --invert-y, it doesn't seem to make any difference for me.

Overv commented 3 years ago

Going by this article it seems that the solution could be:

crud89 commented 3 years ago

@crud89 Assuming that you mean --invert-y, it doesn't seem to make any difference for me.

glslc --help says it's -finvert-y for me. 🤔

It's weird, that it does not work for you. I tried with both (dxc and glslc) and both fixed the issues. Handedness should not influence the y-coordinate, only the z-coordinate (whether positive or negative is pointing forward).

The tutorial flips the sign of the (V)P1,1 matrix. Ultimately this corresponds to multiplying the VP matrix with a matrix that looks like this:

1  0  0  0
0 -1  0  0 
0  0  1  0
0  0  0  1

This transform does nothing else than inverting the y coordinate of the result, so basically this is the same as using the compiler switch.

The article you linked does two things:

  1. Use LH coordinate system, which flips the z-coordinate. That's why it requires you to swap the cull order (since normals now point in the wrong direction).
  2. Negate the sign of the viewport height. Since viewport transform is just a builtin fragment coordinate transform, this does the same as your current matrix-multiplication... or the compiler switch I mentioned.

So there are many fixes to this issue. I personally prefer using the compiler switches, because it appears to be the most portable solution. I am, however, not sure if it might be an issue with glslc and glsl shaders (since I am using hlsl).

Overv commented 3 years ago

glslc --help says it's -finvert-y for me. 🤔

Ah right, I just noticed that my local compiling script was still using glslangValidator.