码迷,mamicode.com
首页 > 其他好文 > 详细

DirectX11笔记4:光照

时间:2015-11-22 20:25:47      阅读:563      评论:0      收藏:0      [点我收藏+]

标签:

按照书中的光照模型,光的类型分为3种:漫反射光,环境光,镜面光。

光源类型也是三种:平行光,点光,聚光灯。

其它需要的数据:材质,法线方向(光照角度)。

 

现在,先以平行光源为例,因为它最简单,不需要去计算距离,角度对于光线的影响:

先定义光源:

    //这里所有的定义只与光的颜色有关,就是定义光的颜色
    DirLight.Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);//环境光
    DirLight.Diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);//漫反射光
    DirLight.Specular = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.0f);//镜面光

1.环境光:

所谓环境光,可以认为有一种光充满了整个照射区域,无论在哪个位置,都可以被覆盖到。他的作用是用于模拟现实世界中的漫反射效果。

实现公式..    A=la?ma  ,解释,获得的环境光等于输入的环境光(Input Ambient 三维向量)逐项相乘材质的环境光系数(Material Ambient三维向量)

HLSL代码:    ambient = mat.Ambient * L.Ambient;

例子:光线(0.2,0.2,0.2)*材质(0.5,0.5,0.5) = (0.1,0.1,0.1)

也就是说,环境光只与材质,光本身有关,与角度无关。

(这里好郁闷。。为什么?表示规是逐项相乘。。。。我记得我们的教材中这个符号表示叉乘。。。而且向量有这种定义吗。。。以下所有的?都表示逐项相乘)

 

2.漫反射光:

 很简单,光打在粗糙的表面上会有各个方向的均匀反射,因此无论在那个方向,我们看到的光的强度是一样的。

实现公式:cd = kd•ld ? md    解释:后一半和前面的环境光一样,材质与光线逐项相乘,前一个kd表示的是一个"角度",在书中7.1的法线定理与7.2中的兰伯特余弦定义有详细的解释,照射点的法线与朝向光线角度的余弦值。

代码与后面的镜面光一起。

 

3.镜面光(也有叫做高光的):

对于一些光滑的材质,光会形成镜面反射,这些光只有在一些特别的角度才可以看见。

实现公式:cs = ks•ls ? ms   这里的ks指的是观察方向与与反射的光线方向的夹角(角度为0时最强)

 

完全代码:

变量的定义:

//-------------------------------------------------------------------------------------
//定义光照结构
//----------------------------------------------------------------------------------------
struct DirectionalLight    ////平行光
{
    float4 Ambient;
    float4 Diffuse;
    float4 Specular;
    float3 Direction;
    float pad;
};
//--------------------------------------------------------------------------------------
// 常量缓冲定义
//--------------------------------------------------------------------------------------
cbuffer ConstantBuffer : register(b0)    //世界,投影坐标转换
{
    matrix World;
    matrix View;
    matrix Projection;
}
cbuffer cbPerFrameLight                        //光线结构打包,暂时就一个平行光
{
    DirectionalLight gDirLight;    //平行光
    //PointLight gPointLight;        //点光
    //SpotLight gSpotLight;        //聚光灯
    float4 gEyePosW;            //眼睛坐标
};


//--------------------------------------------------------------------------------------
//其它结构定义
//--------------------------------------------------------------------------------------
struct Material
{
    float4 Ambient;
    float4 Diffuse;
    float4 Specular; // w = SpecPower
    float4 Reflect;
};

 

函数的实现:

//--------------------------------------------------------------------------------------
// 功能函数实现
//--------------------------------------------------------------------------------------
//实现平行光ComputeDirectionalLight(材质,平行光结构,反射点法线,指向眼睛的单位向量,返回1,返回2,返回3)
void ComputeDirectionalLight(
    Material mat, DirectionalLight L,
    float3 normal, float3 toEye,
    out float4 ambient,
    out float4 diffuse,
    out float4 spec)
{
    // 初始化输出的变量
    ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
    diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
    spec = float4(0.0f, 0.0f, 0.0f, 0.0f);

    // 光照矢量与光线的传播方向相反
    float3 lightVec = -L.Direction;

        // 添加环境光
        ambient = mat.Ambient * L.Ambient;

    // 添加漫反射和镜面光,注意,保证normal,lightVec是单位向量(归一化)
    float diffuseFactor = dot(lightVec, normal);//计算cosA

    // Flatten避免动态分支
    [flatten]
    if (diffuseFactor > 0.0f)    //如果角度的余弦值大于0,
    {
        float3 v = reflect(-lightVec, normal);//reflect通过入射光与法线计算反射向量
            float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);//pow用于计算材质光的线反射度

        diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
        spec = specFactor * mat.Specular * L.Specular;
    }
}

 

相比于原书的代码,我做了更多的注释,但还是要解释一遍:

已经叙述过的环境光计算:ambient = mat.Ambient * L.Ambient;

这里面光线的矢量方向是光线入射方向的反向,也就是反射点指向光源的方向,平行光直接反向就可以了:float3 lightVec = -L.Direction;

计算反射的法线与光线矢量的夹角的余弦值:float diffuseFactor = dot(lightVec, normal),这里面的normal是法线,lightVec上面计算了,他们都是单位向量,只有这样的点乘为cos值,还有一点,关于法线的计算方式可以看书中的7.2节。

然后是一个if语句,关于HLSL中的支持控制语句看msdn的介绍:

https://msdn.microsoft.com/en-us/library/bb509600.aspx

这里面的Flatten与branch的解释我是完全没明白。。。。。再说吧。。。。。。

使用入射光与法线向量计算反射光:float3 v = reflect(-lightVec, normal);

计算反射光与指向眼睛的向量(观察向量,指向观察点)的余弦值dot(v, toEye),判断它是否大于0:max(dot(v, toEye))

最后使用pow对材质进行分析,这是为了用于区分不同材质的反射能力不同。

 

 

 

这一节比较简单,不给代码了。其它的2种光源差不多,不再详细分析了。。。。。。

好麻烦啊。

 

 

追加:关于flatten与branch

https://msdn.microsoft.com/en-us/library/windows/desktop/bb509610

http://www.gamedev.net/topic/650462-branch-and-flatten-attributes-in-sm-5/

我的理解:GPU是尽量避免分支的,因此程序编译的时候会采用一种启发式的智能优化方法去摘除分支,这是为了同个程序在不同分支的情况下都可以有相同的运行时间,避免时间的浪费?但是我们知道有时候一些分支是必须的,因此他提供了branch与flatten来让我们判断是否使用动态分支。书中例子使用了flatten避免了动态分支。

------以上为我看文档与评论得出的结论,自己没有实际的方法去验证。

DirectX11笔记4:光照

标签:

原文地址:http://www.cnblogs.com/Windogs/p/4985811.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!