浏览代码

Removed shadow sampling from loop, shadow bias taken from light, improved shadow algorithm

/RenderPassXR_Sandbox
Felipe Lira 8 年前
当前提交
94744828
共有 7 个文件被更改,包括 94 次插入95 次删除
  1. 5
      Assets/ScriptableRenderPipeline/LightweightPipeline/Editor/LightweightAssetInspector.cs
  2. 82
      Assets/ScriptableRenderPipeline/LightweightPipeline/LightweightPipeline.cs
  3. 2
      Assets/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset
  4. 18
      Assets/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.cs
  5. 35
      Assets/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPipeline.shader
  6. 20
      Assets/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPipelineCore.cginc
  7. 27
      Assets/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPipelineShadows.cginc

5
Assets/ScriptableRenderPipeline/LightweightPipeline/Editor/LightweightAssetInspector.cs


public static GUIContent shadowDistante = new GUIContent("Shadow Distance", "Max shadow drawing distance");
public static GUIContent shadowMinBias = new GUIContent("Shadow Min Normal Bias Offset", "Minimum value of normal bias offset applied");
public static GUIContent shadowBias = new GUIContent("Shadow Normal Bias", "Normal bias offset value.");
public static GUIContent shadowAtlasResolution = new GUIContent("Shadow Map Resolution",
"Resolution of shadow map texture. If cascades are enabled all cascades will be packed into this texture resolution.");

EditorGUILayout.PropertyField(m_ShadowTypeProp, Styles.shadowType);
EditorGUILayout.PropertyField(m_ShadowAtlasResolutionProp, Styles.shadowAtlasResolution);
EditorGUILayout.PropertyField(m_ShadowNearPlaneOffsetProp, Styles.shadowNearPlaneOffset);
EditorGUILayout.PropertyField(m_ShadowMinNormalBiasProperty, Styles.shadowMinBias);
EditorGUILayout.PropertyField(m_ShadowNormalBiasProperty, Styles.shadowBias);
EditorGUILayout.PropertyField(m_ShadowDistanceProp, Styles.shadowDistante);
EditorGUILayout.PropertyField(m_ShadowCascadesProp, Styles.shadowCascades);

82
Assets/ScriptableRenderPipeline/LightweightPipeline/LightweightPipeline.cs


{
public int pixelLightsCount;
public int vertexLightsCount;
public int shadowLightIndex;
public bool shadowsRendered;
}
public class LightweightPipeline : RenderPipeline

private static readonly int kMaxCascades = 4;
private int m_ShadowCasterCascadesCount = kMaxCascades;
private int m_ShadowMapProperty;
private int m_ShadowLightIndex = -1;
private int m_DepthBufferBits = 24;
private int m_DepthBufferBits = 16;
private Vector4[] m_DirectionalShadowSplitDistances = new Vector4[kMaxCascades];
private ShadowSettings m_ShadowSettings = ShadowSettings.Default;

if (!CullResults.GetCullingParameters(camera, out cullingParameters))
continue;
cullingParameters.shadowDistance = m_ShadowSettings.maxShadowDistance;
cullingParameters.shadowDistance = Mathf.Min(m_ShadowSettings.maxShadowDistance, camera.farClipPlane);
CullResults cullResults = CullResults.Cull(ref cullingParameters, context);
VisibleLight[] visibleLights = cullResults.visibleLights;

// Render Shadow Map
bool shadowsRendered = false;
InitializeMainShadowLightIndex(visibleLights);
if (m_ShadowLightIndex > -1)
shadowsRendered = RenderShadows(ref cullResults, ref visibleLights[m_ShadowLightIndex], ref context);
if (lightData.shadowLightIndex > -1)
lightData.shadowsRendered = RenderShadows(ref cullResults, ref visibleLights[lightData.shadowLightIndex], lightData.shadowLightIndex, ref context);
// Setup camera matrices and RT
context.SetupCameraProperties(camera);

cmd.Dispose();
// Setup light and shadow shader constants
SetupShaderLightConstants(visibleLights, ref cullResults, ref context, ref lightData);
if (shadowsRendered)
SetupShadowShaderVariables(ref context, m_ShadowCasterCascadesCount);
SetupShaderLightConstants(visibleLights, ref lightData, ref cullResults, ref context);
if (lightData.shadowsRendered)
SetupShadowShaderConstants(ref context, ref visibleLights[lightData.shadowLightIndex], lightData.shadowLightIndex, m_ShadowCasterCascadesCount);
SetShaderKeywords(ref lightData, ref context);
RendererConfiguration configuration = RendererConfiguration.PerObjectReflectionProbes;
if (m_Asset.EnableLightmap)

