Shader快速复习,巩固知识,加强感觉。今天的内容是Cube Mapping(立方环境贴图)。——ZwqXin.com
广告:Shader快速复习:Per Pixel Lighting(逐象素光照)
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/shaderglsl/review-cube-mapping-shader.html
与Cube map认识挺久了,至少在认识GLSL之前就认识了。在固定管道上应用cubemap也比较简单,不过既然与今天的主题无关,就不多说了(给个连接:CUBE MAP OPENGL TUTORIAL)。
Cube map技术说到底就是用一个虚拟的立方体(cube)包围住物体,眼睛到物体某处的向量eyevec经过反射(以该处的法线为对称轴),反射向量reflectvec射到立方体上,就在该立方体上获得一个纹素了(见下图)。明显,我们需要一个类似天空盒般的6张纹理贴在这个虚拟的立方体上。按CUBE MAPPING原意,就是一种enviroment map,因此把周围场景渲染到这6张纹理里是“正统”的。也就是每次渲染时,都作一次离线渲染,分别在每个矩形中心放置相机“拍下”场景,用FBO渲染到纹理,然后把这张纹理作为一个cube map对象的六纹理之一。这样即使是动态之物也能被映射到物体表面了(虽然缺点是不能映射物体自身的任何部分)。
以上这些都需要在opengl实现里完成,而我接下来只想应用shader,就只用一个天空盒的六张图好了,也暂不设置opengl实现了(反正rendermonkey里内置了些cubemap)。
- uniform vec4 eyepos;
- varying vec3 reflectvec;
- void main(void)
- {
- vec4 pos = normalize(gl_ModelViewMatrix * gl_Vertex);
- pos = pos / pos.w;
- vec3 eyevec = normalize(eyepos.xyz - pos.xyz);
- vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
- reflectvec = reflect(-eyevec, norm);
- gl_Position = ftransform();
- }
一切都很单纯,在vertex shader里,依靠传入的眼睛位置计算单位化视线向量eyevec,并依靠正确处理好的顶点法线作为对称轴求出反射向量,注意reflect函数接受一个入射向量,产出出射向量,而-eyevec才是入射向量(入射点 - 光线发出点[眼睛])。
- uniform samplerCube cubemap;
- varying vec3 reflectvec;
- void main(void)
- {
- vec4 texcolor = textureCube(cubemap, reflectvec);
- gl_FragColor = texcolor;
- }
fragment shader更加简洁,不过就是检取一个纹理对象而已。不过用的检索器是samplerCube而不是单纯的二维纹理检索器sampler2D。颜色提取函数也是cube map版本的textureCube,索引就正是反射向量!显然这里不需要单位化的向量也可。物体象素颜色就取用纹素颜色就可以了。当然可以做些其他处理,譬如加了天蓝色散射光最后进行混合。结果分别如下:
(参考资料:OpenGL Shading Language Secong Edition)
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/shaderglsl/review-cube-mapping-shader.html