浏览代码

Add support for volumetric shadowing and spot lights

/sample_game
Evgenii Golubev 7 年前
当前提交
2cba6a27
共有 9 个文件被更改,包括 134 次插入70 次删除
  1. 10
      Assets/ScriptableRenderPipeline/Core/ShaderLibrary/CommonLighting.hlsl
  2. 48
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  3. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDShaderIDs.cs
  4. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
  5. 17
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/HomogeneousFog.cs
  6. 18
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/HomogeneousFog.cs.hlsl
  7. 60
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute
  8. 37
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  9. 8
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl

10
Assets/ScriptableRenderPipeline/Core/ShaderLibrary/CommonLighting.hlsl


#define PUNCTUAL_LIGHT_THRESHOLD 0.01 // 1cm (in Unity 1 is 1m)
float GetDistanceAttenuation(float3 unL, float invSqrAttenuationRadius)
float GetDistanceAttenuation(float sqrDist, float invSqrAttenuationRadius)
float sqrDist = dot(unL, unL);
}
float GetDistanceAttenuation(float3 unL, float invSqrAttenuationRadius)
{
float sqrDist = dot(unL, unL);
return GetDistanceAttenuation(sqrDist, invSqrAttenuationRadius);
}
float GetAngleAttenuation(float3 L, float3 lightDir, float lightAngleScale, float lightAngleOffset)

48
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


ComputeShader m_VolumetricLightingCS { get { return m_Asset.renderPipelineResources.volumetricLightingCS; } }
int m_VolumetricLightingKernel;
static ComputeBuffer s_UnboundedVolumeData = null;
Material m_CameraMotionVectorsMaterial;

m_DebugDisplaySettings.RegisterDebug();
m_DebugFullScreenTempRT = HDShaderIDs._DebugFullScreenTexture;
s_UnboundedVolumeData = new ComputeBuffer(1, System.Runtime.InteropServices.Marshal.SizeOf(typeof(VolumeProperties)));
}
void InitializeDebugMaterials()

m_SkyManager.Cleanup();
m_SsaoEffect.Cleanup();
Utilities.SafeRelease(s_UnboundedVolumeData);
#if UNITY_EDITOR
SupportedRenderingFeatures.active = SupportedRenderingFeatures.Default;

