——体积光,在物理层面来说是丁达尔效应. 主要实现使用的是RayMarch
一、 What is RayMarch?
一根ray一步一步向前走(marching),一直到与物体相交
。
二、RayMarch 元素:
每一个采样点计算都要把所有因素的数值进行相乘处理,得到该采样点上的最终结果
因素
|
公式
|
代码
| 备注 |
1 光强度的衰减计算
|
|
//世界坐标转到灯光坐标系下
float3
lightCoord =
mul
(_MyLightMatrix0,
float4
(wpos,
1
)).xyz;
/
/使用点到光源中心距离的平方dot(lightCoord, lightCoord)构成二维采样坐标,
//对衰减纹理_LightTexture0采样。
// UNITY_ATTEN_CHANNEL是衰减值所在的纹理通道,可以在内置的HLSLSupport.cginc文件中查看
//一般PC和主机平台的话
UNITY_ATTEN_CHANNEL
是r通道,移动平台的话是a通道
atten =
tex2D
(_LightTexture0,
dot
(lightCoord, lightCoord).rr).
UNITY_ATTEN_CHANNEL
;
|
?_LightTexture0 包含了光源衰减信息的衰减纹理
|
2 散射函数??
HG公式
|
|
【常量配置】散射因子g
rd 视角方向
lightDir 光线的方向
float ScatterHG(float3 rd, float3 lightDir, float g){
? ? ? float cosTheta = dot(lightDir,-rd);
? ? ? float result = 1/(4*3.14)* (1 - pow(g,2))/ pow(1 + pow(g,2) -2*g* cosTheta, 1.5);
? ? ? return result;? ? ? ? ??
?}
|
|
3 透光比
Beer–Lambert法则
|
Out = In*exp(-c*d)
|
c是物质密度,d是距离, In是入射光
float ExtingctionFunc(float In, float d, float c)
{
? ? return In* exp(-c*d);
}
|
?
透光强度随着介质的密度光传播的距离的增加成指数下降。
|
4 阴影
|
|
#if defined(SHADOWS_DEPTH)
// 世界坐标转化到阴影坐标下
? ? ? ? ?float4 shadowCoord = mul(_MyWorld2Shadow, float4(wpos, 1));
? ? ? ? ?atten *= saturate(UnitySampleShadowmap(shadowCoord));
#endif
|
采样点和光源做一条线段,检测场景中这条线段有没有和别的可见物体相交, 如果有就说明该采样点被遮挡
UnitySampleShadowMap函数:
根据给定的而阴影坐标,在阴影深度贴图中进行采样,获得阴影坐标对应的贴图文素的深度值
|
从起点开始, 沿着射线,采样每个点的亮度,所有经过的采样点上的亮度求和就是像素的最终颜色。
三、项目中使用的变量以及计算方式:
|
解释
|
代码
|
_WorldViewProj
|
MVP矩阵。
用于把坐标转化成屏幕空间坐标
|
//平台差异化兼容
处
理 构建 p
//GetGPUProjectionMatrix 由于 DX 和 GL的坐
标
差异,
这
里
为
了
统
一化
处
理。 当使用DX渲染的
时
候, 吧DX的z
轴
从(-1,1) 映射到(0,1)。 y
轴进
行反
转
操作
Matrix4x4 proj = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, true);
//平台差异化兼容
处
理
_viewProj = proj * _camera.worldToCameraMatrix;
// VP
_viewProj = proj * _camera.worldToCameraMatrix;?
//构建world 矩阵
float scale = _light.range;
float angleScale = Mathf.Tan((_light.spotAngle + 1) * 0.5f * Mathf.
Deg2Rad) * _light.range;
Matrix4x4 world = Matrix4x4.TRS(_light.transform.position, _light.transform.rotation, new Vector3(angleScale, angleScale, scale));
_WorldViewProj = _viewProj * world;
|
_MyLightMatrix0
|
灯光的矩阵
用于把坐标转化到灯光的坐标系下
|
_viewMatrix = Matrix4x4.TRS(_light.transform.position, _light.transform.rotation, Vector3.one).inverse;
Matrix4x4 clip = Matrix4x4.TRS(new Vector3(0.5f, 0.5f, 0.0f), Quaternion.identity, new Vector3(-0.5f, -0.5f, 1.0f));
Matrix4x4 proj = Matrix4x4.Perspective(_light.spotAngle, 1, 0, 1);
_MyLightMatrix0 = clip * proj * _viewMatrix
|
_MyWorld2Shadow
|
把世界坐标转化到阴影坐标系下
|
Matrix4x4 m = light_clip * light_proj;
m[0, 2] *= -1;
m[1, 2] *= -1;
m[2, 2] *= -1;
m[3, 2] *= -1;
// m 公式
_MyWorld2Shadow = m*_viewMatrix
|
|
|
|
四: 参考
|