Directx教程(22) 简单的光照模型(1)

     在前面的教程中,我们在顶点属性中直接给顶点赋颜色,这样生成的三维物体缺乏真实感,如下图中两个立方体,左边的是通过光照生成物体表面颜色的,右边的则是直接给顶点赋颜色值。

    

首先,我们学习一下最简单的phong光照模型:

      在phong光照模型中,物体表面的颜色由自发射光(emissive)、环境光(ambient)、漫反射光(diffuse)以及镜面高光(specular)四部分组成,每一部分又是通过物体表面的材质属性和光照属性一起来决定。用公式来表示就是:

     surfaceColor = emissive + ambient + diffuse + specular

自发射光(emissive):

     它表示物体本身具有发射光的属性,它是独立于光源的,同时她它本身也不是光源,不会对场景中的其它为物体有影响。通常emissive用一个常量颜色来表示。

     emissive = Ke, Ke表示材质的自发射光属性。

环境光(ambient):

      环境光模拟场景中来自于来自于各个方向的光线,这些光线也没有位置的概念,比如白天我们在房间里,没有任何特定光源,但我们房间确实亮的。通常它等于

      ambient = Ka x globalAmbient

      Ka表示材质的环境光反射系数,globalAmbient表示入射光线的环境光系数,它们通常都是2个颜色常量。

漫反射光(diffuse):

      漫反射光通常指方向光在物体表面不同方向的反射光,如上图所示,在粗糙的表面上,入射光的反射投向不同的方向。反射光的计算通常用Lambert定律:

 

diffuse = Kd x lightColor x max(N · L, 0)

 

  • Kd  是材质的漫反射颜色系数, lightColor 是入射光的颜色 、
  • N  是物体表面的法向
  • L  是顶点朝向光源的归一化向量
  • P  是着色的顶点位置


高光(specular):

     在光滑的表面,比如金属球,通常有高光的效果。高光通常是物体光滑表面的镜面反射散射效果。

      高光和光源方向和视点都有关系,它的计算公式如下:

specular = Ks x lightColor x facing x (max(N · H, 0)) shininess

  • Ks 是材质的高光系数, lightColor是光源颜色,shininess是高光系数,通常是一个常量。
  • N 是归一化的物体表面法向
  • V 朝向视点的归一化向量
  • L 是顶点朝向光源的归一化向量
  • H 等于归一化的向量(V+L)/2
  • P 是着色的顶点位置
  • 如果N · L > 0facing 是 1 ,否则是0

了解了基本的光照模型以后,我们开始光照程序的编写:

      首先,新建一个CubeModelClass类,该类表示一个cube立方体,但和ModelClass类不同的是,在顶点结构中我们去掉了color属性,增加了normal属性。

struct VertexType
    {
    D3DXVECTOR3 position;
    D3DXVECTOR3 normal; //法向
    };

     该立方体中心在原点,每个顶点的法向,我都取原点到该顶点位置的归一化向量(在shader中实现归一化,给顶点法向赋值时,我并没有做归一化操作)。每个顶点法向位置大概如下图红色线段所示:

     接下来,我们要定义两个新的shader文件light.vs和light.ps,新的基于材质和光源的物体渲染,将使用这两个文件。这两个文件的中光照计算公式就是利用上面的讲的phong光照原理。

    surfaceColor = emissive + ambient + diffuse + specular

    我们在light.vs中实现光照计算,需要注意的是,在利用漫反射(高光)时候,我用了方向光(directional light,所有光线都是一个方向,比如无穷远处的光源,类似太阳光),代码大致如下:

    //自发射颜色
    float3 emissive = float3(0.0, 0.0, 0.0);
   
    //计算环境光
    float3 ambient =  float3(0.3, 0.3, 0.3);
   
    //计算漫反射光
     float3 L = normalize(float3(-1.0, -1.0, 1.0));
     float diffuseLight = max(dot(N, L), 0);
     float3 diffuse =  diffuseLight;

     //计算高光
     float3 V = normalize(cameraPosition - P);
     float3 H = normalize(L + V);
     float specularLight = pow(max(dot(N, H), 0), 5.0);
 
      if (diffuseLight <= 0)
          specularLight = 0;
      float3 specular =  specularLight;

      output.color.xyz = emissive + ambient + diffuse + specular;

      接下来,我们又定义LightShaderClass类,主要用该类实现light.vs和light.ps的载入,参数初始化以及执行shader等功能。

     最后就是在GraphicsClass中创建LightShaderClass和CubeModelClass类,渲染这个新的cube对象(老的modelClass也是一个cube,但我们用colorShader渲染它,并且它的位置也被挪到右边)。

     程序运行后的界面如下:

完整的代码请参考:

工程文件myTutorialD3D11_15

代码下载:

http://files.cnblogs.com/mikewolf2002/myTutorialD3D11.zip