cmd.SetGlobalVectorArray(HDShaderIDs._ShapeParams, sssParameters.shapeParams);
cmd.SetGlobalVectorArray(HDShaderIDs._HalfRcpVariancesAndWeights, sssParameters.halfRcpVariancesAndWeights);
cmd.SetGlobalVectorArray(HDShaderIDs._TransmissionTints, sssParameters.transmissionTints);
SetGlobalVolumeProperties(cmd);
}
}

}
}
void VolumetricLightingPass(HDCamera hdCamera, CommandBuffer cmd)
// Returns 'true' if the global fog is enabled, 'false' otherwise.
public static bool SetGlobalVolumeProperties(CommandBuffer cmd, ComputeShader cs = null)
HomogeneousFog unboundedFogComponent = null;
HomogeneousFog globalFogComponent = null;
unboundedFogComponent = fogComponent;
globalFogComponent = fogComponent;
if (unboundedFogComponent == null) { return; }
// TODO: may want to cache these results somewhere.
VolumeProperties globalFogProperties = (globalFogComponent != null) ? globalFogComponent.volumeParameters.GetProperties()
: VolumeProperties.GetNeutralVolumeProperties();
if (cs)
{
cmd.SetComputeVectorParam(cs, HDShaderIDs._GlobalFog_Extinction, globalFogProperties.extinction);
cmd.SetComputeFloatParam( cs, HDShaderIDs._GlobalFog_Asymmetry, globalFogProperties.asymmetry);
cmd.SetComputeVectorParam(cs, HDShaderIDs._GlobalFog_Scattering, globalFogProperties.scattering);
}
else
{
cmd.SetGlobalVector(HDShaderIDs._GlobalFog_Extinction, globalFogProperties.extinction);
cmd.SetGlobalFloat( HDShaderIDs._GlobalFog_Asymmetry, globalFogProperties.asymmetry);
cmd.SetGlobalVector(HDShaderIDs._GlobalFog_Scattering, globalFogProperties.scattering);
}
return (globalFogComponent != null);
}
void VolumetricLightingPass(HDCamera hdCamera, CommandBuffer cmd)
{
if (!SetGlobalVolumeProperties(cmd, m_VolumetricLightingCS)) { return; }
using (new Utilities.ProfilingSample("VolumetricLighting", cmd))
{

: "VolumetricLightingAllLights");
List<VolumeProperties> unboundedVolumeProperties = new List<VolumeProperties>();
unboundedVolumeProperties.Add(unboundedFogComponent.volumeParameters.GetProperties());
// TODO: probably unnecessary to update the buffer every frame.
s_UnboundedVolumeData.SetData(unboundedVolumeProperties);
cmd.SetComputeBufferParam( m_VolumetricLightingCS, m_VolumetricLightingKernel, "_UnboundedVolume", s_UnboundedVolumeData);
cmd.SetComputeTextureParam(m_VolumetricLightingCS, m_VolumetricLightingKernel, "_LightingTexture", m_CameraColorBufferRT);
cmd.SetComputeTextureParam(m_VolumetricLightingCS, m_VolumetricLightingKernel, HDShaderIDs._DepthTexture, GetDepthTexture());
cmd.SetComputeTextureParam(m_VolumetricLightingCS, m_VolumetricLightingKernel, HDShaderIDs._CameraColorTexture, m_CameraColorBufferRT);
cmd.SetComputeTextureParam(m_VolumetricLightingCS, m_VolumetricLightingKernel, HDShaderIDs._DepthTexture, GetDepthTexture());
// Pass clustered light data (if present) into the compute shader.
m_LightLoop.PushGlobalParams(hdCamera.camera, cmd, m_VolumetricLightingCS, m_VolumetricLightingKernel, true);

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDShaderIDs.cs


internal static readonly int _Cubemap = Shader.PropertyToID("_Cubemap");
internal static readonly int _SkyParam = Shader.PropertyToID("_SkyParam");
internal static readonly int _PixelCoordToViewDirWS = Shader.PropertyToID("_PixelCoordToViewDirWS");
internal static readonly int _GlobalFog_Extinction = Shader.PropertyToID("_GlobalFog_Extinction");
internal static readonly int _GlobalFog_Asymmetry = Shader.PropertyToID("_GlobalFog_Asymmetry");
internal static readonly int _GlobalFog_Scattering = Shader.PropertyToID("_GlobalFog_Scattering");
}
}

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs


cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs.specularLightingUAV, colorBuffers[0]);
cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs.diffuseLightingUAV, colorBuffers[1]);
HDRenderPipeline.SetGlobalVolumeProperties(cmd, deferredComputeShader);
// always do deferred lighting in blocks of 16x16 (not same as tiled light size)
if (enableFeatureVariants)

17
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/HomogeneousFog.cs


[GenerateHLSL]
public struct VolumeProperties
{
public Vector3 extinction;
public float asymmetry;
public float asymmetry;
public Vector3 extinction;
public float unused;
public float align16;
public static VolumeProperties GetNeutralVolumeProperties()
{
VolumeProperties properties = new VolumeProperties();
properties.extinction = Vector3.zero;
properties.asymmetry = 0;
properties.scattering = Vector3.zero;
return properties;
}
}
[Serializable]

18
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/HomogeneousFog.cs.hlsl


// PackingRules = Exact
struct VolumeProperties
{
float3 extinction;
float asymmetry;
float asymmetry;
float3 extinction;
float unused;
float align16;
float3 GetScattering(VolumeProperties value)
float3 GetExtinction(VolumeProperties value)
return value.scattering;
return value.extinction;
float3 GetExtinction(VolumeProperties value)
float3 GetScattering(VolumeProperties value)
return value.extinction;
return value.scattering;
float GetUnused(VolumeProperties value)
float GetAlign16(VolumeProperties value)
return value.unused;
return value.align16;
}

60
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute


//--------------------------------------------------------------------------------------------------
TEXTURE2D(_DepthTexture); // Z-buffer
RW_TEXTURE2D(float4, _LightingTexture); // Updated texture
// Unity does not support structures inside constant buffers,
// so we are forced to use a structured buffer instead.
StructuredBuffer<VolumeProperties> _UnboundedVolume;
RW_TEXTURE2D(float4, _CameraColorTexture); // Updated texture
//--------------------------------------------------------------------------------------------------
// Implementation

// Computes the in-scattered radiance along the ray.
float3 PerformIntegration(PositionInputs posInput, Ray ray, uint numSteps)
{
float3 scattering = _UnboundedVolume[0].scattering;
float3 extinction = _UnboundedVolume[0].extinction;
float asymmetry = _UnboundedVolume[0].asymmetry;
float3 extinction = _GlobalFog_Extinction;
float asymmetry = _GlobalFog_Asymmetry;
float3 scattering = _GlobalFog_Scattering;
LightLoopContext context;
// ZERO_INITIALIZE(LightLoopContext, context);

// Fetch the light.
LightData lightData = _LightDatas[punctualLightIndex];
float3 L = lightData.positionWS - samplePositionWS;
float3 sampleToLight = lightData.positionWS - samplePositionWS;
float dist2 = dot(L, L);
float dist = sqrt(dist2);
float rcpDist = rsqrt(dist2);
float LdotD = dot(L, ray.directionWS) * rcpDist;
float distSq = dot(sampleToLight, sampleToLight);
float dist = sqrt(distSq);
float3 L = sampleToLight * rsqrt(distSq);
float LdotD = dot(L, ray.directionWS);
float shadow = 1;
// Note: lightData.invSqrAttenuationRadius is 0 when applyRangeAttenuation is false
float attenuation = (lightData.lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius) : 1;
// Reminder: lights are oriented backward (-Z)
attenuation *= GetAngleAttenuation(L, -lightData.forward, lightData.angleScale, lightData.angleOffset);
float shadow = 1;
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float4 L_dist = { L * rcpDist, dist };
float3 offset = 0; // GetShadowPosOffset(nDotL, normal);
shadow = GetPunctualShadowAttenuation(context.shadowContext, samplePositionWS + offset, 0, lightData.shadowIndex, L_dist, posInput.unPositionSS);
shadow = GetPunctualShadowAttenuation(context.shadowContext, samplePositionWS + offset, 0, lightData.shadowIndex, float4(L, dist), posInput.unPositionSS);
radiance += (dt * scattering * phase * shadow * rcpDist * rcpDist) * (lightT * sampleT) * lightData.color;
radiance += (dt * scattering * phase * attenuation * shadow) * (lightT * sampleT) * lightData.color;
}
}
}

if (pixelCoord.x >= (uint)_ScreenSize.x || pixelCoord.y >= (uint)_ScreenSize.y) { return; }
#ifdef UNITY_REVERSED_Z
float z = max(LOAD_TEXTURE2D(_DepthTexture, pixelCoord).r, 0 + 0.001);
#else
float z = min(LOAD_TEXTURE2D(_DepthTexture, pixelCoord).r, 1 - 0.001);
#endif
UpdatePositionInput(max(LOAD_TEXTURE2D(_DepthTexture, pixelCoord).r, 0.02), _InvViewProjMatrix, _ViewProjMatrix, posInput);
UpdatePositionInput(z, _InvViewProjMatrix, _ViewProjMatrix, posInput);
Ray cameraRay;

