3

我想在 glsl 顶点着色器中的当前顶点位置计算像素投影金字塔的眼睛空间宽度,但我似乎无法正确计算。这是一个明显不正确的例子:

// GLSL VERTEX SHADER
#version 410 compatibility

uniform vec4 viewport; // same as glViewport​
in vec4 gl_Vertex;

void main ()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    float pixelWidth = gl_Position.z / viewport.z;
<snip>

但这并没有考虑 FOV 或剪裁平面。

4

2 回答 2

2

我通过数学计算并弄清楚了。:) 正如我所希望的,不需要额外的矩阵转换,只需要一个除法:

// GLSL VERTEX SHADER
#version 410 compatibility

uniform vec4 viewport; // same as glViewport​
in vec4 gl_Vertex;

float pixelWidthRatio = 2. / (viewport.z * gl_ProjectionMatrix[0][0]);

void main ()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    float pixelWidth = gl_Position.w * pixelWidthRatio;
    <snip>

或者:

<snip>
float pixelHeightRatio = 2. / (viewport.w * gl_ProjectionMatrix[1][1]);

void main ()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    float pixelHeight = gl_Position.w * pixelHeightRatio;
<snip>

正如预期的那样,如果像素是正方形的,则它们是相同的pixelWidthpixelHeight

于 2012-06-11T14:26:45.527 回答
1

顶点着色器中,没有像素的世界空间宽度之类的东西。“宽度”仅在给定的 Z 距离处投影到像素中。通常,您将金字塔投影到像素中。

干得好:

  1. 将两个屏幕点转换为 NDC 点:

        vec2 Screen = vec2( ScreenWidth, ScreenHeight );
        vec3 Point1 = vec3( ScreenPt1 / Screen * 2.0 - vec2( 1.0 ), 1.0 );
        vec3 Point2 = vec3( ScreenPt2 / Screen * 2.0 - vec2( 1.0 ), 1.0 );
    
  2. 将 NDC 点解投影到世界空间位置:

        vec4 R1 = vec4( Point1, 1.0 );
        vec4 R2 = vec4( Point2, 1.0 );
    
        R1 = Projection.GetInversed() * R1;
        R1 = ModelView.GetInversed() * R1;
        R1 /= R1.W;
    
        R2 = Projection.GetInversed() * R2;
        R2 = ModelView.GetInversed() * R2;
        R2 /= R2.W;
    
  3. 求 R1 和 R2 之间的距离。

片段着色器中,您可以使用局部导数。看看这里:

http://www.opengl.org/sdk/docs/manglsl/xhtml/dFdx.xml

和这里:

http://www.opengl.org/sdk/docs/manglsl/xhtml/fwidth.xml

仅在片段着色器中可用,dFdx 和 dFdy 分别返回表达式 p 在 x 和 y 中的偏导数。使用局部差分计算偏差。暗示高阶导数(例如 dFdx(dFdx(n)))的表达式具有未定义的结果,混合阶导数(例如 dFdx(dFdy(n)))也是如此。假设表达式 p 是连续的,因此,通过非均匀控制流评估的表达式可能是未定义的。

于 2012-06-07T18:34:33.850 回答