经典光照模型(illumination model)

物体表面光照颜色由入射光、物体材质,以及材质和光的交互规律共同决定。

由于环境光给予物体各个点的光照强度相同,且没有方向之分,所以在只有环境光的情况下,同一物体各点的明暗程度均一样。

环境光是对光照现象的最简单抽象,局限性很大。它仅能描述光线在空间中无方向并均匀散布时的状态。

还有一种是平行光,即光线都从同一个方向照射。通过模拟方向光和物体表面的交互模式,可以渲染出具有高真实感(明暗变化、镜面反射等)的三维场景。

漫反射与Lambert 模型

粗糙的物体表面向各个方向等强度地反射光,这种等同地向各个方向散射的现象称为光的漫反射(diffuse reflection)

对于仅暴露在环境光下的朗伯反射体,可以用公式(9-1)表示某点处漫反射的光强:

其中Ia表示环境光强度(简称光强),dk(0<dk<1)为材质对环境光的反射系数,Iam是漫反射体与环境光交互反射的光强。

当方向光照射到朗伯反射体上时,漫反射光的光强与入射光的方向和入射点表面法向夹角的余弦成正比,这称之为Lambert 定律,并由此构造出Lambert漫反射模型:

I是点光源强度,θ是入射光方向与顶点法线的夹角,称为入射(0≤θ ≤90°)

若N 为顶点单位法向量,L 表示从顶点指向光源的单位向量(注意,是由顶点指向光源,不要弄反了),则cosθ 等价于N 与L 的点积。所以公式(9-2)可以表示为公式(9-3):

综合考虑环境光和方向来,Lambert 光照模型可写为:

漫反射渲染

漫反射光照模型顶点着色程序(使用结构体)

  1. struct VertexIn
  2. {
  3. float4 position : POSITION;
  4. float4 normal : NORMAL;
  5. };
  6. struct VertexScreen
  7. {
  8. float4 oPosition : POSITION;
  9. float4 color : COLOR;
  10. };
  11. void main_v(VertexIn posIn,
  12. out VertexScreen posOut,
  13. uniform float4x4 modelViewProj,
  14. uniform float4x4 worldMatrix,
  15. uniform float4x4 worldMatrix_IT,
  16. uniform float3 globalAmbient,
  17. uniform float3 lightPosition,
  18. uniform float3 lightColor,
  19. uniform float3 Kd)
  20. {
  21. posOut.oPosition = mul(modelViewProj, posIn.position);
  22. float3 worldPos = mul(worldMatrix, posIn.position).xyz;
  23. float3 N = mul(worldMatrix_IT, posIn.normal).xyz;
  24. N = normalize(N);
  25. //计算入射光方向
  26. float3 L = lightPosition - worldPos;
  27. L = normalize(L);
  28. //计算方向光漫反射光强
  29. float3 diffuseColor = Kd*lightColor*max(dot(N, L), 0);
  30. //计算环境光漫反射光强
  31. float3 ambientColor = Kd*globalAmbient;
  32. posOut.color.xyz = diffuseColor+ambientColor;
  33. posOut.color.w = 1;
  34. }

镜面反射与Phong 模型

Lambert 模型较好地表现了粗糙表面上的光照现象,但表现不出光泽,主要原因是该模型没有考虑这些表面的镜面反射效果。

Phong Bui Tuong 提出一个计算镜面反射光强的经验模型,称为phong模型,认为镜面反射的光强与反射光线和视线的夹角相关,其数学表达如公式(9-5)所示:

k 为材质的镜面反射系数, Ns是高光指数,V表示从顶点到视点的观察方向, R代表反射光方向。

高光指数反映了物体表面的光泽程度。Ns越大,反射光越集中,当偏离反射方向时,光线衰减的越厉害,只有当视线方向与反射光线方向非常接近时才能看到镜面反射的高光现象,此时,镜面反射光将会在反射方向附近形成亮且小的光斑; Ns越小,表示物体越粗糙,反射光分散,观察到的光斑区域小,强度弱。

反射光的方向R 可以通过入射光方向L(从顶点指向光源)和物体法向量N求出:

phong 模型渲染

