OpenGL 4.0 用GLSL实现双面渲染
来源:互联网 发布:c语言指针3三个数交换 编辑:程序博客网 时间:2024/04/30 23:13
当渲染一个完全封闭的 mesh ,如果里面是隐藏的,则不会被渲染。然而 ,如果这个封闭的mesh有个洞,那么里面就可以有一部分是可见的,则需要被渲染出来。在这中情况下,如果不做处理,可能用shader渲染出的光照效果是不正确的(由于mesh表面法线的方向问题)。为了克服这个问题 需要把mesh的表面法线向量反过来,即-normal,然后计算光照模型。
如图
左边的光照模型采用ADS模式(不正确的光照模型),右边的用ADS光照模型和双边光照模型(Two-sided rendering technique)
顶点shader
- #version 430
- layout (location = 0) in vec3 VertexPosition;
- layout (location = 1) in vec3 VertexNormal;
- out vec3 FrontColor;
- out vec3 BackColor;
- struct LightInfo {
- vec4 Position; // Light position in eye coords.
- vec3 La; // Ambient light intensity
- vec3 Ld; // Diffuse light intensity
- vec3 Ls; // Specular light intensity
- };
- uniform LightInfo Light;
- struct MaterialInfo {
- vec3 Ka; // Ambient reflectivity
- vec3 Kd; // Diffuse reflectivity
- vec3 Ks; // Specular reflectivity
- float Shininess; // Specular shininess factor
- };
- uniform MaterialInfo Material;
- uniform mat4 ModelViewMatrix;
- uniform mat3 NormalMatrix;
- uniform mat4 ProjectionMatrix;
- uniform mat4 MVP;
- vec3 phongModel( vec4 position, vec3 normal ) {
- vec3 s = normalize(vec3(Light.Position - position));
- vec3 v = normalize(-position.xyz);
- vec3 r = reflect( -s, normal );
- vec3 ambient = Light.La * Material.Ka;
- float sDotN = max( dot(s,normal), 0.0 );
- vec3 diffuse = Light.Ld * Material.Kd * sDotN;
- vec3 spec = vec3(0.0);
- if( sDotN > 0.0 )
- spec = Light.Ls * Material.Ks *
- pow( max( dot(r,v), 0.0 ), Material.Shininess );
- return ambient + diffuse + spec;
- }
- void main()
- {
- vec3 tnorm = normalize( NormalMatrix * VertexNormal);
- vec4 eyeCoords = ModelViewMatrix * vec4(VertexPosition,1.0);
- FrontColor = phongModel( eyeCoords, tnorm );
- BackColor = phongModel( eyeCoords, -tnorm );
- gl_Position = MVP * vec4(VertexPosition,1.0);
- }
片元shader
- #version 430
- in vec3 FrontColor;
- in vec3 BackColor;
- layout( location = 0 ) out vec4 FragColor;
- void main() {
- if( gl_FrontFacing ) {
- FragColor = vec4(FrontColor, 1.0);
- } else {
- // FragColor = mix( vec4(BackColor, 1.0), vec4(1.0,0.0,0.0,1.0), 0.7 );
- FragColor = vec4(BackColor, 1.0);
- }
- }
在vertex shader中,ADS光照模型 计算方法放在了phongModel中,这个函数调用了两次,第一次用想模型本身的normal vertor(transformed into eye coordinates ) ,第二次用负normal vector,对应的结果存在Frontcolor 和 Backcolor 中,然后传到片元shader中。
能够优化的地方:
Note that there are a few aspects of the shading model that are independent of the orientation of the normal vector (such as the ambient component). One could optimize this code by rewriting it so that the redundant calculations are only done once. However, in this recipe we compute the entire shading model twice in the interest of making things clear and readable.
注意:在片元shader中,判断是mesh模型的 front 还是back 是通过内置变量gl_FrontFacing判断的,这个判断是基于多边形的环绕方向,而不是法线方向!
A polygon is said to have counter-clockwise winding(逆时针环绕) if the vertices are specified in counter-clockwise order as viewed from the front side of the polygon
默认情况下,如果屏幕上的顶点顺序是逆时针顺序(counter-clockwise order) ,则说明这是一个front facing polygon,然而我们可以通过glFrontFace 来改变。
需要注意的地方
In the vertex shader we determine the front side of the polygon by the direction of the normal vector, and in the fragment shader, the determination is based on the polygon's winding. For this to work properly, the normal vector must be defined appropriately for the face determined by the setting of glFrontFace.
用two-sided rendering 来调试信息
有时候我们想知道哪些是一个mesh的front facing ,哪个是back facing。我们可以用上面的方法,通过在片元shader中中把mesh的back faces 或者 front faces 设置成一个单一颜色来辨认,例如,对于上面的Frag shader ,我们可以在else 中 改为
FragColor = mix( vec4(BackColor,1.0),vec4(1.0,0.0,0.0,1.0), 0.7 );
如下图:
- OpenGL 4.0 用GLSL实现双面渲染
- OpenGL 4.0 用GLSL实现双面渲染
- 【OpenGL】GLSL-双面渲染技术(Two-sided rendering)
- 现代OpenGL+Qt学习笔记之八:GLSL双面渲染
- GLSL-双面渲染技术(Two-sided rendering)
- OpenGL 4.0 GLSL 延迟渲染 Deferred shading
- OpenGL 4.0 GLSL 用单光源 实现逐顶点 漫反射光照模型
- OpenGL 4.0 GLSL 实现 平面着色 Implementing flat shading
- 渲染世界的OPENGL<9>GLSL编程-单位着色器
- OpenGL中GLSL渲染茶壶光照完整程序
- Unity3D双面渲染
- 双面渲染shader
- 双面渲染shader
- OpenGL分片渲染实现
- OpenGL 4.0 GLSL 用 shadow map 算法 生成阴影
- OpenGL/glsl实现bumpmaping的各种细节
- OpenGL GLSL
- opengl实现X射线渲染
- Ueditor和CKeditor 两款编辑器的使用与配置
- 自定义log4j的appender
- Android 中电源状态切换
- HDOJ 1048 The Hardest Problem Ever
- WinInet初识: 登录web
- OpenGL 4.0 用GLSL实现双面渲染
- RequireJS API 中文文档
- thinkphp3.2头像上传即时显示并截取
- 1-29工作日志
- ubuntu 64位系统安装32位软件的一个解决办法
- iOS开发之理解iOS中的MVC设计模式
- ORA-19571: archived-log recid 31 stamp 858722423 not found in control file
- WinInet进阶:发送邮件
- Linux queue.h之TAILQ队列分析