四元数协助类¶
1.旋转向量¶
v * (q.w * q.w - b2)
:这是旋转公式中的实部部分,表示向量的缩放。b * (dot(v, b) * 2.0f)
:这是旋转公式中的虚部部分,表示向量在旋转轴上的投影。cross(b, v) * (q.w * 2.f)
:这是旋转公式中的叉积部分,表示向量在旋转轴垂直方向上的旋转。//将向量v用一个四元数q旋转 float3 DDGIQuaternionRotate(float3 v,float4 q) { float3 b = q.xyz; // 提取四元数的虚部 (x, y, z) float2 b2 = dot(b, b); // 计算虚部的平方和 (x² + y² + z²) return (v * (q.w * q.w - b2) + b * (dot(v,b) * 2.0f) +cross(b,v) * (q.w * 2.f)); }
DDGIInput.hlsl :参数记录类¶
CBUFFER,对应DDGIPass的GPU参数¶
CBUFFER_START(DDGIVolumeGpu)
float4 _ProbeRotation; // 探针旋转四元数,用于旋转探针的采样方向
float3 _StartPosition; // 探针体积的起始位置(通常是左下角)
int _RaysPerProbe; // 每个探针当前发射的光线数量
float3 _ProbeSize; // 探针体积的尺寸(宽、高、深)
int _MaxRaysPerProbe; // 每个探针最大可发射的光线数量
uint3 _ProbeCount; // 探针在XYZ三个方向的数量
float _NormalBias; // 沿表面法线的位移偏移量,用于避免自遮挡
float3 _RandomVector; // 随机向量,用于光线方向的随机化
float _EnergyPreservation; // 能量保存系数,控制间接光照的强度保持
float _RandomAngle; // 光线随机化的角度范围
float _HistoryBlendWeight; // 历史数据混合权重,控制时间过滤平滑度
float _IndirectIntensity; // 间接光照强度乘数
float _NormalBiasMultiplier; // 法线偏移的额外乘数
float _ViewBiasMultiplier; // 视图偏移的额外乘数
int DDGI_PROBE_CLASSIFICATION; // 探针分类开关(0=关闭,1=开启)
int DDGI_PROBE_RELOCATION; // 探针重定位开关(0=关闭,1=开启)
float _ProbeFixedRayBackfaceThreshold; // 探针背面检测阈值,用于分类和重定位
float _ProbeMinFrontfaceDistance; // 探针前面最小距离,用于分类和重定位
int _DirectionalLightCount; // 存储场景内所有Directional光源数量(不考虑剔除)
int _PunctualLightCount; // 存储场景内所有Spot和Point光源数量(不考虑剔除)
int DDGI_SKYLIGHT_MODE; // 天空光照模式(0=天空盒,1=渐变,2=纯色,3=不支持)
float4 _SkyboxTintColor; // 天空盒颜色色调
float4 _SkyColor; // 天空颜色(用于渐变模式)
float4 _EquatorColor; // 地平线颜色(用于渐变模式)
float4 _GroundColor; // 地面颜色(用于渐变模式)
float4 _AmbientColor; // 环境光颜色(用于纯色模式)
int DDGI_PROBE_REDUCTION; // 探针精简开关(0=关闭,1=开启)
float _SkyboxIntensityMultiplier; // 天空盒强度乘数
float _SkyboxExposure; // 天空盒曝光值
float _Pad0; // 填充变量,用于对齐内存(无实际作用)
CBUFFER_END
方法类DDGLFuncs.hlsl¶
1.提供一个传入id返回世界坐标的方法(暂时不做探针重定位)¶
float3 DDGIGetProbeWorldPosition(uint gridCoord)
{
//探针世界坐标 = 起始坐标 + 探针大小 * gridCoord坐标
const float3 probeSpaceWorldPosition = gridCoord * _ProbeSize;
//旋转探针(大小*间隔)
const float3 probeVolumeExtents = (_ProbeSize * (_ProbeCount - 1)) * 0.5f;//总长度的一半
float3 probeWorldPostion = probeSpaceWorldPosition - probeVolumeExtents;//实际位置减去一半,【-n/2,n/2】,方便旋转
probeWorldPostion = DDGIQuaternionRotate(probeWorldPostion,_ProbeRotation) + probeVolumeExtents;//旋转后再把这一半加回来
probeWorldPosition += _StartPosition;
//探针重定位:暂时不考虑
/*
// 光追Shader中会用到该函数,而根据下面的链接,光线跟踪Shader分支仍在计划中,这意味着我们不能用变体,所以用变量判断开启与否
// https://portal.productboard.com/unity/1-unity-platform-rendering-visual-effects/tabs/125-shader-system
if(DDGI_PROBE_RELOCATION == DDGI_PROBE_RELOCATION_ON)
{
// 因为我们采样tex2DArray时,采样坐标的z分量实际上对应于gridCoord的y分量,这里需要额外做一步反转
int probeIndex = DDGIGetProbeIndex(gridCoord);
uint3 probeDataTexelCoord = DDGIGetProbeTexelCoordsOneByOne(probeIndex);
probeWorldPosition += DDGILoadProbeDataOffset(probeDataTexelCoord);
}
*/
return probeWorldPosition;
}
2.获取DDGI对应探针的状态¶
这个探针分类感觉可以关。
//------------------------------------------------------------------------
// Probe Data Fetcher 探针数据获取
//------------------------------------------------------------------------
#if defined(DDGI_VISUALIZATION) || defined(DDGI_RAYTRACING) || defined(FORWARD_USE_DDGI)
int DDGILoadProbeState(uint3 coords)
{
int state = DDGI_PROBE_STATE_ACTIVE;
if(DDGI_PROBE_CLASSIFICATION == DDGI_PROBE_CLASSIFICATION_ON)
{
state = (int)LOAD_TEXTURE2D_ARRAY_LOD(_ProbeData, coords.xy, coords.z, 0).a;
}
return state;
}
#else
int DDGILoadProbeState(uint3 coords)
{
int state = DDGI_PROBE_STATE_ACTIVE;
if(DDGI_PROBE_CLASSIFICATION == DDGI_PROBE_CLASSIFICATION_ON)
{
state = (int)_ProbeData[coords].a;
}
return state;
}
#endif
DDGIProbeIndexing¶
1.根据传入的探针ID获取三维坐标¶
count本身记录了三维
//获取一个平面的探针数量
uint3 DDGIGetProbeTexelCoordsOneByOne(int probeIndex)
{
//先拿到一个平面的探针数量
int probesPerPlane = DDGIGetProbesPerPlane(_ProbeCount);
int planeIndex = int(probeIndex / probesPerPlane);
int x = (probeIndex % _ProbeCount.x);
int y = (probeIndex / _ProbeCount.x) % _ProbeCount.z;
return uint3(x, y, planeIndex);
}
DDGIVisualize¶
1.引用DDGI库¶
#define DDGI_VISUALIZATION 1
...
#include "Lib/DDGIInputs.hlsl"
#include "Lib/DDGIProbeIndexing.hlsl"
#include "Lib/DDGIFuncs.hlsl"
2.数据结构¶
其实很简单,我们只需要多一个记录球ID就好了
struct Attributes
{
float3 positionOS : POSITION;
float3 normalOS : NORMAL;
uint instanceID : SV_InstanceID;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 normalWS : NORMAL;
uint probeIndex : SV_InstanceID;
};
3.顶点着色器¶
比较关键的就是根据id转换球的世界坐标,以及赋值ID
//根据id获取探针的相对世界坐标,并加在世界坐标上
uint probeIndex = input.instanceID;
float3 probePosition = DDGIGetProbeWorldPosition(probeIndex);
worldPos += probePosition;
...
vout.probeIndex = probeIndex;