【OpenGL】GLSL-双面渲染技术(Two-sided rendering)
来源:互联网 发布:淘宝最长发货时间 编辑:程序博客网 时间:2024/04/28 19:46
当我们渲染一个完全封闭的物体的时候,多边形的背面都是隐藏的,我们无法看见。但是如果这个物体有一些空洞,那么一些背面就可以被看见了。然而因为这些多边形的法向量的方向在这个时候不是正确的,所以会渲染出错误的结果。为了合理的渲染这些背面,我们必须反转法向量,然后基于这些反转的法向量来计算光照。
下图显示了一个采用Phong光照模型绘制茶壶使用双面渲染与否的结果对比:
图一 使用双面渲染与不使用的效果对比
一、固定管线OpenGL实现双面渲染
在固定管线中,我们需要用一个函数来启用双面光照:
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
这样,OpenGL将会反转表面的法线的方向,表示背面多边形的法线。
实例:
- void GLWidget::initLight()
- {
- GLfloat light_ambient[]={0.7,0.8,0.9,1.0};
- GLfloat light_diffuse[]={1.0,1.0,1.0,1.0};
- GLfloat light_specular[]={1.0,1.0,1.0,1.0};
- GLfloat light_position[]={2.0,2.0,2.0,0.0};
- GLfloat mat_diffuse[]={0.8,0.8,0.8,1.0};
- glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
- glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
- glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
- glLightfv(GL_LIGHT0,GL_POSITION,light_position);
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glEnable(GL_AUTO_NORMAL);
- glEnable(GL_NORMALIZE);
- //glEnable(GL_CULL_FACE);
- //启用双面光照
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
- glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse);
- }
void GLWidget::initLight(){GLfloat light_ambient[]={0.7,0.8,0.9,1.0}; GLfloat light_diffuse[]={1.0,1.0,1.0,1.0}; GLfloat light_specular[]={1.0,1.0,1.0,1.0}; GLfloat light_position[]={2.0,2.0,2.0,0.0};GLfloat mat_diffuse[]={0.8,0.8,0.8,1.0}; glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); glLightfv(GL_LIGHT0,GL_POSITION,light_position); glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);glEnable(GL_AUTO_NORMAL);glEnable(GL_NORMALIZE);//glEnable(GL_CULL_FACE);//启用双面光照glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,mat_diffuse); }效果:
二、可编程管线OpenGL实现双面渲染
假设我们的光照(采用Phong光照模型)计算是基于顶点的。在顶点着色器中,我们需要为每个顶点分别计算两次:front face和back face。两次计算采用的法向量不同。
- #version 400
- layout (location = 0) in vec3 VertexPosition;
- layout (location = 1) in vec3 VertexNormal;
- out vec3 FrontColor;
- out vec3 BackColor;
- struct LightInfo{
- vec4 Position;
- vec3 La;
- vec3 Ld;
- vec3 Ls;
- };
- uniform LightInfo Light;
- struct MaterialInfo{
- vec3 Ka;
- vec3 Kd;
- vec3 Ks;
- float Shininess;
- };
- uniform MaterialInfo Material;
- uniform mat4 ModelViewMatrix;
- uniform mat3 NormalMatrix;
- uniform mat4 ProjectionMatrix;
- uniform mat4 MVP;
- //转化到视空间
- void getEyeSpace(out vec3 tnorm,out vec4 eyeCoords)
- {
- //convert normal and position to eye coords
- tnorm = normalize(NormalMatrix * VertexNormal);
- eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);
- }
- //计算Phong光照模型
- vec3 phongModel(vec4 eyeCoords,vec3 tnorm)
- {
- vec3 s = normalize(vec3(Light.Position - eyeCoords));
- vec3 v = normalize(-eyeCoords.xyz);
- vec3 r = reflect(-s,tnorm);
- vec3 ambient = Light.La * Material.Ka;
- float sDotN = max(dot(s,tnorm),0.0);
- vec3 diffuse = Light.Ld * Material.Kd * sDotN;
- vec3 specular = vec3(0.0);
- if(sDotN > 0)
- specular = Light.Ls * Material.Ks *
- pow(max(dot(r,v),0.0),Material.Shininess);
- return (ambient + diffuse + specular);
- }
- void main()
- {
- vec3 tnorm;
- vec4 eyeCoords;
- getEyeSpace(tnorm,eyeCoords);
- FrontColor = phongModel(eyeCoords,tnorm);
- BackColor = phongModel(eyeCoords,-tnorm);
- gl_Position = MVP * vec4(VertexPosition,1.0);
- }
#version 400layout (location = 0) in vec3 VertexPosition;layout (location = 1) in vec3 VertexNormal;out vec3 FrontColor;out vec3 BackColor;struct LightInfo{vec4 Position;vec3 La;vec3 Ld;vec3 Ls;};uniform LightInfo Light;struct MaterialInfo{vec3 Ka;vec3 Kd;vec3 Ks;float Shininess;};uniform MaterialInfo Material;uniform mat4 ModelViewMatrix;uniform mat3 NormalMatrix;uniform mat4 ProjectionMatrix;uniform mat4 MVP;//转化到视空间void getEyeSpace(out vec3 tnorm,out vec4 eyeCoords){//convert normal and position to eye coordstnorm = normalize(NormalMatrix * VertexNormal);eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);}//计算Phong光照模型vec3 phongModel(vec4 eyeCoords,vec3 tnorm){vec3 s = normalize(vec3(Light.Position - eyeCoords));vec3 v = normalize(-eyeCoords.xyz);vec3 r = reflect(-s,tnorm);vec3 ambient = Light.La * Material.Ka;float sDotN = max(dot(s,tnorm),0.0);vec3 diffuse = Light.Ld * Material.Kd * sDotN;vec3 specular = vec3(0.0);if(sDotN > 0)specular = Light.Ls * Material.Ks * pow(max(dot(r,v),0.0),Material.Shininess);return (ambient + diffuse + specular);}void main(){vec3 tnorm;vec4 eyeCoords;getEyeSpace(tnorm,eyeCoords);FrontColor = phongModel(eyeCoords,tnorm);BackColor = phongModel(eyeCoords,-tnorm);gl_Position = MVP * vec4(VertexPosition,1.0);}在片断着色器中,我们根据关键字gl_FrontFacing的值来为片断赋予颜色值。
gl_FrontFacing是GLSL内置的关键字,它代表图元是面向光源还是背向光源。
片断着色器 twosided.frag:
- #version 400
- in vec3 FrontColor;
- in vec3 BackColor;
- layout (location = 0) out vec4 FragColor;
- void main()
- {
- if(gl_FrontFacing)
- {
- FragColor = vec4(FrontColor,1.0);
- }
- else
- {
- FragColor = vec4(BackColor,1.0);
- }
- }
#version 400in vec3 FrontColor;in vec3 BackColor;layout (location = 0) out vec4 FragColor;void main(){if(gl_FrontFacing){FragColor = vec4(FrontColor,1.0);}else{FragColor = vec4(BackColor,1.0);}}
- 【OpenGL】GLSL-双面渲染技术(Two-sided rendering)
- GLSL-双面渲染技术(Two-sided rendering)
- OpenGL 4.0 用GLSL实现双面渲染
- OpenGL 4.0 用GLSL实现双面渲染
- 现代OpenGL+Qt学习笔记之八:GLSL双面渲染
- Cg Programming/Unity/Two-Sided Surfaces双面表面
- Cg Programming/Unity/Two-Sided Smooth Surfaces双面平滑曲面
- OpenGL 4.0 GLSL 延迟渲染 Deferred shading
- Large Terrain Rendering(大型地形渲染技术)
- 渲染世界的OPENGL<9>GLSL编程-单位着色器
- OpenGL中GLSL渲染茶壶光照完整程序
- Unity3D双面渲染
- 双面渲染shader
- 双面渲染shader
- GLSL实现HDR Rendering
- GLSL实现HDR Rendering
- GLSL实现HDR Rendering
- GLSL实现HDR Rendering
- 数据结构之【图】部分复习题
- Hibernate的一级缓存
- 【OpenGL4.0】GLSL-使用Subroutines选择着色器功能
- JVM相关知识小结
- Android:控件属性
- 【OpenGL】GLSL-双面渲染技术(Two-sided rendering)
- 关于Virtual Machine Manager中linux系统启动报错
- win7怎么取消自动更换桌面
- struts2中s:select标签的使用
- 解决win7 桌面右键没有新建记事本的问题
- 【OpenGL4.0】GLSL-几何着色器详解和实例(GS:Geometry Shader)
- vs2010编译生成sqlite3.lib库
- oracle学习需要的linux基本操作
- jquery 插件收藏其