environment mapping的技术可以不依赖ray-trace而实现复杂环境我反射,这种技术使用一个或多个纹理来模拟外部环境的反射,这种技术最适合于应用到具有高亮镜面的物体。
环境映射方法是从视点到反射物体某点P的一根光纤,根据P点的位置与法向n,计算得到反射光线r,不像光线跟踪那样真正去计算反射光线的最近交点,环境映射方法则用该反射光线作为一个索引,得到环境映射中的相应的环境纹理。
其中计算映射到物体的纹理是通过计算视点到正方体表面点的向量的反向量
根据http://www.cnblogs.com/sssa2000/archive/2009/03/22/1419205.html中提到的:
在一个环境中生成球面贴图的时候,由于环境相对于球体而言无限大,所以可以把球体看成是一个单位球体。同时,有由于相机位于无限远处,所以相机到球体上的各个点的向量可以看成是相互平行的。
于是很容易的想到:
1、生成视线向量V。
2、根据顶点法线生成反射向量R。
3、查找R和球面的交点。
4、根据交点求出UV坐标。
R可以很容易的求出。为了求出UV,需要求出R和球面的交点E在球面的位置。这个时候回到生成球面纹理图时候的场景,由于球面是单位球面,利用单位球面的一个性质:球面上的点的归一化法线就是该点在球面上的位置。
我们只需要知道在生成球面纹理图的时候,在球面上相同的点,当反射向量也为R的时候该点的法线为多少即可。
根据向量加法原则,法线是视线向量和反射向量的和。为了模拟视点位于无限远处的情况,可以假象生成球面纹理图的过程是位于View Space,这样的话,Eye Vec就总是(0,0,1)。于是只需要把反射向量也转化到View Space就可以得出球面的法线向量。
也可以这样理解:
环境贴图的坐标和一般2D的贴图的贴图坐标不同,首先它需要用三维向量(x,y,z)来定位,GPU以(x,y,z)中绝对值最大的那个轴来决定要采用哪站贴图,假如坐标为(1,0,0),X轴数值的绝对值最大,所以会采用X轴方向视角的两贴图的其中一个,又因为X>0,即正直,所以会用正X轴方向的贴图。
选择好贴图以后,再把三维贴图坐标转换成正常的二维坐标,转换方法是把绝对值最大的数值除以其他两个数值,再把得到的结果从-1到1的范围使用公式f(x)=(x+1.0)*0.5转换到0~1的范围,假如贴图坐标是(2,0,0),那么会使用正x轴方向的贴图,读取坐标位置为(0.5,0.5)的像素,
绘制渲染环境代码
1 void draw_environment (){
2 static GLfloat xPlane[] = { 1.0f, 0.0f, 0.0f, 0.0f };
3 static GLfloat yPlane[] = { 0.0f, 1.0f, 0.0f, 0.0f };
4 static GLfloat zPlane[] = { 0.0f, 0.0f, 1.0f, 0.0f };
5
6 glEnable (GL_TEXTURE_GEN_S);
7 glEnable (GL_TEXTURE_GEN_T);
8 glEnable (GL_TEXTURE_GEN_R);
9
10 /**//* Bind to cube map texture */
11 glEnable (GL_TEXTURE_CUBE_MAP_ARB);
12 glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, g_uiCubemapTexture);
13
14 //Setup auto texture coord generation
15 glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
16 glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
17 glTexGeni (GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
18
19 glTexGenfv (GL_S, GL_OBJECT_PLANE, xPlane);
20 glTexGenfv (GL_T, GL_OBJECT_PLANE, yPlane);
21 glTexGenfv (GL_R, GL_OBJECT_PLANE, zPlane);
22
23 glDisable (GL_DEPTH_TEST);
24
25// glutSolidSphere (20.0f, 60, 30);
26 glutSolidCube (20.0f);
27
28 glEnable (GL_DEPTH_TEST);
29
30 glDisable (GL_TEXTURE_CUBE_MAP_ARB);
31
32 glDisable (GL_TEXTURE_GEN_S);
33 glDisable (GL_TEXTURE_GEN_T);
34 glDisable (GL_TEXTURE_GEN_R);
35} 绘制反射场景:
1void myDispaly(){
2 GLfloat mat[16], invmat[16];
3 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4 glMatrixMode (GL_TEXTURE);
5 glLoadIdentity ();
6 glMatrixMode (GL_MODELVIEW);
7 glLoadIdentity ();
8 glTranslatef (0.0, 0.0, -5.0);
9
10 glRotated (cam_rot.x, 1.0f, 0.0f, 0.0f);
11 glRotated (cam_rot.y, 0.0f, 1.0f, 0.0f);
12 glRotated (cam_rot.z, 0.0f, 0.0f, 1.0f);
13 draw_environment ();
14
15
16 glEnable (GL_TEXTURE_GEN_S);
17 glEnable (GL_TEXTURE_GEN_T);
18 glEnable (GL_TEXTURE_GEN_R);
19
20 glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
21 glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
22 glTexGeni (GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
23
24
25
26 glEnable (GL_TEXTURE_CUBE_MAP_ARB);
27 glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, g_uiCubemapTexture);
28
29 glGetFloatv (GL_MODELVIEW_MATRIX, mat);
30 compute_matrix_inverse (mat, invmat);
31
32 glMatrixMode (GL_TEXTURE);
33 invmat[12] = 0.0f;
34 invmat[13] = 0.0f;
35 invmat[14] = 0.0f;
36 invmat[15] = 1.0f;
37 glLoadMatrixf (invmat);
38
39
40
41 glMatrixMode (GL_MODELVIEW);
42 glRotated(45,0,1,0);
43 glRotated(180,1,0,0);
44 glutSolidTeapot(1.0);
45
46
47 glDisable (GL_TEXTURE_CUBE_MAP_ARB);
48
49
50 glDisable (GL_TEXTURE_GEN_S);
51 glDisable (GL_TEXTURE_GEN_T);
52 glDisable (GL_TEXTURE_GEN_R);
53 glutSwapBuffers();
54} 渲染结果:
旋转场景:
参考:
http://www.nvidia.cn/object/cube_chs.htmlhttp://www.cnblogs.com/sssa2000/archive/2009/03/22/1419205.html