lightData.pixelLightsCount = Mathf.Min(lightsCount, m_Asset.MaxSupportedPixelLights);
lightData.vertexLightsCount = (m_Asset.SupportsVertexLight) ? Mathf.Min(lightsCount - lightData.pixelLightsCount, kMaxVertexLights) : 0;
lightData.isSingleDirectionalLight = lightData.pixelLightsCount == 1 && lightData.vertexLightsCount == 0 && lights[0].lightType == LightType.Directional;
lightData.shadowsRendered = false;
InitializeMainShadowLightIndex(lights, out lightData.shadowLightIndex);
}
private void FillLightIndices(ref CullResults cullResults, int visibleLightsCount)

cullResults.FillLightIndices(m_LightIndexListBuffer);
}
private void SetupShaderLightConstants(VisibleLight[] lights, ref CullResults cullResults, ref ScriptableRenderContext context, ref LightData lightData)
private void SetupShaderLightConstants(VisibleLight[] lights, ref LightData lightData, ref CullResults cullResults, ref ScriptableRenderContext context)
SetupShaderLightListConstants(lights, ref cullResults, ref context);
CommandBuffer cmd = new CommandBuffer() { name = "SetShaderKeywords" };
SetShaderKeywords(cmd, lightData.isSingleDirectionalLight, lightData.vertexLightsCount > 0);
cmd.SetGlobalVector("globalLightData", new Vector4(lightData.pixelLightsCount, m_ShadowLightIndex, m_Asset.ShadowMinNormalBias, m_Asset.ShadowNormalBias));
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
SetupShaderLightListConstants(lights, lightData.pixelLightsCount, ref cullResults, ref context);
}
private void SetupShaderSingleDirectionalLightConstants(ref VisibleLight light, ref ScriptableRenderContext context)

}
// TODO: Perform tests on light lights memory pattern access (SOA vs AOS vs Swizzling)
private void SetupShaderLightListConstants(VisibleLight[] lights, ref CullResults cullResults, ref ScriptableRenderContext context)
private void SetupShaderLightListConstants(VisibleLight[] lights, int pixelLightsCount, ref CullResults cullResults, ref ScriptableRenderContext context)
{
FillLightIndices(ref cullResults, lights.Length);
int maxLights = Math.Min(kMaxVisibleLights, lights.Length);

}
CommandBuffer cmd = new CommandBuffer () { name = "SetupShadowShaderConstants" };
cmd.SetGlobalVector("globalLightCount", new Vector4 (pixelLightsCount, 0.0f, 0.0f, 0.0f));
cmd.SetGlobalBuffer ("globalLightIndexList", m_LightIndexListBuffer);
cmd.SetGlobalBuffer("globalLightIndexList", m_LightIndexListBuffer);
private bool RenderShadows(ref CullResults cullResults, ref VisibleLight shadowLight, ref ScriptableRenderContext context)
private void SetShaderKeywords(ref LightData lightData, ref ScriptableRenderContext context)
{
CommandBuffer cmd = new CommandBuffer() { name = "SetShaderKeywords" };
SetShaderKeywords(cmd, lightData.shadowsRendered, lightData.isSingleDirectionalLight, lightData.vertexLightsCount > 0);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
private bool RenderShadows(ref CullResults cullResults, ref VisibleLight shadowLight, int shadowLightIndex, ref ScriptableRenderContext context)
{
m_ShadowCasterCascadesCount = m_ShadowSettings.directionalLightCascadeCount;

int shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.shadowAtlasWidth, m_ShadowSettings.shadowAtlasHeight, m_ShadowCasterCascadesCount);
Bounds bounds;
if (!cullResults.GetShadowCasterBounds(m_ShadowLightIndex, out bounds))
if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds))
return false;
var setRenderTargetCommandBuffer = new CommandBuffer();