时间: 2024-10-14 04:36:30

Directx教程(22) 简单的光照模型(1)的相关文章

Directx教程(26) 简单的光照模型(5)

    在前面的工程中,我们都是在vs中实现顶点光照计算,然后再把顶点颜色传到ps中.本章中我们尝试fragment光照(或者说叫ps光照),在vs中,我们把顶点在世界坐标系中的法向和位置都直接传输到ps中.     // 世界坐标系中的顶点法向.     float3 N = mul(input.normal, (float3x3)worldMatrix);     output.worldnormal= N;         //世界坐标系顶点位置     worldPosition = m

Directx教程(29) 简单的光照模型(8)

     现在我们新建一个工程myTutorialD3D_23,在这个工程中,对前面一章的代码进行一些整理: 1.我们在顶点属性中增加材质的的漫反射系数和高光系数,前面我们放在一个光照材质结构中,这样我们能够比较灵活的定义不同顶点的材质属性,当然这也增加了顶点缓冲的大小. struct VertexType { D3DXVECTOR3 position; D3DXVECTOR3 normal; //法向 D3DXVECTOR4 Kd; //材质漫反射系数 D3DXVECTOR4 Ks; //材质

Directx教程(28) 简单的光照模型(7)

       现实生活中的点光源都是随着距离衰减的,比如一个电灯泡在近处会照的很亮,远处光线就很弱.本节中我们在前面光公式的基础上,再给漫反射和高光加上一个衰减因子.       光源随着距离衰减并不是纯线性的,常用的公式是: d 是光源到着色点的距离. kC, kL, 和 kQ 分别是常量.线性以及二次衰减系数. 现在在light.ps中,计算光照的代码变成了:   for ( i = 0; i < NUM_LIGHTS; i++)   {     //自发射颜色     emissive =

Directx教程(27) 简单的光照模型(6)

     从myTutorialD3D11_15到myTutorialD3D11_19的工程中,我们都只有一个光源,光源的位置在LightClass中我设置为m_position = D3DXVECTOR4(5.0, 5.0, -3.0,1.0),所以我们渲染的cube,在前面,右侧,上面都没有问题,但是,我们通过A键移动摄像机后,会发现右侧的面没有光照效果.这是因为右侧面的法向是-x方向,漫反射光和高光都为0,所以效果很差. 现在我们将在场景中增加第二个光源,位置放在SetLightPosit

Directx教程(25) 简单的光照模型(4)

     在本篇日志中,我们尝试用不带衰减的点光源来计算漫反射颜色.     前面的三个工程,我们都用的是方向光源(directional light),它的特点是没有光源位置或者说光源位置位于无穷远处,且光线在各个方向都是平行的,所以在工程myTutorialD3D11_17中,我们看到的程序界面上,cube每个面上的颜色都是一样的[因为diffuse光占颜色的大部分].     方向光原理可用以下图表示:      现在我们尝试点光源,点光源原理如下:     因为计算漫反射时候,每个顶点的

Directx教程(24) 简单的光照模型(3)

     在工程myTutorialD3D11_17中,我们重新定义我们的cube顶点法向,每个三角形面的顶点法向都是和这个三角形的面法向是一致的.如下图所示:     在该工程中,我们还修改了CubeModelClass文件,从一个cube.txt文件中读cube顶点位置.法向.纹理坐标.     cube.txt的格式为: Vertex Count: 36 Data: -1.0  1.0 -1.0 0.0 0.0  0.0  0.0 -1.0      数据行前三个数据为顶点位置,接着两个数

Directx教程(23) 简单的光照模型(2)

   在工程myTutorialD3D11_16中,我在文件light.vs中定义了一个材质光源属性常量缓冲. //const buffer最好为4 float的倍数,否则创建const buffer会fail cbuffer LightMaterialBuffer {     float4 lightPosition; //光源位置     float4 lightColor;  //光源颜色     float4 globalAmbient; //光源的环境光反射系数     float4

Directx11教程(29) 简单的光照模型(8)

     现在我们新建一个工程myTutorialD3D_23,在这个工程中,对前面一章的代码进行一些整理: 1.我们在顶点属性中增加材质的的漫反射系数和高光系数,前面我们放在一个光照材质结构中,这样我们能够比较灵活的定义不同顶点的材质属性,当然这也增加了顶点缓冲的大小. struct VertexType     {     D3DXVECTOR3 position;     D3DXVECTOR3 normal; //法向     D3DXVECTOR4 Kd;  //材质漫反射系数    

CSS3实例教程代码:简单制作遨游浏览器LOGO

文章简介:CSS3实例教程代码:简单制作遨游浏览器LOGO. <!DOCTYPE HTML> <html> <head> <title>LOGO</title> <style type="text/css"> * {margin:0; padding:0} .main {width:800px; margin:50px auto 0}  .main_wrapper {width:240px; height:240p