在 Vulkan 中翻转视口
Flipping the viewport in Vulkan
来自规范:
VK_KHR_maintenance1
Allow negative height to be specified in the slink::VkViewport::height field to perform y-inversion of the
clip-space to framebuffer-space transform. This allows apps to avoid
having to use gl_Position.y = -gl_Position.y in shaders also targeting
other APIs.
我的物理设备支持版本 1.0.42
,并且我已启用 VK_KHR_maintenance1
。
当我在 VkViewport
结构中执行负高度时,我没有得到任何验证 error/warning。
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);
}
只需完成数学运算即可。您拥有所有数字,并且规范明确列出了所有数字。
帧缓冲区 Y 分量的方程式-space 顶点坐标为:
Yf = (Py / 2) Yd + Oy
Oy = viewport.y + viewport.height / 2.0
Py = viewport.height
其中 Yf
是帧缓冲区-space Y 分量,Yd
是 NDC-space Y 分量。
如果你输入 1024 的正数 height
,你会得到什么数字?对于 -1 的 Yd
,您会得到 0.0 的 Yf
。对于 3 的 Yd
,你得到 2048 的 Yf
。
在 Vulkan 中,“自然”视口变换映射 NDC-space,方法是将 -1 置于 viewport.x/y
,将 1 置于 viewport.width/height
。请记住:Vulkan 的图像从左上角开始,正值向下和向右。所以0.0的Yf
在最上面,2048的Yf
在屏幕底部。因此,三角形(部分)在视口的可见区域。
鉴于此,当您使用负数 height
时会发生什么?数学没有改变;只是结果。对于 -1 的 Yd
,您会得到 0.0 的 Yf
,就像以前一样。对于 3 的 Yd
,您得到 -2048 的 Yf
。
那看起来像什么?好吧,视口的含义没有改变;只是数字。这意味着帧缓冲区图像的可见区域仍然在左上角,向下。因此,-2048 的值 高于 视口。
简而言之,负高度会翻转视口。但这会在 视口原点 处翻转它,而不是在屏幕中心。视口原点位于左上角,向下和向右。因此,翻转它会将之前在屏幕上可见的所有内容都翻转掉。您现在正在查看屏幕的不同区域,在您的情况下该区域是空白的。
如果您想翻转视口 center 周围的所有内容,则需要调整 viewport.y
以补偿负高度。具体需要为正高度。
来自规范:
VK_KHR_maintenance1
Allow negative height to be specified in the slink::VkViewport::height field to perform y-inversion of the clip-space to framebuffer-space transform. This allows apps to avoid having to use gl_Position.y = -gl_Position.y in shaders also targeting other APIs.
我的物理设备支持版本 1.0.42
,并且我已启用 VK_KHR_maintenance1
。
当我在 VkViewport
结构中执行负高度时,我没有得到任何验证 error/warning。
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);
}
只需完成数学运算即可。您拥有所有数字,并且规范明确列出了所有数字。
帧缓冲区 Y 分量的方程式-space 顶点坐标为:
Yf = (Py / 2) Yd + Oy
Oy = viewport.y + viewport.height / 2.0
Py = viewport.height
其中 Yf
是帧缓冲区-space Y 分量,Yd
是 NDC-space Y 分量。
如果你输入 1024 的正数 height
,你会得到什么数字?对于 -1 的 Yd
,您会得到 0.0 的 Yf
。对于 3 的 Yd
,你得到 2048 的 Yf
。
在 Vulkan 中,“自然”视口变换映射 NDC-space,方法是将 -1 置于 viewport.x/y
,将 1 置于 viewport.width/height
。请记住:Vulkan 的图像从左上角开始,正值向下和向右。所以0.0的Yf
在最上面,2048的Yf
在屏幕底部。因此,三角形(部分)在视口的可见区域。
鉴于此,当您使用负数 height
时会发生什么?数学没有改变;只是结果。对于 -1 的 Yd
,您会得到 0.0 的 Yf
,就像以前一样。对于 3 的 Yd
,您得到 -2048 的 Yf
。
那看起来像什么?好吧,视口的含义没有改变;只是数字。这意味着帧缓冲区图像的可见区域仍然在左上角,向下。因此,-2048 的值 高于 视口。
简而言之,负高度会翻转视口。但这会在 视口原点 处翻转它,而不是在屏幕中心。视口原点位于左上角,向下和向右。因此,翻转它会将之前在屏幕上可见的所有内容都翻转掉。您现在正在查看屏幕的不同区域,在您的情况下该区域是空白的。
如果您想翻转视口 center 周围的所有内容,则需要调整 viewport.y
以补偿负高度。具体需要为正高度。