球面贴图用于环境反射(reflection), 纹理坐标的生成与cube map的reflection mode类似:
推导如下:
顶点处理器:
// Sphere Mapping Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130
// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
// Color to fragment program
smooth out vec2 vVaryingTexCoord;
// Generates a sphere map texture coordinate based on the eyespace surface normal
// and the eye space vertex.
vec2 sphereMap(in vec3 normal, in vec3 ecPosition3)
{
float m;
vec3 r, u;
u = normalize(ecPosition3);
r = reflect(u, normal);
m = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z + 1.0) * (r.z + 1.0));
return vec2 (r.x / m + 0.5, r.y / m + 0.5);
}
void main(void)
{
// Normal in Eye Space
vec3 vEyeNormal = normalMatrix * vNormal;
// Vertex position in Eye Space
vec4 vVert4 = mvMatrix * vVertex;
vec3 vEyeVertex = vVert4.xyz / vVert4.w;
// Pass on the texture coordinates
vVaryingTexCoord = sphereMap(vEyeNormal, vEyeVertex);
// Don't forget to transform the geometry!
gl_Position = mvpMatrix * vVertex;
}
片断着色器:
// ADS Point lighting Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130
out vec4 vFragColor;
uniform sampler2D sphereMap;
smooth in vec2 vVaryingTexCoord;
void main(void)
{
vFragColor = texture(sphereMap, vVaryingTexCoord);
}
用于球面贴图的纹理图像:
在一幅平面纹理图像中对各个方向的颜色进行编码就相当于把一个擦得锃亮的完美球体放在环境的中央,然后在极远处用长焦镜头对它进行拍照。需要编码的区域就是覆盖整个纹理图像的一个圆形区域,它与纹理图像的顶、底、左、右边缘相切。这个圆形区域之外的纹理值不会对结果产生影响,因为它们不会在环境纹理中使用。
如下图: