glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
The position is transformed by the modelview matrix when glLight is called (just as if it were a point), and it is stored in eye coordinates.
如上,传入的光位置参数是定义在模型坐标系下的,但被保存在镜头空间中(即固定管线将其视为镜头坐标系下的语义使用).且除非再次指定,该值不变,即相当于光的位置相对镜头固定.这通常不是我们想要的,通常光应该相对世界固定(如DirectX).所以需要在每次变更ModelViewMatrix后再次设置光的位置,以表明其相对世界固定.
glClipPlane:
When you call glClipPlane, equation is transformed by the inverse of the modelview matrix and stored in the resulting eye coordinates. Subsequent changes to the modelview matrix have no effect on the stored plane-equation components.
即不同于glLightfv, glClipPlane指定的平面公式参数受到当前ModelViewMatrix逆矩阵的影响(没想到吧),实际存储的数值为: 传入的平面公式参数四元组 P 乘以 (ModelViewMatrix ^ -1). 需要特别指出的是,这里的计算是P * M,而不是OpenGL习惯的M * V.
glTexGenfv:
与glClipPlane相同,GL_EYE_LINEAR模式下的纹理坐标自动生成,参数指定的平面公式系数4元组,受到当前ModelViewMatrix逆矩阵影响后存储在镜头空间,即: P * (ModelViewMatrix ^ -1)。但GL_OBJECT_LINEAR没有这种特性。
推论:
1.分别为(s,t,r,q)这4个纹理坐标分量定义一个平面公式,实际上可以理解为定义了一个纹理坐标转换矩阵Ma,这个Ma与纹理变换矩阵glMatrixMode(GL_TEXTURE)机制是相互独立的,也就是说纹理坐标自动生成机制可以提供一个额外的纹理变换矩阵. 通过glTexGenfv(GL_x, GL_EYE_PLANE, ...)可以指定矩阵的4个行向量,记这个矩阵为Ma.
2.平面公式定义下的纹理坐标自动生成可以总结为 M * V.
3.在GL_OBJECT_LINERAR模式下, V是模型坐标系的坐标, M等于Ma.
4.在GL_EYE_LINEAR模式下就复杂多了,glTexGeni(GL_X, GL_TEXTURE_GEN_MODE, GL_EYE_LINERE)负责直接获得镜头空间的坐标值,但是得到后要先乘以使用glTexGenfv(GL_X, GL_EYE_PLANE, m)指定的平面方程(STRQ这4个平面方程组合相当于一个4x4矩阵),再乘以当前ModelViewMatrix的逆矩阵,即设V是取得的镜头坐标系下的坐标,M = Ma * (ModelViewMatrix ^ -1).其中ModelViewMatrix是执行glTexGenfv时的ModelViewMatrix.Ma是平面方程组合矩阵,纹理坐标总公式为:
Vtex = Ma * (ModelViewMatrix1 ^ -1) * TextureMatrix * ModelViewMatrix2 * Vobject
其中: Ma是glTexGenfv(GL_x, GL_EYE_PLANE, ...)定义的平面公式矩阵
ModelViewMatrix1是指定glTexGenfv时的ModelViewMatrix,为了得到视图矩阵的逆矩阵,我们总是应该在当前只指定了gluLookAt的时候调用glTexGenfv.
ModelViewMatrix2是实际渲染时的ModelViewMatrix
TextureMatrix是纹理矩阵
Voject是模型顶点坐标.
5.假设当前Batch渲染时的ModelViewMatrix等于glTexGenfv指定时的ModelViewMatrix,且没有TextureMatrix作用,依矩阵乘法结合率,则有 Vtex = Ma * Vobject,等同与GL_OBJECT_LINERAR模式.这就是为什么有的时候GL_EYE_LINEAR和GL_OBJECT_LINEAR的图像没有差别的原因.
6.假设当前Batch渲染时的ModelViewMatrix不等于glTexGenfv指定时的ModelViewMatrix,通常的技巧设置glTexGenfv指定时的ModelViewMatrix为纯ViewMatrix(即用gluLookAt指定),随后镜头不再变换,ModelViewMatrix仅追加ModelMatrix变换,ViewMatrix不变,即有:
Vtex = Ma * (ViewMatrix ^ -1) * ModelViewMatrix * Vobject = Ma * (ViewMatrix ^ -1) * Veye = Ma * Vworld
就是说Ma神奇地作用到了物体的世界坐标上了,这就是Project Texture, Shadow Map使用固定管线渲染时大量应用的技巧.
Shader编程大大降低了一些图形学技巧的复杂性,但我坚持要知其然,知其所以然.