ele*_*ect 1 opengl shader view perspective
在这些日子里,我正在阅读Jason L. McKesson撰写的" 学习现代3D图形编程"一书.基本上它是一本关于OpenGL 3.3的书,我现在在第4章,这是关于正交和透视的.
在本章的最后,在"进一步研究"部分,他建议尝试一些事情,比如实现可变眼点(他在相机空间的开头(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;
}
Run Code Online (Sandbox Code Playgroud)
编辑2:谢谢鲍里斯,你的照片帮了很多:)特别是因为:
只是好奇心,你为什么提到减去后乘以?这本书是否出于同样的原因,那就是宽高比?因为逻辑上所有东西都让我完全相反,那就是第一次翻译(-2)然后乘法(/ 5)..或者也许用"缩放"一词,本书指的是重塑功能?
在这里,我们感兴趣的是计算从摄像机坐标(CC)到标准化设备坐标(NDC)的转换.
将其E视为相机坐标中投影平面的位置,而不是根据投影平面的眼点位置.在摄像机坐标中,根据定义,眼点位于原点,至少在我对"摄像机坐标"的含义的解释中:一个坐标框架,从您观察场景的位置开始.(您可以在数学上定义一个以任何地方为中心的透视变换,但这意味着您的输入空间不是摄像机空间,imho.这就是World-> Camera变换的用途,正如您将在第6章中看到的那样)
摘要:
这是这里的图片(每个刻度是0.5单位):

在这张图片中,您可以看到投影平面(灰色梯形的底边)以(0,0,-1)为中心,在X和Y方向都有[-1,1]的大小.
现在,问的不是选择(0,0,-1)这个平面的中心,而是选择任意(Ex,Ey,Ez)位置(假设Ez为负).但是该平面仍然与xOy轴平行并且具有相同的尺寸.
您可以看到,尺寸E.xy与Ez的作用非常不同,因为E.xy将参与减法,而Ez将参与分裂.通过示例很容易看到:
它在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和两个可能的投影平面.在蓝色的解释和着色器中使用的这里,和红色的是你现在要使用的一个.彩色区域对应于最终屏幕中应该可见的内容,例如NDC空间中立方体[-1,1] ^ 3中的内容.因此,如果使用蓝色投影平面,则需要获取右上角的空间,如果使用红色投影平面,则需要在底部获取空间.为此,您可以观察到需要在NDC空间中执行缩放和平移,例如在透视分割之后!(我认为书中所写的内容不正确,或以不同的方式解释问题).
因此,您希望以欧几里德坐标(即不是齐次坐标,例如没有W坐标)来做:
clipPosEuclideanRed.xy = clipPosEuclideanBlue.xy * (-E.z) - E.xy;
clipPosEuclideanRed.z = clipPosEuclideanBlue.z;
Run Code Online (Sandbox Code Playgroud)
但是,因为您处于齐次坐标中,所以这个值实际上是:
clipPosEuclidean.xyz = clipPos.xyz / clipPos.w; // with clipPos.w = -cameraPos.z;
Run Code Online (Sandbox Code Playgroud)
因此,你必须写作:
clipPosRed.xy = clipPosBlue.xy * (-E.z) - E.xy * (-cameraPos.z);
clipPosRed.z = clipPosBlue.z;
Run Code Online (Sandbox Code Playgroud)
所以我对这个问题的解决方案是只添加一行:
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;
}
Run Code Online (Sandbox Code Playgroud)