1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
| Shader "Hidden/VolumeRenderer" { Properties { // 后处理传入的全屏幕RT _MainTex("Texture", 2D) = "white" {} // 体积雾 Volume 的 Bounding Box _BoundMin("Bound Min", Vector) = (-5, -5, -5, 0) _BoundMax("Bound Max", Vector) = (5, 10, 5, 0) // 体积雾的总体密度 _Density("Density", float) = 0.01 // 体积雾的颜色 _AttenuationColor("Attenuation Color", float) = (1, 1, 1, 1)
// 体积雾的噪声图 _VolumeTex("Volume Texture", 3D) = "white"{} _VolumeOffset("Volume Texture Offset", Vector) = (1, 1, 1, 0) _VolumeScale("Volume Texture Scale", Vector) = (1, 1, 1, 0) } SubShader { Tags { "RenderType"="Opaque" } LOD 100
Pass { ZTest Always Cull Off ZWrite Off
// HLSL 代码块。Unity SRP 使用 HLSL 语言。 HLSLPROGRAM // 此行定义顶点着色器的名称。 #pragma vertex vert // 此行定义片元着色器的名称。 #pragma fragment frag
// Core.hlsl 文件包含常用的 HLSL 宏和 // 函数的定义,还包含对其他 HLSL 文件(例如 // Common.hlsl、SpaceTransforms.hlsl 等)的 #include 引用。 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// DeclareDepthTexture.hlsl 文件包含用于对摄像机深度纹理进行采样的 // 实用程序。 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" // #include "TerrainFog.hlsl"
#pragma enable_d3d11_debug_symbols
// 结构定义将定义它包含哪些变量。 // 此示例使用 Attributes 结构作为顶点着色器中的 // 输入结构。 struct Attributes { // positionOS 变量包含对象空间中的顶点 // 位置。 float2 uv : TEXCOORD0; float4 positionOS : POSITION; };
struct Varyings { // 此结构中的位置必须具有 SV_POSITION 语义。 float4 positionHCS : SV_POSITION; float2 uv : TEXCOORD0; };
sampler _MainTex; sampler _VolumeTex;
float4 _BoundMin; float4 _BoundMax; float _Density;
float4 _VolumeOffset; float4 _VolumeScale; float4 _AttenuationColor;
// 顶点着色器定义具有在 Varyings 结构中定义的 // 属性。vert 函数的类型必须与它返回的类型(结构) // 匹配。 Varyings vert(Attributes IN) { // 使用 Varyings 结构声明输出对象 (OUT)。 Varyings OUT; // TransformObjectToHClip 函数将顶点位置 // 从对象空间变换到齐次裁剪空间。 OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); OUT.uv = IN.uv; // 返回输出。 return OUT; }
int intersect(float3 rayPos, float rayDistance) { return rayPos.x < _BoundMax.x&& rayPos.x > _BoundMin.x && rayPos.y < _BoundMax.y&& rayPos.y > _BoundMin.y && rayPos.z < _BoundMax.z&& rayPos.z > _BoundMin.z && rayDistance > 0.0f; }
float phase(float3 rayPos, float3 wi, float3 wo) { return 1.0 / (4 * 3.1415926f); }
// 光线与方形bounding box求交函数 void rayBoxDst(float3 boundsMin, float3 boundsMax, //世界相机位置 光线方向倒数 float3 rayOrigin, float3 invRaydir, out float dstToBox, out float dstInsideBox) { float3 t0 = (boundsMin - rayOrigin) * invRaydir; float3 t1 = (boundsMax - rayOrigin) * invRaydir; float3 tmin = min(t0, t1); float3 tmax = max(t0, t1);
float dstA = max(max(tmin.x, tmin.y), tmin.z); //进入点 float dstB = min(tmax.x, min(tmax.y, tmax.z)); //出去点
dstToBox = max(0, dstA); dstInsideBox = max(0, dstB - dstToBox); }
#define SOURCE_RAY_MARCH_STEP_COUNT (8) // 计算 Ls项 float4 sourceFunction(float3 rayPos, float3 w) { // 获取主光源的方向 float3 dirToLight = GetMainLight().direction; // 获取主光源的强度 float4 intensity = float4(GetMainLight().color, 1.0f);
float3 invRayDir = 1.0f / (dirToLight + 1e-6f);
float _, dstInsideBox; // 计算交点位置,其中dstInsideBox为光线在体积雾内部传播距离。 rayBoxDst(_BoundMin.xyz, _BoundMax.xyz, rayPos, invRayDir, _, dstInsideBox);
// 根据距离计算步长 float rayStepDistance = dstInsideBox / SOURCE_RAY_MARCH_STEP_COUNT; float3 step = rayStepDistance * dirToLight;
float4 transmittance = 1.0f; float4 sigma = 1.0f;
float texDensity = tex3D(_VolumeTex, rayPos * _VolumeScale + _VolumeOffset).r; sigma = _Density * texDensity * _AttenuationColor;
// ray marching 计算 transmittance for (int i = 0; i < SOURCE_RAY_MARCH_STEP_COUNT; i++) { rayPos += step; float texDensity = tex3D(_VolumeTex, rayPos * _VolumeScale + _VolumeOffset).r; transmittance *= exp(-_Density * texDensity * rayStepDistance * _AttenuationColor); }
return sigma * phase(rayPos, dirToLight, w) * transmittance * intensity; }
#define RAY_MARCH_STEP_COUNT (32)
// 计算体渲染方程,其中返回值对应Tr项,inScatter对应右半部分Ls的积分 float4 VolumeRayMarching(float3 worldPos, out float4 inScatter) { float3 rayPos = _WorldSpaceCameraPos; float3 rayDir = worldPos - rayPos; float rayDistance = length(rayDir); rayDir /= (rayDistance + 1e-6f);
// float rayStepDistance = 0.25f;
float3 invRayDir = 1.0f / (rayDir + 1e-6f); float dstToBox, dstInsideBox; rayBoxDst(_BoundMin.xyz, _BoundMax.xyz,rayPos, invRayDir, dstToBox, dstInsideBox);
float maxStepDistance = max(_BoundMax.x - _BoundMin.x, max(_BoundMax.y - _BoundMin.y, _BoundMax.z - _BoundMin.z)); float rayStepDistance = maxStepDistance / RAY_MARCH_STEP_COUNT;
rayPos += dstToBox * rayDir; rayDistance -= dstToBox;
float3 step = rayDir * rayStepDistance; float4 transmittance = 1.0f; inScatter = 0.0f;
for (int i = 0;i < RAY_MARCH_STEP_COUNT;i++) { rayPos += step; rayDistance -= rayStepDistance;
if (intersect(rayPos, rayDistance)) { float texDensity = tex3D(_VolumeTex, rayPos * _VolumeScale + _VolumeOffset).r; transmittance *= exp(-_Density * texDensity * rayStepDistance * _AttenuationColor); inScatter += sourceFunction(rayPos, rayDir) * rayStepDistance * transmittance; } } return transmittance; }
// 片元着色器定义。 half4 frag(Varyings i) : SV_Target { #if UNITY_REVERSED_Z real depth = SampleSceneDepth(i.uv); #else // 调整 z 以匹配 OpenGL 的 NDC real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(i.uv)); #endif
// float3 worldPos = ComputeWorldSpacePosition(i.uv, depth, UNITY_MATRIX_I_VP); float4 ndc = float4(i.uv * 2 - 1, depth, 1);
#if UNITY_UV_STARTS_AT_TOP ndc.y *= -1; #endif
float4 worldPos = mul(UNITY_MATRIX_I_VP, ndc); worldPos /= worldPos.w;
float4 volumeInScattering = 0.0f; float4 attenduation = VolumeRayMarching(worldPos, volumeInScattering); // 将体渲染方程的两部分相加,其中_MainTex采样对应Lo项。 half4 customColor = tex2D(_MainTex, i.uv) * attenduation + volumeInScattering;//lerp( tex2D(_MainTex, i.uv) , half4(1, 1, 1, 1), density); return customColor; } ENDHLSL } } }
|