我想在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或裁剪平面。
答案 0 :(得分: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>
如预期的那样,pixelWidth
和pixelHeight
如果像素为方形,则相同。
答案 1 :(得分:0)
在顶点着色器中,不存在像素的世界空间宽度。 “宽度”仅在给定的Z距离处投影到像素中。通常,您有一个投影到像素中的金字塔。
你走了:
将两个屏幕点转换为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 );
将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;
找出R1和R2之间的距离。
在片段着色器中,您可以使用本地衍生物。看看这里:
http://www.opengl.org/sdk/docs/manglsl/xhtml/dFdx.xml
在这里:
http://www.opengl.org/sdk/docs/manglsl/xhtml/fwidth.xml
仅在片段着色器中可用,dFdx和dFdy分别在x和y中返回表达式p的偏导数。使用局部差分计算偏差。隐含高阶导数的表达式如dFdx(dFdx(n))具有不确定的结果,混合阶导数如dFdx(dFdy(n))也是如此。假设表达式p是连续的,因此,通过非均匀控制流程评估的表达式可能是不确定的。