CS184.1X 计算机图形学导论 第7讲 学习笔记

L7V1:OPENGL 着色:学习动机

1.光照的重要性

1)能够真正显示出形状感知的外观;

2)准确的着色和光照对对传达物体的形状非常重要;

3)着色的方式也十分重要:平面着色(GL_FLAT)、平滑着色(GL_SMOOTH)。

2.颜色

1)RGB模式:分为Red、Green、Blue三个通道

2)RGBA模式:OpenGL中常用此模式,A代表着透明度,每个通道占8bit,总共4字节。

L7V2:OPENGL 着色:Gouraud and Phong Shading

1.Gouraud Shading--标准的平滑着色

1)方法:采用线性插值的方法进行平滑着色;

2)变量说明:I1、I2、I3分别为三个顶点的颜色值,Ip为所要求的颜色值,Ia、Ib为横向扫描线上的交点;

3)公式推导:

a.首先沿Y轴方向插值,得到Ia、Ib

b.在扫描线上沿X轴方向插值,得到Ip

4)极端情况:当以上公式分母等于0时,该公式无法进行插值;

      解决方法:将模型细化,分割成足够多的三角形。

2.Phong Shading (≠ Phong Illumination)

1)思想:不是对颜色进行插值,而是对法向量进行插值;

2)整个光照计算是逐个像素进行的;

L7V3:OPENGL 着色:光照和着色

1.光源

1)属性:Position、Color;

2)衰减模型:

其中:atten代表光强,d代表距离,kc、kl、kq为常数;

3)常数设置(一般情况下,假设光源不存在能量衰竭):

a)点光源:(kc, kl, kq)=(0, 0, 1);

b)线光源:(kc, kl, kq)=(0, 1, 0);

c)面光源(方向光源):(kc, kl, kq)=(1, 0, 0),此处忽略光强衰减;

2.材质

1)计算法向量 -->进而计算漫反射、镜面反射的反射方向;需要计算出每一个顶点的法向量;

     一些由GLUT提供的图形,GLUT已经计算好了法向量;

2)着色模式:

A)环境光(Ambient):即使没有光照射到表面,仍然有光在屋内来回反射,并且产生了漫反射或环境光的感觉;需要设置一个环境光强度,一般来说很小,使不存在黑色的像素;

B)漫反射(Diffuse):对应粗糙不光滑的表面,如墙壁、地板;光均匀地向各个方向反射;

C)镜面反射(Specular):对应于光滑的物体;

D)发射光(Emissive):对应于太阳光等光源,对应于直接看向光源发出的光,而不是反射方向的,在OpenGL中,想看到光源还必须创建光源的几何体;

3.Phong Illumination

1)简单依赖于视点的高光,不基于物理;

 2)思想:a)在镜面反射上,选择视线和反射光线之间进行点积,更进一步,给cos项加上指数来控制表面的光泽度,高光到底有多亮;b)取光源、视线之间的角度的一半,求视线和法向的点积,这样会更接近;

3)Phong Formula

specular = Ks * lightcolor * (dot(V, R))shininess

【说明】

Ks:物体对于反射光线的衰减系数

N:表面法向量

H:光入射方向L和视点方向V的中间向量

Shininess:高光系数

Phong模型计算中的一个关键步骤就是反射向量R的计算:

上图中的位于表面“下面”的向量 ‘I’ 是原始 ‘I’ 向量的拷贝,并且二者是一样的,现在我们的目标计算出向量'R'。根据向量相加原则,向量'R'等于'I'+'V','I'是已知的,所以我们需要做的就是找出向量'V'。注意法向量 ‘N’ 的负方向就是 ‘-N’,我们可以在 ‘I’ 和 ‘-N’ 之间使用一个点乘运算就能得到 ‘I’ 在 ‘-N’ 上面的投影的模。这个模正好是 ‘V’ 的模的一半,由于 ‘V’ 与 ‘N’ 有相同的方向,我们可以将这个模乘上 ‘N’ (其模为 1 )再乘上 2 即可得到 ‘V’。总结一下就是下面的公式:

R = I + V

V = 2 * N * ( -N * I )

得出:R = I + 2 * N * ( -N * I ) = I - 2 * N * ( N * I )

4)Blinn-Phong Formula

Phong模型中计算反射光线的向量是一件相对比较耗时的任务,因此Blinn-Phong对这一点进行了改进。

specular = Ks * lightcolor * (dot(V, H))shininess

