在这些日子里,我正在阅读Jason L. McKesson撰写的Learning Modern 3D Graphics Programming书。基本上它是一本关于OpenGL 3.3的书,我现在在chapter 4,这是关于正交和透视的。
在本章的最后,在"Further Study"部分下,他建议尝试一些诸如实现可变眼点(他在相机空间的开头(0,0,0)使用以获得简洁性)和任意透视平面位置。 他说我需要分别用E_x和E_y来偏移顶点的X,Y相机空间位置。
我无法理解这段话,我怎么能使用可变眼点仅修改X,Y偏移?
编辑:可能是这样的吗?
#version 330
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 color;
smooth out vec4 theColor;
uniform vec2 offset;
uniform vec2 E;
uniform float zNear;
uniform float zFar;
uniform float frustumScale;
void main()
{
vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0);
vec4 clipPos;
clipPos.xy = cameraPos.xy * frustumScale + vec4(E.x, E.y, 0.0, 0.0);
clipPos.z = cameraPos.z * (zNear + zFar) / (zNear - zFar);
clipPos.z += 2 * zNear * zFar / (zNear - zFar);
clipPos.w = cameraPos.z / (-E.z);
gl_Position = clipPos;
theColor = color;
}
Edit2:谢谢鲍里斯,你的照片帮了很多:)特别是因为:
只是好奇心,为什么你在减去之后提到乘法?这本书是否出于同样的原因,那就是宽高比?因为逻辑上所有东西都让我完全相反,那就是第一次翻译(-2)然后乘法(/ 5)..或者也许用“缩放”这个术语,本书指的是重塑函数?
答案 0 :(得分:5)
在这里,我们感兴趣的是计算从相机坐标(CC)到标准化设备坐标(NDC)的转换。
将E
视为相机坐标中投影平面的位置,而不是根据投影平面的眼点位置。在相机坐标系中,根据定义,眼点位于原点,至少在我对“摄像机坐标”的解释中是什么?表示:以您查看场景的位置为中心的坐标框架。 (你可以在数学上定义一个以任何地方为中心的透视变换,但这意味着你的输入空间不是摄像机空间,imho。这就是World-> Camera变换的用途,正如你将在chapter 6中看到的那样)
要点:
这是这里的图片(每个刻度是0.5单位):
在这张图片中,您可以看到投影平面(灰色梯形的底边)以(0,0,-1)为中心,X和Y方向的尺寸均为[-1,1]
现在,问的是,不是选择(0,0,-1)这个平面的中心,而是选择任意(E.x,E.y,E.z)位置(假设E.z为负)。但是这个平面仍然要与xOy轴平行且尺寸相同。
你可以看到,尺寸E.xy与E.z的作用非常不同,因为E.xy将参与减法,而E.z将参与分裂。通过示例很容易看到:
它在NDC空间的坐标是什么?根据定义,它是(0,0,-1)。你所做的是减去E.xy,但除以-E_z。
你的代码有了这个想法,但仍有一些问题:
uniform vec2 E;
而不是uniform vec3 E;
(只是一个错字,不是什么大问题)clipPos.xy = ... ;
行约为vec2
算术。因此,您只能乘以标量值(即浮点数)或加/减vec2
值。因此,vec4(E.x, E.y, 0.0, 0.0)
的类型不正确,您应该改为使用E.xy
,其类型vec2
正确。E.xy
而不是添加它。这在上面的示例中很容易看到。我拍了一张照片来说明修改:
此图片中的每个刻度为1个单位。左上角是您的相机坐标空间,显示zNear,zFar和两个可能的投影平面。蓝色是解释和着色器here中使用的蓝色,红色是您现在要使用的那个。彩色区域对应于最终屏幕中应该可见的内容,例如什么应该在NDC空间的立方体[-1,1] ^ 3中。因此,如果使用蓝色投影平面,则需要获取右上角的空间,如果使用红色投影平面,则需要在底部获取空间。为此,您可以观察到需要在NDC空间中执行缩放和转换,例如:透视师之后! (我认为书中所写的内容不正确,或以不同方式解释问题)。
因此你想要用欧几里德坐标(即不是齐次坐标,例如没有W坐标):
clipPosEuclideanRed.xy = clipPosEuclideanBlue.xy * (-E.z) - E.xy;
clipPosEuclideanRed.z = clipPosEuclideanBlue.z;
但是,因为你是齐次坐标,所以这个值实际上是:
clipPosEuclidean.xyz = clipPos.xyz / clipPos.w; // with clipPos.w = -cameraPos.z;
因此,你必须写作:
clipPosRed.xy = clipPosBlue.xy * (-E.z) - E.xy * (-cameraPos.z);
clipPosRed.z = clipPosBlue.z;
所以我对这个问题的解决办法就是只添加一行:
void main()
{
vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0);
vec4 clipPos;
clipPos.xy = cameraPos.xy * frustumScale;
// only add this line
clipPos.xy = - clipPos.xy * E.z + E.xy * cameraPos.z;
clipPos.z = cameraPos.z * (zNear + zFar) / (zNear - zFar);
clipPos.z += 2 * zNear * zFar / (zNear - zFar);
clipPos.w = -cameraPos.z;
gl_Position = clipPos;
theColor = color;
}