DirectX11 光照实现
2015-10-03 12:17
387 查看
光照实现
1. 光照结构体
在LightHelper.h文件中,我们定义了一些的结构体来表示平行光、点光或聚光灯。结构体成员组成如下:
1.Ambient:由光源发射的环境光的数量。
2.Diffuse:由光源发射的漫反射光的数量。
3.Specular:由光源发射的高光的数量。
4.Direction:灯光方向。
5.Position:灯光位置。
6.Range:光照范围(离开光源的距离大于这个值的点不会被照亮)。
7.Attenuation:按照(a0、a1和a2)的顺序存储3个衰减常量。衰减常量只用于点和聚光灯,用于控制光强随距离衰减的程度。
8.Spot:该指数用于控制聚光灯的圆锥体区域大小;这个值只用于聚光灯。
“pad”变量的必要性和“packing”格式已经在上一篇博文中讨论过了,如果不知道什么意思,请务必回顾上一篇博文。
下面是各种光源的结构体定义:
struct DirectionalLight { DirectionalLight() { ZeroMemory(this, sizeof(this)); } XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; XMFLOAT3 Direction; float Pad; // 占位最后一个float,这样我们就可以设置光源数组了。 }; struct PointLight { PointLight() { ZeroMemory(this, sizeof(this)); } XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; // 打包到4D矢量: (Position, Range) XMFLOAT3 Position; float Range; // 打包到4D矢量: (A0, A1, A2, Pad) XMFLOAT3 Att; float Pad; // 占位最后一个float,,这样我们就可以设置光源数组了。 }; struct SpotLight { SpotLight() { ZeroMemory(this, sizeof(this)); } XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; // 打包到4D矢量: (Position, Range) XMFLOAT3 Position; float Range; // 打包到4D矢量: (Direction, Spot) XMFLOAT3 Direction; float Spot; // 打包到4D矢量: (Att, Pad) XMFLOAT3 Att; float Pad; // 占位最后一个float,,这样我们就可以设置光源数组了。 };
定义在LightHelper.fx文件中的结构体镜像了上面的结构体:
struct DirectionalLight { float4 Ambient; float4 Diffuse; float4 Specular; float3 Direction; float pad; }; struct PointLight { float4 Ambient; float4 Diffuse; float4 Specular; float3 Position; float Range; float3 Att; float pad; }; struct SpotLight { float4 Ambient; float4 Diffuse; float4 Specular; float3 Position; float Range; float3 Direction; float Spot; float3 Att; float pad; };
2. 实现平行光
下面的HLSL函数根据给出的材质、平行光源、表面法线和由表面指向观察点的矢量,输出光照后的表面颜色。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; // 添加漫反射和镜面光 float diffuseFactor = dot(lightVec, normal); // Flatten避免动态分支 [flatten] if( diffuseFactor > 0.0f ) { float3 v = reflect(-lightVec, normal); float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w); diffuse = diffuseFactor * mat.Diffuse * L.Diffuse; spec = specFactor * mat.Specular * L.Specular; } }
其中,使用的HLSL内置函数有:dot、reflect、pow和max,它们分别用来计算向量点积、向量反射、乘方和取最大值。读者可以在附录B中找到大部分HLSL内置函数的描述,以及有关HLSL语法的快速入门。另外还有一件事情需要注意,那就是当两个向量使用*运算符相乘时,实际执行的是分量乘法。
注意:PC上的HLSL函数总是内联的,调用函数或传递参数不会有性能损失。
3. 实现点光
下面的HLSL函数根据给出的材质、点光源、表面位置、表面法线和表面点到观察点的的矢量信息,输出光照后的表面颜色。void ComputePointLight(Material mat, PointLight L, float3 pos, 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.Position - pos; // 表面离光源的距离 float d = length(lightVec); // 范围测试 if( d > L.Range ) return; // 光源向量归一化 lightVec /= d; // 环境光项 ambient = mat.Ambient * L.Ambient; // 添加漫反射和镜面反射项,所提供的表面是在该光线的位置射出的直线。 float diffuseFactor = dot(lightVec, normal); // Flatten避免动态分支 [flatten] if( diffuseFactor > 0.0f ) { float3 v = reflect(-lightVec, normal); float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w); diffuse = diffuseFactor * mat.Diffuse * L.Diffuse; spec = specFactor * mat.Specular * L.Specular; } // 衰减 float att = 1.0f / dot(L.Att, float3(1.0f, d, d*d)); diffuse *= att; spec *= att; }
4. 实现聚光灯
下面的HLSL函数根据给出的材质、聚光灯、表面位置、表面法线、表面点指向观察点位置的矢量信息,输出光照后的表面颜色:void ComputeSpotLight(Material mat, SpotLight L, float3 pos, 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.Position - pos; // 表面离开光源的距离 float d = length(lightVec); // Range test. if( d > L.Range ) return; // 规范化光照矢量 lightVec /= d; // 计算环境光 ambient = mat.Ambient * L.Ambient; // 计算漫反射和镜面光,所提供的表面是在该光线的位置射出的直线。 float diffuseFactor = dot(lightVec, normal); // Flatten避免动态分支 [flatten] if( diffuseFactor > 0.0f ) { float3 v = reflect(-lightVec, normal); float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w); diffuse = diffuseFactor * mat.Diffuse * L.Diffuse; spec = specFactor * mat.Specular * L.Specular; } // 通过聚光灯因子缩放和衰减 float spot = pow(max(dot(-lightVec, L.Direction), 0.0f), L.Spot); // 通过聚光灯因子缩放和衰减 float att = spot / dot(L.Att, float3(1.0f, d, d*d)); ambient *= spot; diffuse *= att; spec *= att; }
相关文章推荐
- HDU2031 进制转换
- Partition List
- 高可用网站的软件质量保证
- struts2+spring+hibernate框架总结(框架分析+环境搭建+实例源码下载)
- 浅谈HTML5之二:新增的元素和废除的元素
- AndroidUI 引导页面的使用
- ACM起步
- 散列表(hash table)——算法导论(13)
- 浅谈HTML5之一:语法的改变
- JDK源码阅读(三) Collection<T>接口,Iterable<T>接口
- AndroidUI 引导页面的使用
- 下载、编译Android源码简明版
- C#学习日记04---数据类型 之 整数类型
- QT5 学习之路14---对象模型
- POJ 1236 Network of Schools(强连通缩点)
- JavaScript显示和隐藏某个div
- Android开发之基础------------测试相关、sdcard操作、SharedPreferences存取
- HDU 3831 DICS
- java模拟线程死锁
- 判断一个树是不是平衡二叉树