纹理投影流程
cg toolkit中关于纹理投影的例子
一 主程序中执行的空间变换
二 shader执行的render pipe处理
1 建立视点矩阵
eyePosition[3];//观察视点位置
lightPosition[3];//光源位置,或投影视点位置
center[3];//投影中心,是地形或模型上的一点
up[3];上向量方向,一般为Y轴正方向
buildLookAtMatrix(eyePosition[0], eyePosition[1], eyePosition[2], center[0], center[1], center[2], up[0], up[1], up[2], eyeViewMatrix); buildLookAtMatrix(lightPosition[0], lightPosition[1], lightPosition[2], center[0], center[1], center[2], up[0], -up[1], up[2], /* Flip up for projected texture's view */ lightViewMatrix);
//buildLookAtMatrix实现
/* Build a row-major (C-style) 4x4 matrix transform based on the parameters for gluLookAt. */ static void buildLookAtMatrix(double eyex, double eyey, double eyez, double centerx, double centery, double centerz, double upx, double upy, double upz, float m[16]) { double x[3], y[3], z[3], mag; /* Difference eye and center vectors to make Z vector. */ z[0] = eyex - centerx; z[1] = eyey - centery; z[2] = eyez - centerz; /* Normalize Z. */ mag = sqrt(z[0]*z[0] + z[1]*z[1] + z[2]*z[2]); if (mag) { z[0] /= mag; z[1] /= mag; z[2] /= mag; } /* Up vector makes Y vector. */ y[0] = upx; y[1] = upy; y[2] = upz; /* X vector = Y cross Z. */ x[0] = y[1]*z[2] - y[2]*z[1]; x[1] = -y[0]*z[2] + y[2]*z[0]; x[2] = y[0]*z[1] - y[1]*z[0]; /* Recompute Y = Z cross X. */ y[0] = z[1]*x[2] - z[2]*x[1]; y[1] = -z[0]*x[2] + z[2]*x[0]; y[2] = z[0]*x[1] - z[1]*x[0]; /* Normalize X. */ mag = sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); if (mag) { x[0] /= mag; x[1] /= mag; x[2] /= mag; } /* Normalize Y. */ mag = sqrt(y[0]*y[0] + y[1]*y[1] + y[2]*y[2]); if (mag) { y[0] /= mag; y[1] /= mag; y[2] /= mag; } /* Build resulting view matrix. */ m[0*4+0] = x[0]; m[0*4+1] = x[1]; m[0*4+2] = x[2]; m[0*4+3] = -x[0]*eyex + -x[1]*eyey + -x[2]*eyez; m[1*4+0] = y[0]; m[1*4+1] = y[1]; m[1*4+2] = y[2]; m[1*4+3] = -y[0]*eyex + -y[1]*eyey + -y[2]*eyez; m[2*4+0] = z[0]; m[2*4+1] = z[1]; m[2*4+2] = z[2]; m[2*4+3] = -z[0]*eyex + -z[1]*eyey + -z[2]*eyez; m[3*4+0] = 0.0; m[3*4+1] = 0.0; m[3*4+2] = 0.0; m[3*4+3] = 1.0; }
2 创建模型矩阵modelMatrix
/* modelView = rotateMatrix * translateMatrix */ makeRotateMatrix(70, 1, 1, 1, rotateMatrix); makeTranslateMatrix(2, 0, 0, translateMatrix); multMatrix(modelMatrix, translateMatrix, rotateMatrix);
Opengl中设置模型方位和位置.Ogre中自己获取参数.该矩阵即model到世界空间的变换矩阵.
//makeRotateMatrix实现
/* Build a row-major (C-style) 4x4 matrix transform based on the parameters for glRotatef. */ static void makeRotateMatrix(float angle, float ax, float ay, float az, float m[16]) { float radians, sine, cosine, ab, bc, ca, tx, ty, tz; float axis[3]; axis[0] = ax; axis[1] = ay; axis[2] = az; normalizeVector(axis); radians = angle * myPi / 180.0; sine = sin(radians); cosine = cos(radians); ab = axis[0] * axis[1] * (1 - cosine); bc = axis[1] * axis[2] * (1 - cosine); ca = axis[2] * axis[0] * (1 - cosine); tx = axis[0] * axis[0]; ty = axis[1] * axis[1]; tz = axis[2] * axis[2]; m[0] = tx + cosine * (1 - tx); m[1] = ab + axis[2] * sine; m[2] = ca - axis[1] * sine; m[3] = 0.0f; m[4] = ab - axis[2] * sine; m[5] = ty + cosine * (1 - ty); m[6] = bc + axis[0] * sine; m[7] = 0.0f; m[8] = ca + axis[1] * sine; m[9] = bc - axis[0] * sine; m[10] = tz + cosine * (1 - tz); m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; }
//makeTranslateMatrix实现
/* Build a row-major (C-style) 4x4 matrix transform based on the parameters for glTranslatef. */ static void makeTranslateMatrix(float x, float y, float z, float m[16]) { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = x; m[4] = 0; m[5] = 1; m[6] = 0; m[7] = y; m[8] = 0; m[9] = 0; m[10] = 1; m[11] = z; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; }
//multMatrix实现
3 建立光源到model空间的变换矩阵
/* invModelMatrix = inverse(modelMatrix) */ invertMatrix(invModelMatrix, modelMatrix); /* Transform world-space light positions to sphere's object-space. */ transform(objSpaceLightPosition, invModelMatrix, lightPosition); cgSetParameter3fv(myCgVertexParam_lightPosition, objSpaceLightPosition);
实际上既是求modelMatrix的逆矩阵.然后将光源位置(或投影视点)转换到model空间.
//invertMatrix
/* Invert a row-major (C-style) 4x4 matrix. */ static void invertMatrix(float *out, const float *m) { /* Assumes matrices are ROW major. */ #define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } #define MAT(m,r,c) (m)[(r)*4+(c)] double wtmp[4][8]; double m0, m1, m2, m3, s; double *r0, *r1, *r2, *r3; r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1), r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3), r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1), r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3), r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1), r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3), r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1), r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3), r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; /* Choose myPivot, or die. */ if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2); if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1); if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0); if (0.0 == r0[0]) { assert(!"could not invert matrix"); } /* Eliminate first variable. */ m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; s = r0[4]; if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r0[5]; if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r0[6]; if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r0[7]; if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } /* Choose myPivot, or die. */ if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2); if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1); if (0.0 == r1[1]) { assert(!"could not invert matrix"); }
//transform实现
/* Simple 4x4 matrix by 4-component column vector multiply. */ static void transform(float dst[4], const float mat[16], const float vec[4]) { double tmp[4], invW; int i; for (i=0; i<4; i++) { tmp[i] = mat[i*4+0] * vec[0] + mat[i*4+1] * vec[1] + mat[i*4+2] * vec[2] + mat[i*4+3] * vec[3]; } invW = 1 / tmp[3]; /* Apply perspective divide and copy to dst (so dst can vec). */ for (i=0; i<3; i++) dst[i] = tmp[i] * invW; dst[3] = 1; }
4 创建模型视点矩阵
/* modelViewMatrix = eyeViewMatrix * modelMatrix */ multMatrix(modelViewMatrix, eyeViewMatrix, modelMatrix);
model到视点空间的变换矩阵.
5 创建模型视点投影矩阵
/* modelViewProj = projectionMatrix * modelViewMatrix */ multMatrix(modelViewProjMatrix, projectionMatrix, modelViewMatrix);
projectionMatrix根据以下参数确定:视点空间变换到投影空间的变换矩阵.该步骤与纹理投影无关.
fieldOfView(FOV):视角大小;
aspectRatio(aspect):长宽比
zNear(near):近裁剪面
zFar(far):远裁剪面
//buildPerspectiveMatrix实现
6 创建纹理投影矩阵
buildTextureMatrix(lightViewMatrix, modelMatrix, /*out*/textureMatrix);
/* Set matrix parameter with row-major matrix. */
cgSetMatrixParameterfr(myCgVertexParam_modelViewProj, modelViewProjMatrix);
cgSetMatrixParameterfr(myCgVertexParam_textureMatrix, textureMatrix);
static void buildTextureMatrix(const float viewMatrix[16], const float modelMatrix[16], float textureMatrix[16]) { static float eyeToClipMatrix[16]; float modelViewMatrix[16]; static int needsInit = 1; if (needsInit) { const float fieldOfView = 50.0f; const float aspectRatio = 1; float textureProjectionMatrix[16]; float clipToTextureMatrix[16]; /* Build texture projection matrix once. */ buildPerspectiveMatrix(fieldOfView, aspectRatio, 0.25, 20.0, /* Znear and Zfar */ textureProjectionMatrix); makeClipToTextureMatrix(clipToTextureMatrix); /* eyeToClip = clipToTexture * textureProjection */ multMatrix(eyeToClipMatrix, clipToTextureMatrix, textureProjectionMatrix); needsInit = 1; } /* modelView = view * model */ multMatrix(modelViewMatrix, viewMatrix, modelMatrix); /* texture = eyeToClip * modelView */ multMatrix(textureMatrix, eyeToClipMatrix, modelViewMatrix); }
该函数中:
1> buildPerspectiveMatrix同前面的,不过这里用来计算用于投影纹理的视景体变换(投影变换).
2> makeClipToTextureMatrix(clipToTextureMatrix)建立视景体裁切矩阵.
因为视景体是长度为1的单位空间.
3> 将1, 2步的矩阵相乘: multMatrix(eyeToClipMatrix,clipToTextureMatrix,textureProjectionMatrix);
eyeToClipMatrix为得到的纹理投影裁剪变换矩阵.
4> multMatrix(modelViewMatrix, viewMatrix, modelMatrix);
modelViewMatrix为从模型空间到光源(投影视点)空间的变换矩阵.
5> 将3, 4步的结果相乘:
multMatrix(textureMatrix, eyeToClipMatrix, modelViewMatrix);
textureMatrix为从模型视点空间(基于光源位置或投影视点)到纹理投影裁剪空间的变换矩阵.
textureMatrix此即最终的纹理投影变换矩阵.从这些流程可以明白,实际上是把模型投影到纹理上.
顶点程序:
void C9E5v_projTex(float4 position : POSITION, float3 normal : NORMAL, out float4 oPosition : POSITION, out float4 texCoordProj : TEXCOORD0, out float4 diffuseLighting : COLOR, uniform float Kd, uniform float4x4 modelViewProj, uniform float3 lightPosition, uniform float4x4 textureMatrix) { oPosition = mul(modelViewProj, position); // Compute texture coordinates for // querying the projective texture texCoordProj = mul(textureMatrix, position); // Compute diffuse lighting float3 N = normalize(normal); float3 L = normalize(lightPosition - position.xyz); diffuseLighting = Kd * max(dot(N, L), 0); }
片段程序:
void C9E6f_projTex(float4 texCoordProj : TEXCOORD0, float4 diffuseLighting : COLOR, out float4 color : COLOR, uniform sampler2D projectiveMap) { // Fetch color from the projective texture float4 textureColor = tex2Dproj(projectiveMap, texCoordProj); color = textureColor * diffuseLighting; }