VulkanTutorial
VulkanTutorial copied to clipboard
GLM_FORCE_LEFT_HANDED
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".
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
Found the explanation: https://github.com/Overv/VulkanTutorial/blob/master/en/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md near the end
Exactly. That's what the left hand macro is for.
https://chromium.googlesource.com/external/github.com/g-truc/glm/+/HEAD/manual.md#section2_16
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
.
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.
The proper import of the object model and its proper alignment along Vulkan coordinates probably warrants a separate chapter.
The model was exported with positive Y coordinates meaning up, so that would be the convention for the view transform in this case.
The proper fix to this issue is not to do this at run-time, but instead using a compiler switch for the shaders:
-
-finvert-y
for glslc -
-fvk-invert-y
for dxc
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.
@crud89 Assuming that you mean --invert-y
, it doesn't seem to make any difference for me.
Going by this article it seems that the solution could be:
- Tell GLM to use a left-hand coordinate system:
#define GLM_FORCE_LEFT_HANDED
- Flip the viewport upside down:
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = (float)swapChainExtent.height;
viewport.width = (float)swapChainExtent.width;
viewport.height = -(float)swapChainExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
- Fix the
frontFace
:
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
@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:
- 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).
- 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).
glslc --help
says it's-finvert-y
for me. 🤔
Ah right, I just noticed that my local compiling script was still using glslangValidator
.