Flipping the viewport

I’m following Ray Tracing In a Weekend, and would like to implement this in Vulkan. In Chapter one, we iterate through all the fragments and color them. Here is the resulting image from vulkan, versus one made in ShaderToy. Both same fragment shader

And from ShaderToy

As you can see, the image seems to be flipped.

Things that I have tried.
Invert gl_Position.y in fragment shader. No change to output.
Invert viewport.y and submitting vkCmdSetViewport(), no change to output.

What must I be doing wrong? Or is the underlying problem something else? Any input would be appreciated, thank you.

EDIT: The correct output should be the one from ShaderToy.

The straightforward solution would be to simply flip the y-component of your rg-vector.

The more correct way would be flipping the viewport itself by using a negative viewport height. This requires VK_KHR_Maintenance1 (or Vulkan 1.1 upwards). I wrote a bit about using this here.

@Sascha_Willems Thank you for your reply. I have visited your website and attempted that solution. However, the result was the same regardless of those two options that are mentioned there.
This however, fixed the problem, as you’ve recommended.
Error1

I’m very new to this, any ideas as to why this method works and the other ( flipping the viewport ) doesn’t? My only guess, which could be completely wrong, is that even after flipping the viewport, the fragment shader still starts at lower left corner as opposed to upper left? Hence after the viewport flip, the result is the same. Any ideas as to why? I’d love to know the reason. Thank you for your help.

Vulkan semantics GLSL has origin at upper left.

I think the problem is you are using gl_FragCoord, which is the value after the viewport transform.

Greetings,

I decided to use this thread, since my problem is similar:
I’m porting from OpenGL, setting
gl_Position.y = -glPosition.y;
solves my problem.

I also tried the maintenance method by

  • Adding VK_KHR_Maintenance1 to extension list during device creation
  • Setting viewport.y from 0 to WindowHeight and viewport.height to -WindowHeight in VkPipelineViewportStateCreateInfo pViewports during pipeline creation. Also disabled backface culling.

This doesn’t work. Can anyone tell me what might be the issue?
Btw what about the scissor test? Does it also need the inverted window coordinates?

In what way does it “doesn’t work”?

Objects not seen when the manual flip in the shader would show the objects correctly.

Should work…

Do you have validation layers properly enabled, and what do they say?

Do you have appropriate extension or core version for negative height enabled (and the device supports it)?

What other changes did you make? It should not need change in scissor. Unless you have some smarts somewhere, enabling the extension\version and then VK_CULL_MODE_NONE, viewport.y = fb_height, viewport.height = -fb_height is all that is needed.

Make the habit of posting the code and not prose, so I know you did not made a typo or stuff (e.g. it is VK_KHR_maintenance1 not VK_KHR_Maintenance1).

1 Like

Ok, some more info:

  • Switching between Vulkan 1.0 and Vulkan 1.2 will make validation error for viewport height disappear/appear, so I assume with 1.2 the functionality is enabled.

This is the viewport setup for the pipeline:

VkViewport viewport{};
myrenderer::Viewport const & _viewport = stateInfo.get< myrenderer::Viewport >();
viewport.x = static_cast < float > ( _viewport.getX() );
viewport.y = static_cast < float > ( _viewport.getY() );
viewport.width = static_cast < float > ( _viewport.getWidth() );
viewport.height = static_cast < float > ( _viewport.getHeight() );
myrenderer::Depth const & depth = stateInfo.get< myrenderer::Depth >();
viewport.minDepth = depth.getNearRange();
viewport.maxDepth = depth.getFarRange();

with the following values that takes the window extents:

m_Height -800 int
m_Width 1000 int
m_X 0 int
m_Y 800 int

m_DepthRangeFar 1 float
m_DepthRangeNear 0 float

And VK_CULL_MODE_NONE of course.

This will produce a black screen. Using the original viewport (x,y = 0, width = 1000, height = 800) plus gl_Position.y = -glPosition.y; in the shader will show the correct view.

Ok, forget it. My mistake was to use the flipped viewport also for stencil.