来自规范:
VK_KHR_maintenance1
允许在slink :: VkViewport :: height字段中指定负高度以执行y的反转 clip-space to framebuffer-space transform。这允许应用程序避免 必须在着色器中使用gl_Position.y = -gl_Position.y 其他API。
我的物理设备支持版本1.0.42
,我启用了VK_KHR_maintenance1
。
当我在VkViewport
结构中执行负高度时,我没有得到任何验证错误/警告。
vkCmdSetViewport(vkContext.commandBuffer, 0, 1, &viewport);
但是我在屏幕上看不到任何内容,它是黑色的,如果我删除viewport
中的负值,则所有内容都按预期呈现。我是否需要执行其他操作才能使用VK_KHR_maintenance1 extension
翻转视口?我只是在屏幕上渲染一个红色四边形,带有全屏视口。
VkViewport viewport = {};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = 1024.0f;
viewport.height = -1024.0f;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(vkContext.commandBuffer, 0, 1, &viewport);
顶点着色器:
void main() {
vec4 positions[3] = {
vec4(-1.0, -1.0, 0.0, 1.0),
vec4(3.0, -1.0, 0.0, 1.0),
vec4(-1.0, 3.0, 0.0, 1.0)
};
gl_Position = positions[gl_VertexIndex % 3];
}
片段着色器:
void main() {
outFragColor = vec4(1,0,0,1);
}
答案 0 :(得分:10)
完成数学考试。您拥有所有数字,并且规范明确规定了所有数字。
帧缓冲空间顶点坐标的Y分量的等式是:
Yf = (Py / 2) Yd + Oy
Oy = viewport.y + viewport.height / 2.0
Py = viewport.y
其中Yf
是帧缓冲空间Y分量,Yd
是NDC空间Y分量。
如果你插入1024的正height
,你会得到什么数字?如果Yd
为-1,则Yf
为0.0。如果Yd
为3,则得到Yf
的2048。
在Vulkan中,“自然”视口变换通过在viewport.x/y
处设置-1,在viewport.width/height
处设置1来映射NDC空间。请记住:Vulkan的图像具有左上角的原点,正值向下和向右。因此0.0的Yf
位于顶部,而2048的Yf
位于屏幕底部。因此,三角形(部分)位于视口的可见区域中。
鉴于此,当您使用否定height
时会发生什么?数学不会改变;只是结果。对于Yd
的-1,您得到的Yf
为0.0,与之前非常相似。如果Yd
为3,则得到Yf
的-2048。
这是什么样的?那么,视口的含义没有改变;只是数字。这意味着帧缓冲区图像的可见区域仍位于左上方,向下。因此,值为-2048 高于视口。
简而言之,负高度会翻转视口。但是它会在视口原点处翻转,而不是在屏幕的中心。视口原点位于左上方和右上方。因此,翻转它将翻转之前在屏幕上可见的所有内容。您现在正在查看屏幕的不同区域,在您的情况下是空白区域。
如果要围绕视口的 center 翻转所有内容,则需要调整viewport.y
以补偿负高度。具体来说,它需要是正高度。