float shadowNearPlane = m_Asset.ShadowNearOffset;
Vector3 splitRatio = m_ShadowSettings.directionalLightCascades;
Vector3 lightDir = Vector3.Normalize(shadowLight.light.transform.forward);
var settings = new DrawShadowsSettings(cullResults, m_ShadowLightIndex);
var settings = new DrawShadowsSettings(cullResults, shadowLightIndex);
needRendering = cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(m_ShadowLightIndex, out view, out proj,
needRendering = cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(shadowLightIndex, out view, out proj,
out settings.splitData);
if (!needRendering)

RenderShadowSlice(ref context, lightDir, 0, proj, view, settings);
RenderShadowSlice(ref context, 0, proj, view, settings);
needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(m_ShadowLightIndex,
needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(shadowLightIndex,
cascadeIdx, m_ShadowCasterCascadesCount, splitRatio, shadowResolution, shadowNearPlane, out view, out proj,
out settings.splitData);

return false;
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view);
RenderShadowSlice(ref context, lightDir, cascadeIdx, proj, view, settings);
RenderShadowSlice(ref context, cascadeIdx, proj, view, settings);
}
}
else

m_ShadowSlices[cascadeIndex].shadowTransform = matTile * matScaleBias * proj * view;
}
private void RenderShadowSlice(ref ScriptableRenderContext context, Vector3 lightDir, int cascadeIndex,
private void RenderShadowSlice(ref ScriptableRenderContext context, int cascadeIndex,
Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings)
{
var buffer = new CommandBuffer() {name = "Prepare Shadowmap Slice"};

return resolution;
}
private void SetupShadowShaderVariables(ref ScriptableRenderContext context, int cascadeCount)
private void SetupShadowShaderConstants(ref ScriptableRenderContext context, ref VisibleLight shadowLight, int shadowLightIndex, int cascadeCount)
Vector3 shadowLightDir = Vector3.Normalize(shadowLight.localToWorld.GetColumn(2));
// TODO: multiplying by 0.1 to get similar results to Unity vanilla shadow bias
float bias = shadowLight.light.shadowBias * 0.1f;
float normalBias = shadowLight.light.shadowNormalBias;
float shadowResolution = m_ShadowSlices[0].shadowResolution;
const int maxShadowCascades = 4;

var setupShadow = new CommandBuffer() {name = "SetupShadowShaderConstants"};
setupShadow.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices);
setupShadow.SetGlobalVectorArray("_DirShadowSplitSpheres", m_DirectionalShadowSplitDistances);
setupShadow.SetGlobalVector("_ShadowLightDirection", new Vector4(-shadowLightDir.x, -shadowLightDir.y, -shadowLightDir.z, 0.0f));
setupShadow.SetGlobalVector("_ShadowData", new Vector4(shadowLightIndex, bias, normalBias, 0.0f));
private void SetShaderKeywords(CommandBuffer cmd, bool singleDirecitonal, bool vertexLightSupport)
private void SetShaderKeywords(CommandBuffer cmd, bool renderShadows, bool singleDirecitonal, bool vertexLightSupport)
{
if (vertexLightSupport)
cmd.EnableShaderKeyword("_VERTEX_LIGHTS");

for (int i = 0; i < shadowKeywords.Length; ++i)
cmd.DisableShaderKeyword(shadowKeywords[i]);
if (m_ShadowLightIndex != -1 && m_Asset.CurrShadowType != ShadowType.NO_SHADOW)
if (renderShadows && m_Asset.CurrShadowType != ShadowType.NO_SHADOW)
{
int keywordIndex = (int)m_Asset.CurrShadowType - 1;
if (m_Asset.CascadeCount > 1)

cmd.DisableShaderKeyword("_LIGHT_PROBES_ON");
}
private void InitializeMainShadowLightIndex(VisibleLight[] lights)
private void InitializeMainShadowLightIndex(VisibleLight[] lights, out int shadowIndex)
m_ShadowLightIndex = -1;
shadowIndex = -1;
float maxIntensity = -1;
for (int i = 0; i < lights.Length; ++i)
{

m_ShadowLightIndex = i;
shadowIndex = i;
maxIntensity = light.intensity;
}
}

2
Assets/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.asset


m_ShadowAtlasResolution: 1024
m_ShadowNearPlaneOffset: 2
m_ShadowDistance: 50
m_MinShadowNormalBias: 0.0005
m_ShadowNormalBias: 0.05
m_ShadowCascades: 1
m_Cascade2Split: 0.25
m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467}

18
Assets/ScriptableRenderPipeline/LightweightPipeline/LightweightPipelineAsset.cs