phong 光照模型的顶点着色程序实现

  1. struct VertexIn
  2. {
  3. float4 position : POSITION; // Vertex in object-space
  4. float4 normal : NORMAL;
  5. };
  6. struct VertexScreen
  7. {
  8. float4 oPosition : POSITION;
  9. float4 color : COLOR;
  10. };
  11. void main_v( VertexIn posIn,
  12. out VertexScreen posOut,
  13. uniform float4x4 modelViewProj,
  14. uniform float4x4 worldMatrix,
  15. uniform float4x4 worldMatrix_IT,
  16. uniform float3 globalAmbient,
  17. uniform float3 eyePosition,
  18. uniform float3 lightPosition,
  19. uniform float3 lightColor,
  20. uniform float3 Kd,
  21. uniform float3 Ks,
  22. uniform float shininess)
  23. {
  24. posOut.oPosition = mul(modelViewProj, posIn.position);
  25. float3 worldPos = mul(worldMatrix, posIn.position).xyz;
  26. float3 N = mul(worldMatrix_IT, posIn.normal).xyz;
  27. N = normalize(N);
  28. //计算入射光方向、视线方向、反射光线方向
  29. float3 L = normalize(lightPosition - worldPos);
  30. float3 V = normalize(eyePosition - worldPos);
  31. float3 R = 2*max(dot(N, L), 0)*N-L;
  32. R = normalize(R);
  33. // 计算漫反射分量
  34. float3 diffuseColor = Kd * globalAmbient+Kd*lightColor*max(dot(N, L), 0);
  35. //计算镜面反射分量
  36. float3 specularColor = Ks * lightColor*pow(max(dot(V, R), 0), shininess);
  37. posOut.color.xyz = diffuseColor + specularColor;
  38. posOut.color.w = 1;
  39. }

phong 光照模型片段着色实现的结构体

  1. struct VertexIn
  2. {
  3. float4 position : POSITION;
  4. float4 normal : NORMAL;
  5. };
  6. struct VertexScreen
  7. {
  8. float4 oPosition : POSITION;
  9. float4 objectPos : TEXCOORD0;
  10. float4 objectNormal : TEXCOORD1;
  11. };

首先将几何顶点的模型空间坐标转换为用于光栅化的投影坐标;然后将顶点模型坐标和法向量模型坐标赋值给绑定TEXCOORD 语义词的变量,用于传递到片段着色程序中。

phong 光照模型顶点着色程序

  1. void main_v(VertexIn posIn,
  2. out VertexScreen posOut,
  3. uniform float4x4 modelViewProj)
  4. {
  5. posOut.oPosition = mul(modelViewProj, posIn.position);
  6. posOut.objectPos = posIn.position;
  7. posOut.objectNormal = posIn.normal;
  8. }

phong 光照模型片段着色程序

  1. void main_f( VertexScreen posIn,
  2. out float4 color : COLOR,
  3. uniform float4x4 worldMatrix,
  4. uniform float4x4 worldMatrix_IT,
  5. uniform float3 globalAmbient,
  6. uniform float3 eyePosition,
  7. uniform float3 lightPosition,
  8. uniform float3 lightColor,
  9. uniform float3 Kd,
  10. uniform float3 Ks,
  11. uniform float shininess)
  12. {
  13. float3 worldPos = mul(worldMatrix, posIn.objectPos).xyz;
  14. float3 N = mul(worldMatrix_IT, posIn.objectNormal).xyz;
  15. N = normalize(N);
  16. //计算入射光方向、视线方向、反射光线方向
  17. float3 L = normalize(lightPosition - worldPos);
  18. float3 V = normalize(eyePosition - worldPos);
  19. float3 R = 2*max(dot(N, L), 0)*N-L;
  20. R = normalize(R);
  21. // 计算漫反射分量
  22. float3 diffuseColor = Kd * globalAmbient+Kd*lightColor*max(dot(N, L), 0);
  23. //计算镜面反射分量
  24. float3 specularColor = Ks * lightColor*pow(max(dot(V, R), 0), shininess);
  25. color.xyz = diffuseColor + specularColor;
  26. color.w = 1;
  27. }

Blinn-Phong 光照模型

phong光照模型中,必须计算V • R的值,其中R为反射光线方向单位向量,V 为视线方向单位向量,但是在Blinn-phong光照模型中,用N • H 的值取代了V • R。Blinn-phong光照模型公式为:

H 是“光入射方向L 和视点方向V 的中间向量”,通常也称之为半角向量。

Blinn-phong 模型片段着色程序

  1. void main_f(VertexScreen posIn,
  2. out float4 color : COLOR,
  3. uniform float4x4 worldMatrix,
  4. uniform float4x4 worldMatrix_IT,
  5. uniform float3 globalAmbient,
  6. uniform float3 eyePosition,
  7. uniform float3 lightPosition,
  8. uniform float3 lightColor,
  9. uniform float3 Kd,
  10. uniform float3 Ks,
  11. uniform float shininess)
  12. {
  13. float3 worldPos = mul(worldMatrix, posIn.objectPos).xyz;
  14. float3 N = mul(worldMatrix_IT, posIn.objectNormal).xyz;
  15. N = normalize(N);
  16. //计算入射光方向/视线方向/半角向量
  17. float3 L = normalize(lightPosition - worldPos);
  18. float3 V = normalize(eyePosition - worldPos);
  19. float3 H = normalize(L + V);
  20. // 计算漫反射分量
  21. float3 diffuseColor = Kd * globalAmbient+Kd*lightColor*max(dot(N, L), 0);
  22. //计算镜面反射分量
  23. float3 specularColor = Ks * lightColor*pow(max(dot(N, H), 0), shininess);
  24. color.xyz = diffuseColor + specularColor;
  25. color.w = 1;
  26. }