cameraRay.maxLength = sqrt(dot(cameraRay.directionWS, cameraRay.directionWS));
cameraRay.directionWS *= rsqrt(dot(cameraRay.directionWS, cameraRay.directionWS)); //Normalize
float3 rayT = Transmittance(OpticalDepthHomogeneous(_UnboundedVolume[0].extinction, cameraRay.maxLength));
// TODO: make this a parameter controllable from C#.
const float maxSamplingDistance = 64.0f; // In meters
float3 rayT = Transmittance(OpticalDepthHomogeneous(_GlobalFog_Extinction, cameraRay.maxLength));
float distanceScale = max(1, maxSamplingDistance / cameraRay.maxLength);
cameraRay.maxLength *= distanceScale;
posInput.depthVS *= distanceScale;
float3 inL = PerformIntegration(posInput, cameraRay, 64);
const int numSamples = 64;
float3 inL = PerformIntegration(posInput, cameraRay, numSamples);
_LightingTexture[pixelCoord] = float4(rayT * _LightingTexture[pixelCoord].rgb + inL, _LightingTexture[pixelCoord].a);
_CameraColorTexture[pixelCoord] = float4(rayT * _CameraColorTexture[pixelCoord].rgb + inL, _CameraColorTexture[pixelCoord].a);
}

37
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


#include "Lit.cs.hlsl"
#include "SubsurfaceScatteringProfile.cs.hlsl"
// Enables attenuation of light source contributions by participating media (fog).
#define VOLUMETRIC_SHADOWING_ENABLED
#ifdef VOLUMETRIC_SHADOWING_ENABLED
// Apparently, not all shaders include "ShaderVariables.hlsl".
#include "../../ShaderVariables.hlsl"
#include "../../../Core/ShaderLibrary/VolumeRendering.hlsl"
#endif
// In case we pack data uint16 buffer we need to change the output render target format to uint16
// TODO: Is there a way to automate these output type based on the format declare in lit.cs ?
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16

float3x3 ltcXformClearCoat; // TODO: make sure the compiler not wasting VGPRs on constants
float ltcClearCoatFresnelTerm;
float3x3 ltcCoatT;
#ifdef VOLUMETRIC_SHADOWING_ENABLED
float3 globalFogExtinction;
#endif
};
// This is a refract - TODO: do we call original refract or this one, original maybe slightly emore expensive, to check

{
preLightData.ltcMagnitudeFresnel = bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
}
#ifdef VOLUMETRIC_SHADOWING_ENABLED
preLightData.globalFogExtinction = _GlobalFog_Extinction;
#endif
return preLightData;
}

// For point light and directional GetAngleAttenuation() return 1
float3 lightToSurface = positionWS - lightData.positionWS;
float3 unL = -lightToSurface;
float3 L = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? normalize(unL) : -lightData.forward;
float NdotL = dot(bsdfData.normalWS, L);
float3 unL = -lightToSurface;
float distSq = dot(unL, unL);
float dist = sqrt(distSq);
float3 L = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? unL * rsqrt(distSq) : -lightData.forward;
float NdotL = dot(bsdfData.normalWS, L);
float attenuation = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? GetDistanceAttenuation(unL, lightData.invSqrAttenuationRadius) : 1;
float attenuation = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius) : 1;
// Reminder: lights are oriented backward (-Z)
attenuation *= GetAngleAttenuation(L, -lightData.forward, lightData.angleScale, lightData.angleOffset);

{
// TODO: make projector lights cast shadows.
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float4 L_dist = { normalize( L.xyz ), length( unL ) };
float4 L_dist = { L, dist };
}
illuminance *= shadow;
}
#ifdef VOLUMETRIC_SHADOWING_ENABLED
shadow *= Transmittance(OpticalDepthHomogeneous(preLightData.globalFogExtinction, dist));
#endif
illuminance *= shadow;
// Projector lights always have a cookie.
[branch] if (lightData.cookieIndex >= 0)

8
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl


float4 _InvProjParam;
float4 _ScreenSize; // (w, h, 1/w, 1/h)
float4 _FrustumPlanes[6]; // (N, -dot(N, P))
// Volumetric lighting. Should be a struct in 'UnityPerFrame'.
// Unfortunately, we cannot modify the layout of 'UnityPerFrame',
// and structures inside constant buffers are not supported by Unity.
float3 _GlobalFog_Extinction;
float _GlobalFog_Asymmetry;
float3 _GlobalFog_Scattering;
float _GlobalFog_Align16;
CBUFFER_END
#ifdef USE_LEGACY_UNITY_MATRIX_VARIABLES

正在加载...
取消
保存