private static readonly string m_AssetName = "LightweightPipelineAsset.asset";
#if UNITY_EDITOR
[UnityEditor.MenuItem("RenderPipeline/LightweightPipeline/Create Pipeline Asset")]
[UnityEditor.MenuItem("RenderPipeline/LightweightPipeline/Create Pipeline Asset", false, 15)]
static void CreateLightweightPipeline()
{
var instance = ScriptableObject.CreateInstance<LightweightPipelineAsset>();

[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024;
[SerializeField] private float m_ShadowNearPlaneOffset = 2.0f;
[SerializeField] private float m_ShadowDistance = 50.0f;
[SerializeField] private float m_MinShadowNormalBias = 0.0005f;
[SerializeField] private float m_ShadowNormalBias = 0.05f;
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES;
[SerializeField] private float m_Cascade2Split = 0.25f;
[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f);

private set { m_ShadowDistance = value; }
}
public float ShadowMinNormalBias
{
get { return m_MinShadowNormalBias; }
private set { m_MinShadowNormalBias = value; }
}
public float ShadowNormalBias
{
get { return m_ShadowNormalBias; }
private set { m_ShadowNormalBias = value; }
}
public float Cascade2Split
{
get { return m_Cascade2Split; }

35
Assets/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPipeline.shader


#if defined(_VERTEX_LIGHTS) && !defined(_SINGLE_DIRECTIONAL_LIGHT)
half4 diffuseAndSpecular = half4(1.0, 1.0, 1.0, 1.0);
int vertexLightStart = unity_LightIndicesOffsetAndCount.x + globalLightData.x;
int vertexLightEnd = vertexLightStart + (unity_LightIndicesOffsetAndCount.y - globalLightData.x);
int vertexLightStart = unity_LightIndicesOffsetAndCount.x + globalLightCount.x;
int vertexLightEnd = vertexLightStart + (unity_LightIndicesOffsetAndCount.y - globalLightCount.x);
half NdotL;
o.fogCoord.yzw += EvaluateOneLight(lightInput, diffuseAndSpecular.rgb, diffuseAndSpecular, normal, o.posWS, o.viewDir.xyz, NdotL);
o.fogCoord.yzw += EvaluateOneLight(lightInput, diffuseAndSpecular.rgb, diffuseAndSpecular, normal, o.posWS, o.viewDir.xyz);
}
#endif

half3 viewDir = i.viewDir.xyz;
half3 color = half3(0, 0, 0);
half NdotL;
color = EvaluateDirectionalLight(diffuse, specularGloss, normal, _LightPosition0, viewDir, NdotL) * _LightColor0;
half3 color = EvaluateDirectionalLight(diffuse, specularGloss, normal, _LightPosition0, viewDir) * _LightColor0;
float bias = max(globalLightData.z, (1.0 - NdotL) * globalLightData.w);
color *= ComputeShadowAttenuation(i, bias);
color *= ComputeShadowAttenuation(i, _LightPosition0.xyz);
int pixelLightEnd = unity_LightIndicesOffsetAndCount.x + min(globalLightData.x, unity_LightIndicesOffsetAndCount.y);
half3 color = half3(0, 0, 0);
#ifdef _SHADOWS
half shadowAttenuation = ComputeShadowAttenuation(i, _ShadowLightDirection.xyz);
#endif
int pixelLightEnd = unity_LightIndicesOffsetAndCount.x + min(globalLightCount.x, unity_LightIndicesOffsetAndCount.y);
half NdotL;
color += EvaluateOneLight(lightData, diffuse, specularGloss, normal, i.posWS, viewDir, NdotL);
if (lightIndex == globalLightData.y)
{
float bias = max(globalLightData.z, (1.0 - NdotL) * globalLightData.w);
color *= ComputeShadowAttenuation(i, bias);
}
// multiplies shadowAttenuation to avoid branching.
// step will only evaluate to 1 when lightIndex == _ShadowData.x (shadowLightIndex)
half currLightAttenuation = shadowAttenuation * step(abs(lightIndex - _ShadowData.x), 0);
color += EvaluateOneLight(lightData, diffuse, specularGloss, normal, i.posWS, viewDir) * currLightAttenuation;
#else
color += EvaluateOneLight(lightData, diffuse, specularGloss, normal, i.posWS, viewDir);
#endif
}

