【发布时间】:2014-12-21 23:23:16
【问题描述】:
编辑:更新了 JSFiddle 链接,因为它在 Windows 7 上的 Chrome 中无法正确呈现。
上下文
我正在使用 THREE.JS 中的粒子,并使用帧缓冲区/渲染目标(双缓冲)将位置写入纹理。这个贴图受自己的ShaderMaterial影响,然后被PointCloud的ShaderMaterial读取来定位粒子。到目前为止一切都很好;一切都按预期工作。
我现在要做的是使用场景的深度纹理来查看是否有任何粒子与场景的几何体相交。
我做的第一件事是在 PointCloud 的片段着色器中引用我的深度纹理,使用gl_FragCoord.xy / screenResolution.xy 生成我的uv 用于深度纹理查找。
There's a JSFiddle of this here。它运行良好 - 当粒子位于场景中某物的后面时,我会告诉粒子渲染为红色,而不是白色。
当我尝试在位置纹理着色器中进行相同的深度比较时,就会出现我的问题。在绘制片段着色器中,我可以使用gl_FragCoord 的值来获取粒子在屏幕空间中的位置并将其用于深度uv 查找,因为在绘制顶点着色器中我使用modelViewMatrix 和projectionMatrix设置gl_Position的值。
我尝试在位置片段着色器中执行此操作,但无济于事。顺便说一句,我的目标是与 GPU 上的场景发生粒子碰撞。
所以...问题(终于!):
- 给定一个纹理,其中每个像素/纹素都是代表粒子位置的世界空间 3d 矢量,我如何将此矢量投影到片段着色器中的屏幕空间,最终目标是使用
.xy的属性这个向量作为uv在深度纹理中的查找?
我的尝试
-
在位置纹理着色器中,使用与绘图着色器相同的转换,使用模型视图和投影矩阵将粒子的位置转换到(我认为是)屏幕空间:
// Position texture's fragment shader: void main() { vec2 uv = gl_FragCoord.xy / textureResolution.xy; vec4 particlePosition = texture2D( tPosition, uv ); vec2 screenspacePosition = modelViewMatrix * projectionMatrix * vec4( particlePosition, 1.0 ); vec2 depthUV = vec2( screenspacePosition.xy / screenResolution.xy ); float depth = texture2D( tDepth, depthUV ).x; if( depth < screenspacePosition.z ) { // Particle is behind something in the scene, // so do something... } gl_FragColor = vec4( particlePosition.xyz, 1.0 ); } -
以上主题的变奏:
- 通过执行
0.5 - depthUV来抵消深度的uv - 使用 tPosition 纹理分辨率而不是屏幕分辨率来缩放 depthUV。
- 另一个深度
uv变体:做depthUV = (depthUV - 1.0) * 2.0;。这有点帮助,但规模完全没有。
- 通过执行
帮助!并提前致谢。
【问题讨论】:
-
你的深度纹理是否标准化? IE。你应该把
screenspacePosition.z除以screenspacePosition.w吗? -
是的,深度纹理不是问题(IMO)。将深度纹理渲染到屏幕上的四边形会显示应有的一切(灰度,0.0 到 1.0)。
-
快速更新:我认为我的问题在于模型视图和/或投影矩阵被三个传递到位置 FBO/RTT 着色器。手动传递正确的矩阵作为制服似乎有点帮助(即它现在可以正确比较深度,但是当使用粒子位置作为 UV 时深度纹理的比例太小了。嗯!
-
啊哈!我想我已经找到了问题——这与矩阵有关。我将制作一个新的 JSFiddle 并尽可能详细地发布它作为答案,以防万一其他人遇到这个问题......
标签: javascript three.js glsl opengl-es-2.0 webgl