【问题标题】:Shader - Calculate depth relative to Object着色器 - 计算相对于对象的深度
【发布时间】:2014-10-15 14:44:14
【问题描述】:

我正在尝试计算相对于 objectdepth
这是检索相对于 depth 的好方法>相机Depth as distance to camera plane in GLSL

varying float distToCamera;

void main()
{
    vec4 cs_position = glModelViewMatrix * gl_Vertex;
    distToCamera = -cs_position.z;
    gl_Position = gl_ProjectionMatrix * cs_position;
}

在此示例中,深度是相对于相机
但我想获得相对于对象的深度。如果我离物体很近或很远,我想要相同的深度和价值。

这是我想要实现的一个示例。在左侧,您可以看到深度是相对于相机的。而在右侧,即使相机从物体移回,深度也保持不变,因为它取决于物体。

【问题讨论】:

  • 非常模糊,我得到的印象是你真正想到的是线性深度。精度分布不随距离变化的地方。您可以非常简单地线性化透视深度缓冲区,或者像多年前在透视 Z 缓冲成为事实上的标准之前所做的那样使用 w 坐标。
  • 这个公式很奇怪——“如果我离物体近或远,深度和值相同”——听起来像是一个常数值。也许如果你写了你需要它做什么。顺便说一句,您不需要分离 MVP 和投影矩阵 - gl_Position.w 最终包含来自相机的深度。
  • 很抱歉,如果配方完全错误地陈述。我制作了一个小 gif 来说明我想要实现的目标。

标签: opengl directx glsl shader hlsl


【解决方案1】:

片段到相机的距离总是依赖相机的位置。如果 value 不是常数,则不可能使 value 成为常数。

我建议您重新制定您正在开发的要求。您必须自己弄清楚您需要什么深度,它似乎不依赖于相机位置。

我建议您考虑引入一个平面,这将作为计算深度的参考。参数,指定平面在空间中的位置可以作为制服传递给着色器。

如何计算一个点到平原的距离?深度可以计算为从片段掉落的垂直于平面的长度。让我们有一个位于平面上的任意点 p 和该平面的法线 n。 距离是:

d = 点(f, n) - 点(p, n)

where f - 片段的位置。

下面列出了执行此计算的简单着色器:

uniform vec3 u_point;    
uniform vec3 u_normal;    
uniform float u_unitLength;

varying vec4 v_worldPosition;   

void main( void ) 
{        
    float refPoint = dot(u_point, u_normal);
    float testPoint = dot(v_worldPosition.xyz, u_normal);
    float depth = testPoint - refPoint;
    vec3 color = vec3(depth / u_unitLength);
    gl_FragColor = vec4( color, 1.0 );
}

您应该知道,您需要将片段位置的变化 v_worldPosition 从顶点着色器传递到片段着色器。我写了一个简单的example 进行演示。

可以进行一些优化。您可以不在着色器中执行 dot(p, n),而是预先计算它。更多详情请阅读this

因此,最好以一般形式传递平面方程的系数,而不是以点法线形式传递。优化的着色器将是:

uniform vec4 u_abcd;
uniform float u_unitLength;

varying vec4 v_worldPosition;   

void main( void ) 
{        
    float depth = dot(u_abcd.xyz, v_worldPosition.xyz) + u_abcd.w;
    vec3 color = vec3(depth / u_unitLength);
    gl_FragColor = vec4( color, 1.0 );
}

使用优化着色器的example

您可以使用相机旋转平面,但要使其与物体的距离保持不变。有一个example。结果与您在 gif 动画中演示的一样。

【讨论】:

  • 感谢您非常详细的回答!
  • 我喜欢平面的想法,不幸的是你正在改变制服而不是在着色器中。是否可以根据着色器内部的相机调整正常值?
【解决方案2】:

我相信您所追求的是相对于对象的深度,而不是相机。要找到距物体原点的眼睛空间 Z 距离...

vec4 esVert = glModelViewMatrix * gl_Vertex;
vec4 esObjOrigin = glModelViewMatrix * vec4(0,0,0,1);
distToCamera = -esVert.z;
distToOrigin = -esObjOrigin.z;
originToVertexZ = distToOrigin - distToCamera;

现在,originToVertexZ 是相对于对象的位置而不是相机,因此除非您旋转相机,否则它不会改变。

可以预先计算并传入眼睛空间原点距离esObjOrigin.z(避免额外的矩阵相乘)。 IE。在应用程序代码中计算-(glModelViewMatrix * vec4(0,0,0,1)).z,并将其作为统一变量传入。

根据应用程序,您可能希望预先计算一个边界球体,为originToVertexZ 提供一个已知的上限和下限。例如,如果您总是想要示例中显示的平滑的零到一转换,请找到 bounds=max(length(vertex)) for each vertex in the object,然后找到 normalizedZ = 0.5*originToVertexZ/bounds+0.5

【讨论】:

  • 这正是我想要的,非常感谢。但你能详细说明一下吗? 可以预先计算并传入眼睛空间原点 esObjOrigin.z。根据应用程序,您可能希望预先计算边界球体,为 originToVertexZ 提供已知的上限和下限。
  • 感谢您的解释!
  • @MaT:请更新您的问题以澄清问题。正如它现在所写的那样,它提出了一个不同的问题,你接受的是“这正是我想要的”。
  • @KromStern 我同意这种情况,但有时留下措辞奇怪的问题可以帮助不知道要搜索的确切术语的其他人。
  • @jozxyqk:对于 OP,它与术语无关(实际上可以用更常用的词来表达)。 OP 描述非常模糊和误导。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 2016-11-27
  • 2014-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多