【说明】

Ks:物体对于反射光线的衰减系数

 

N:表面法向量

 

H:光入射方向L和视点方向V的中间向量

 

Shininess:高光系数

可见,通过该式计算镜面反射光是符合基本规律的,当视点方向和反射光线方向一致时,计算得到的H与N平行,dot(N,H)取得最大;当视点方向V偏离反射方向时,H也偏离N。同时H的计算比起反射向量R的计算简单的多,R向量的计算需要若干次的向量乘法与加法,而H的计算仅仅需要一次加法。

 

L7V4:OPENGL 着色:片元着色器

1.片元着色器的设置

1 # version 120 
2 
3 varying vec4 color ;
4 varying vec3 mynormal ; 
5 varying vec4 myvertex ; 
6 
7 uniform sampler2D tex ; 
8 uniform int istex ; 
9 uniform int islight ; // are we lighting. 

【说明】

3-5行:由顶点着色器简单传入颜色、法向、顶点;7-8行:sampler2D tex用于纹理,istex表示是否是纹理,islight表示是否是光源,uniform表示在片元着色器中一直不变;

2.着色器变量

 1 // Assume light 0 is directional, light 1 is a point light.  
 2 // The actual light values are passed from the main OpenGL program. 
 3 
 4 uniform vec3 light0dirn ; 
 5 uniform vec4 light0color ; 
 6 uniform vec4 light1posn ; 
 7 uniform vec4 light1color ; 
 8 
 9 // Now, set the material parameters.  These could be varying and/or 
10 // bound to a buffer.  But for now, I'll just make them uniform.  
11 
12 uniform vec4 ambient ; 
13 uniform vec4 diffuse ; 
14 uniform vec4 specular ; 
15 uniform float shininess ; 

【说明】

6行:vec4 light1posn:这是齐次坐标下一个位置处的光源;

12-15行:设置材质参数:环境光系数、漫反射系数、镜面反射系数、光泽度;

3.计算光照

 1 vec4 ComputeLight (const in vec3 direction, const in vec4 lightcolor, 
 2         const in vec3 normal, const in vec3 halfvec, const in vec4 mydiffuse,
 3         const in vec4 myspecular, const in float myshininess) {
 4 
 5     float nDotL = dot(normal, direction)  ;         
 6     vec4 lambert = mydiffuse * lightcolor * max (nDotL, 0.0) ;  
 7 
 8     float nDotH = dot(normal, halfvec) ; 
 9     vec4 phong = myspecular * lightcolor * pow (max(nDotH, 0.0), myshininess) ; 
10 
11     vec4 retval = lambert + phong ; 
12     return retval ;            
13 }    

【说明】此处算法参考Phong光照模型

4.主要变换代码

 1         // They eye is always at (0,0,0) looking down -z axis 
 2         // Also compute current fragment position and direction to eye 
 3 
 4         const vec3 eyepos = vec3(0,0,0) ; 
 5         vec4 _mypos = gl_ModelViewMatrix * myvertex ; 
 6         vec3 mypos = _mypos.xyz / _mypos.w ; // Dehomogenize current location 
 7         vec3 eyedirn = normalize(eyepos - mypos) ; 
 8 
 9         // Compute normal, needed for shading. 
10         // Simpler is vec3 normal = normalize(gl_NormalMatrix * mynormal) ; 
11         vec3 _normal = (gl_ModelViewMatrixInverseTranspose*vec4(mynormal,0.0)).xyz ; 
12         vec3 normal = normalize(_normal) ; 
13 
14         // Light 0, directional
15         vec3 direction0 = normalize (light0dirn) ; 
16         vec3 half0 = normalize (direction0 + eyedirn) ; 
17         vec4 col0 = ComputeLight(direction0, light0color, normal, half0, diffuse, specular, shininess) ;
18 
19         // Light 1, point 
20         vec3 position = light1posn.xyz / light1posn.w ; 
21         vec3 direction1 = normalize (position - mypos) ; // no attenuation 
22         vec3 half1 = normalize (direction1 + eyedirn) ;  
23         vec4 col1 = ComputeLight(direction1, light1color, normal, half1, diffuse, specular, shininess) ;
24 
25         gl_FragColor = ambient + col0 + col1 ; 

【说明】11行:思维矩阵转置后,我们只取xyz分量部分,去掉齐次坐标部分;

 

原文地址:https://www.cnblogs.com/mzyan/p/9641982.html