4种基本光照模型

1.Lambert模型(漫反射)

环境光:

                                             

其中Ambient 表示环境光强度,Kd(0<K<1)为材质对环境光的反射系数,Lambdiff是漫反射体与环境光交互反射的光强。

方向光:

                                             

其中LightColor是点光源强度,θ是入射光方向与顶点法线的夹角,称入射角(0<=A<=90°),Ildiff是漫反射体与方向光交互反射的光强。

若 N为顶点单位法向量,L表示从顶点指向光源的单位向量(注意顶点指向光源),则Cos(θ)等价于dot(N,L),故又有:

                                             

最后综合环境光Ambient和方向光源LightColor,Lambert光照模型可以写成:

                                             

若有多个光源,公式如下:

 

                                              

其中Diffiuse为物体表面漫反射颜色系数,Ambient为环境光颜色,LightColor为光源颜色,N为顶点切平面的法向量,LightVector为从反射点到光源的向量

 

2.Gouraud着色模型

       Gouraud着色处理首先是计算三角形的每个顶点的光照,然后用顶点颜色通过插值处理计算三角形内部的光照颜色。通常在shader代码的顶点着色器中处理光照。

 

3.Phong模型(镜面反射)

Phong着色中,不对每个顶点光照值进行插值计算,而是对顶点法向量N、执行光源的方向向量L和观察者的视线方向V进行插值,计算每个像素的光照。

Phong模型认为镜面反射的光强与反射光线和视线的夹角相关:

                                            

其中Speculer 为镜面反射系数,Light为光源颜色,View表示从顶点到视点的观察方向,Reflect代表反射光方向,Ns是高光指数。由于反射光的方向Reflect可以通过入射光方向LightDirection(从顶点指向光源)和物体的法向量求出: 

                                   注意:dot(N, LightDirection)是入射光与法向量的夹角。乘以N

即:                         

所以最终的计算式为:

                              

 

 

4.Blinn-Phong光照模型(修正镜面光)

Blinn-Phong是一个基于Phong模型修正的模型,其公式为:

                       

其中N是入射点的单位法向量,H是光入射方向L和视点方向V的中间向量,通常也称之为半角向量。

半角向量被广泛用于各类光照模型,原因不但在于半角向量蕴含的信息价值,也在于半角向量是很简单的计算:

                         

 

5.Rendering Equation(全局光照模型)

Rendering Equation 是Kajia在1986年提出的,

Lo(X, Wo) = Le(X, Wo) + ∫fr(X, Wi, Wo) Li(X, Wi) dot(N, Wi) dWi

其中X表示入射点,Lo(X, Wo)即从物体表面X点,沿方向Wo反射的光强,Le(X, Wo)表示从物体表面X以方向Wo 发射出去的光强,该值仅对自发光体有效,fr(X, Wi, Wo)为,入射光线方向为Wi, 照射到点X上,然后从Wo方向发射出去的BRDF值,Li(X, Wi)为入射方向为Wi照射到点X上的入射光强,N表示点X处的法向量,然后对入射方向进行积分(因为光线入射的方向是四面八方的,积分的意义是对每个方向进行一遍计算后相加),计算的结果就是全局光照的辐射率。

对于单个点光源照射到不会自发光的物体上,公式可以简化成:

Lo(X, Wo) = fr(X, Wi, Wo) Li(X, Wi) dot(N, Wi)

这个公式非常有用,通常会将该公式分解为漫反射表达式和镜面表达式之和。对于漫反射表面,BRDF可以忽略不计,因为它总是返回某个恒定值,所以可以写成如下形式:

Lo(X, Wo) = Idiff + frs(X, Wi, Wo) Li(X, Wi) dot(N, Wi)

其中Idiff表示漫反射分量,使用公式的计算方法,frs(X, Wi, Wo)表示镜面反射的BRDF函数,前面的Phong高光模型,其实是rendering equation在单一光源下针对理想镜面反射的特定推导,对于Phong高光而言:

frs(X, Wi, Wo) = Ks (dot(N, H)^Ns  / dot(N, Wi)

 

//-------------------------------------------------------------------------------------------------------------------------

 

几种光照模型的比较

Lambert 模型能够较好地表现粗糙表面上的光照现象,如石灰墙,纸张等等,但是在渲染金属材质制成的物体时,则会显得呆板,表现不出光泽,主要原因是其没有考虑到镜面反射效果,所以Phong模型对其进行了很好的补充。由于Blinn-phng光照模型混合了Lambert的漫射部分和标准的高光,渲染效果有时会比 Phong高光更柔和,有些人认为phong光照模型比blinn-phong更加真实,实际上也是如此,Blinn-phong渲染效果要更加柔和一些,但是由于Blinn-phong的光照模型省去了计算反射光线方向向量的两个乘法运算,速度更快,因此成为许多CG软件中默认的光找渲染方法,此外它也继承在了大多数图形芯片中,用以产生实时的快速渲染。在OpenGL和Direct3D渲染管线中,Blinn-Phong就是默认的渲染模型。 Rendering Equation是基于物理光学的模型,其对于观察方向上的辐射率进行了本质上的量化,Phong模型只是其特定BRDF的推导。

以下给出Blinn-Phong的CG片段,用于参考实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

struct VertexScreen

{

    float4 oPosition : POSITION;

    float4 objectPos : TEXCOORD0;

    float4 objectNormal : TEXCOORD1;

};

 

void main_f(VertexScreen posIn,

    out float4 color : COLOR,

    uniform float4x4 worldMatrix,

    uniform float4x4 worldMatrix_IT,

    uniform float3 globalAmbient,

    uniform float3 eyePosition,

    uniform float3 lightPosition,

    uniform float3 lightColor,

    uniform float3 Kd,

    uniform float3 Ks,

    uniform float shininess)

{

    float3 worldPos = mul(worldMatrix, posIn.objectPos).xyz;

    float3 N = mul(worldMatrix_IT, posIn.objectNormal).xyz;

    N = normalize(N);

 

    //计算入射光方向\视线方向\半角向量

    float3 L = normalize(lightPosition - worldPos);

    float3 V = normalize(eyePosition - worldPos);

    float3 H = normalize(L + V);

 

    // 计算漫反射分量

    float3 diffuseColor = Kd * globalAmbient+Kd*lightColor*max(dot(N, L), 0);

  

    //计算镜面反射分量

    float3 specularColor = Ks * lightColor*pow(max(dot(N, H), 0), shininess);

    color.xyz = diffuseColor + specularColor;

    color.w = 1;

}

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基本光照模型算法通常包括漫反射、镜面反射和环境光三个部分。下面是一个简单的示例程序,使用C语言和OpenGL实现了基本光照模型算法。 ```c #include <GL/glut.h> #include <math.h> // 光源位置 GLfloat light_position[] = { 1.0f, 1.0f, 1.0f, 0.0f }; // 材质属性 GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat mat_shininess[] = { 100.0f }; // 物体位置 GLfloat object_pos[] = { 0.0f, 0.0f, 0.0f }; void init(void) { // 设置光源位置 glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 设置材质属性 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); // 启用光照 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // 启用深度测试 glEnable(GL_DEPTH_TEST); } void display(void) { // 清空缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 设置物体位置 glPushMatrix(); glTranslatef(object_pos[0], object_pos[1], object_pos[2]); // 绘制物体 glutSolidSphere(1.0, 20, 20); glPopMatrix(); // 刷新显示 glutSwapBuffers(); } void reshape(int w, int h) { // 设置视口大小 glViewport(0, 0, (GLsizei)w, (GLsizei)h); // 设置投影矩阵 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (GLdouble)w / (GLdouble)h, 1.0, 100.0); // 设置模型视图矩阵 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'w': object_pos[2] -= 0.1; break; case 's': object_pos[2] += 0.1; break; case 'a': object_pos[0] -= 0.1; break; case 'd': object_pos[0] += 0.1; break; case 'q': object_pos[1] -= 0.1; break; case 'e': object_pos[1] += 0.1; break; } glutPostRedisplay(); } int main(int argc, char **argv) { // 初始化 GLUT glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(400, 400); glutInitWindowPosition(100, 100); glutCreateWindow("Basic Lighting"); // 初始化 init(); // 设置回调函数 glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); // 进入主循环 glutMainLoop(); return 0; } ``` 这个示例程序使用了OpenGL的固定管线,其中`init()`函数设置了光源位置和材质属性,并启用了光照和深度测试。`display()`函数绘制了一个球体,`reshape()`函数设置了投影矩阵和模型视图矩阵,`keyboard()`函数处理键盘事件。在主函数中,我们使用了GLUT库初始化窗口并设置回调函数,然后进入主循环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值