python - 使用延迟屏幕空间贴花系统的边界检查问题
问题描述
在一篇名为“使用延迟屏幕空间贴花在其他东西上绘制东西”的文章之后,我正在尝试使用 OpenGL 实现延迟屏幕空间贴花系统,链接:http ://martindevans.me/game-development/2015/02/27/Drawing- Stuff-On-Other-Stuff-With-Deferred-Screenspace-Decals/。
一个红色阴影立方体被绘制在场景的顶部,该立方体与深度掩码设置为 false 的墙相一致。图片链接(无界立方体):https ://gyazo.com/8487947bd4afb08d8d0431551057ad6f
墙的深度缓冲区和一些顶点着色器输出用于计算立方体尺寸内墙的对象空间位置。边界检查确保立方体的每个像素在墙的对象空间位置之外是丢弃。
问题是边界没有正常工作,立方体完全消失了。
潜在故障
我已经通过在 lighitingpass 中可视化它来检查深度缓冲区是否正常工作,它似乎工作正常。深度缓冲区存储在 gbuffer 中的颜色附件中,浮动大小为 GL_RGB32F。图片链接(远处墙的Ligtingpass depthbuffer可视化):https ://gyazo.com/69920a532ca27aa9f57478cb57e0c84c
贴花着色器代码
顶点着色器
// Vertex positions
vec4 InputPosition = vec4(aPos, 1);
// Viewspace Position
PositionVS = view* model* InputPosition;
// Clipspace Position
PositionCS = projection*PositionVS;
gl_Position = PositionCS;
片段着色器
// Position on the screen
vec2 screenPos = PositionCS.xy / PositionCS.w;
// Convert into a texture coordinate
vec2 texCoord = vec2((1 + screenPos.x) / 2 + (0.5 / resolution.x), (1 -
screenPos.y) / 2 + (0.5 / resolution.y));
// Sampled value from depth buffer
vec4 sampledDepth = texture(gDepth, texCoord);
// View-direction
vec3 viewRay = PositionVS.xyz * (farClip / -PositionVS.z);
// Wallposition in view-space
vec3 viewPosition = viewRay*sampledDepth.z;
// Transformation from view-space to world-space
vec3 WorldPos = (invView*vec4(viewPosition, 1)).xyz;
// Transformation from world-space to object-space
vec3 objectPosition = (invModel*vec4(WorldPos, 1)).xyz;
// Bounds check, discard pixels outside the wall in object-space
if (abs(objectPosition.x) > 0.5) discard;
else if (abs(objectPosition.y) > 0.5) discard;
else if (abs(objectPosition.z) > 0.5) discard;
// Color to Gbuffer
gAlbedoSpec = vec4(1, 0, 0, 1);
代码说明
invView 和 invModel 分别是视图和模型的反面。矩阵逆计算在 CPU 中完成,并作为统一发送到片段着色器。farClip 是到相机远平面的距离(此处设置为 3000)。gDepth 是 Gbuffer 的深度纹理。
问题
与立方体一致的墙壁部分应该是红色的,如下图所示,显然不是。
图片链接(带边界的立方体):https ://gyazo.com/ab6d0db2483a969db932d2480a5acd08
我的猜测是问题是如何将视图空间位置转换为对象空间位置,但我无法弄清楚!
解决方案
你混淆了粉笔和奶酪。PositionCS
是剪辑空间位置,可以通过透视除法转换为标准化设备空间位置:
vec2 ndcPos = PositionCS.xyz / PositionCS.w;
sampledDepth
是一个深度值(默认在 [0, 1] 范围内),可以通过从深度缓冲区纹理中读取“红色”颜色通道 ( .r
, ) 来获取。.x
深度可以通过以下方式转换为归一化的设备空间 Z 坐标depth*2.0-1.0
:
vec2 texCoord = ndcPos.xy * 0.5 + 0.5;
// (+ 0.5/resolution.xy;) is not necessary if texture filter is GL_NEAREST
float sampledDepth = texture(gDepth, texCoord).x;
float sampleNdcZ = sampledDepth * 2.0 - 1.0;
在透视投影和标准化设备空间中,具有相同 x 和 y 坐标的所有点都在同一条射线上,该射线从视图位置开始。
这意味着如果深度缓冲区是使用与( )gDepth
相同的视图矩阵和投影矩阵生成的,则您可以用深度缓冲区 ( ) 中的相应 NDC z 坐标替换,并且该点仍然在同一视图射线上。并且是同一参考系统中的可比较值。ndcPos
PositionCS
ndcPos.z
sampleNdcZ
ndcPos.z
sampleNdcZ
vec3 ndcSample = vec3(ndcPos.xy, sampleNdcZ);
该坐标可以通过逆投影矩阵和透视划分转换为视图空间坐标。
如果 NDC 点,在同一条视图射线上,被转换到视图空间,那么 XY 坐标将是不同的。* 1/.w
请注意,由于 ( ) ,变换不是线性的。另请参见OpenGL-鼠标坐标到空间坐标。
uniform mat4 invProj; // = inverse(projection)
vec4 hViewPos = invProj * vec4(ndcSample, 1.0);
vec3 viewPosition = hViewPos.xyz / hViewPos.w;
这可以通过逆视图矩阵到世界空间和逆模型矩阵到对象空间进一步转换:
vec3 WorldPos = (invView * vec4(viewPosition, 1.0)).xyz;
vec3 objectPosition = (invModel * vec4(WorldPos, 1.0)).xyz;
推荐阅读
- php - PHP 比较小于一
- batch-file - &此时出乎意料
- r - R中Rainfall栅格的Mannkendall趋势分析及其解释
- javascript - JavaScript 只调用标头
- ibm-cloud - 如何将 IBM Watson Assistant 聊天机器人嵌入另一个 HTML 页面
- apache-spark - Spark SQL 中的 Sort by 与数据集 API 的排序与 Spark SQL 中的 Order by 有什么区别?
- word2vec - word2vec 词汇表中缺少单词
- xamarin - 使用 IdentityServer4 和 Xamarin Android 使用资源所有者密码进行脱机访问和刷新令牌
- sql - 从日期 SQL 返回按年和月分组的所有行
- python - 在 Python-Django 项目中将 XML 值呈现为 HTML