float4 vert(float4 pos : POSITION) : SV_POSITION
{
float4 clipPos = UnityObjectToClipPos(pos);
float4 clipPos = UnityObjectToClipPos(pos);
#if defined(UNITY_REVERSED_Z)
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE);
#else

20
Assets/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPipelineCore.cginc


// The variables are very similar to built-in unity_LightColor, unity_LightPosition,
// unity_LightAtten, unity_SpotDirection as used by the VertexLit shaders, except here
// we use world space positions instead of view space.
half4 globalLightCount;
half4 globalLightColor[MAX_VISIBLE_LIGHTS];
float4 globalLightPos[MAX_VISIBLE_LIGHTS];
half4 globalLightSpotDir[MAX_VISIBLE_LIGHTS];

#endif
float4 globalLightData; // x: pixelLightCount, y = shadowLightIndex, z = minShadowNormalBiasOffset, w = shadowNormalBiasOffset
half _Shininess;
samplerCUBE _Cube;
half4 _ReflectColor;

#endif
}
inline half3 EvaluateDirectionalLight(half3 diffuseColor, half4 specularGloss, half3 normal, half3 lightDir, half3 viewDir, out half NdotL)
inline half3 EvaluateDirectionalLight(half3 diffuseColor, half4 specularGloss, half3 normal, half3 lightDir, half3 viewDir)
NdotL = saturate(dot(normal, lightDir));
half3 diffuse = diffuseColor * NdotL;
half NdotL = saturate(dot(normal, lightDir));
half3 diffuse = diffuseColor * NdotL;
half3 halfVec = normalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 specular = specularGloss.rgb * pow(NdotH, _Shininess * 128.0) * specularGloss.a;
half3 halfVec = normalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 specular = specularGloss.rgb * pow(NdotH, _Shininess * 128.0) * specularGloss.a;
return diffuse;
return diffuse;
inline half3 EvaluateOneLight(LightInput lightInput, half3 diffuseColor, half4 specularGloss, half3 normal, float3 posWorld, half3 viewDir, out half NdotL)
inline half3 EvaluateOneLight(LightInput lightInput, half3 diffuseColor, half4 specularGloss, half3 normal, float3 posWorld, half3 viewDir)
{
float3 posToLight = lightInput.pos.xyz;
posToLight -= posWorld * lightInput.pos.w;

half cutoff = step(distanceSqr, lightInput.atten.w);
lightAtten *= cutoff;
NdotL = saturate(dot(normal, lightDir));
half NdotL = saturate(dot(normal, lightDir));
half3 lightColor = lightInput.color.rgb * lightAtten;
half3 diffuse = diffuseColor * lightColor * NdotL;

27
Assets/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPipelineShadows.cginc


float _PCFKernel[8];
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES];
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES];
half4 _ShadowData;
// In case of single directional light, shadow light dir is the same of light dir
#ifndef _SINGLE_DIRECTIONAL_LIGHT
half4 _ShadowLightDirection;
#endif
inline half ShadowAttenuation(float3 shadowCoord)
{

float depth = tex2D(_ShadowMap, shadowCoord).r;
return step(depth, shadowCoord.z);
return step(depth - _ShadowData.y, shadowCoord.z);
return step(shadowCoord.z, depth);
return step(shadowCoord.z, depth + _ShadowData.y);
#endif
}

return attenuation * 0.25;
}
inline half ComputeShadowAttenuation(v2f i, float bias)
inline half ComputeShadowAttenuation(v2f i, half3 shadowDir)
float3 vertexNormal = float3(i.tangentToWorld0.z, i.tangentToWorld1.z, i.tangentToWorld2.z);
half3 vertexNormal = half3(i.tangentToWorld0.z, i.tangentToWorld1.z, i.tangentToWorld2.z);
float3 vertexNormal = i.normal;
half3 vertexNormal = i.normal;
float3 offset = vertexNormal * bias;
half NdotL = dot(vertexNormal, shadowDir);
half bias = saturate(1.0 - NdotL) * _ShadowData.z;
float3 posWorldOffsetNormal = i.posWS + vertexNormal * bias;
float3 posWorldOffsetNormal = i.posWS + offset;
cascadeIndex = ComputeCascadeIndex(i.posWS);
cascadeIndex = ComputeCascadeIndex(posWorldOffsetNormal);
if (cascadeIndex >= MAX_SHADOW_CASCADES)
return 1.0;
#endif

正在加载...
取消
保存