http://blog.csdn.net/doctorsc/article/details/6287059?reload

(转)光照模型及cg实现的更多相关文章

  1. [CG编程] 基本光照模型的实现与拓展以及常见光照模型解析

    0.前言 这篇文章写于去年的暑假.大二的假期时间多,小组便开发一个手机游戏的项目,开发过程中忙里偷闲地了解了Unity的shader编写,而CG又与shaderLab相似,所以又阅读了<CG教程 ...

  2. CG之基本光照模型计算公式

    在一个基本模型里,一个物体表面的颜色是由放射(emissive).环境反射(ambient).漫反射(diffuse)和镜面反射(specular)等光照作用的总和.每种光照作用取决于表面材质的性质( ...

  3. 解读Unity中的CG编写Shader系列八(镜面反射)

    转自http://www.itnose.net/detail/6117378.html 讨论完漫反射之后,接下来肯定就是镜面反射了 在开始镜面反射shader的coding之前,要扩充一下前面提到的知 ...

  4. Unity3D ShaderLab 自定义光照模型

    接着上一篇BasicMyDiffuse的代码来说,这次要说明的就是自定义的光照模型,Ctrl+D>BasicMyDiffuse. 1.>//#pragma surface surf Lam ...

  5. 【Unity Shaders】使用CgInclude让你的Shader模块化——创建CgInclude文件存储光照模型

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...

  6. 【Unity Shaders】Lighting Models —— 光照模型之Lit Sphere

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  7. 【Unity Shaders】Diffuse Shading——创建一个自定义的diffuse lighting model(漫反射光照模型)

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  8. Unity shader学习之高光反射光照模型

    高光反射光照模型的公式如下: Cspecular = Clight * mspecular * max(0, dot(v, r))gloss 要计算高光反射需要知道4个参数:入射光线颜色Cspecul ...

  9. Phong和Blinn-Phong光照模型

    Phong和Blinn-Phong是计算镜面反射光的两种光照模型,两者仅仅有很小的不同之处. 1.Phong模型 Phone模型计算中的一个关键步骤就是反射向量R的计算: 上图中的位于表面“下面”的向 ...

随机推荐

  1. HihoCoder - 1040 矩形判断

    矩形判断 给出平面上4条线段,判断这4条线段是否恰好围成一个面积大于0的矩形. Input 输入第一行是一个整数T(1<=T<=100),代表测试数据的数量. 每组数据包含4行,每行包含4 ...

  2. Core中使用Hangfire

    之前使用Quartz.Net,后来发现hangfire对Core的继承更加的好,而且自带管理后台,这就比前者好用太多了. 安装注册 安装 PM> Install-Package Hangfire ...

  3. 用java实现一个简易编译器1-词法解析入门

    本文对应代码下载地址为: http://download.csdn.net/detail/tyler_download/9435103 视频地址: http://v.youku.com/v_show/ ...

  4. Ruby中Time的常用函数

      Time的常用函数 时间对象. Time.now返回当前时间. 1.Time.at Time.at(time[, usec]) 返回time所指时间的Time对象. time可以是Time对象,也 ...

  5. vuex中怎么把‘库’中的状态对象赋值给内部对象(三种方法)

    一.通过computed的计算属性直接赋值 import store from '@/store/store' export default{ name: 'count', data(){ retur ...

  6. VM CentOS 问题汇总

    1. 锁定文件失败 / 模块启动失败 如下图问题: 原因分析: 虚拟机为了防止有多虚拟机共用一个虚拟磁盘(就是后 缀为.vmdk那个文件)造成数据的丢失等问题,每次启动虚拟机时会给每个虚拟磁盘加一个磁 ...

  7. Extjs报错处理

    错误信息: IE:SCRIPT1009: 缺少 '}' FF: SyntaxError: identifier starts immediately after numeric literal ... ...

  8. ABP学习入门系列(三) (领域层中的仓储Repository)

    一,仓储定义:“在领域层和数据映射层的中介,使用类似集合的接口来存取领域对象”(Martin Fowler) . 仓储用来操作数据库进行数据存取.仓储接口在领域层定义,而仓储的实现类应该写在基础设施层 ...

  9. linux的文件基本属性

    Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限.为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定 1.在Linux中我们 ...

  10. 基于asp.net mvc的近乎产品开发培训课程(第三讲)

    演示产品源码下载地址:http://www.jinhusns.com/Products/Download