浏览代码

Changed the LDRenderLoop to define a minimal shadow setup instead of using the one from FPTL/HDRenderPipe. This will make it also easier for users to understand and provide example beyond the basic render loop.

/vr_sandbox
Felipe Lira 7 年前
当前提交
17101aa5
共有 5 个文件被更改,包括 506 次插入384 次删除
  1. 2
      Assets/LowEndRenderLoop/LowEndPipeline.asset
  2. 32
      Assets/LowEndRenderLoop/LowEndRenderLoopShader.shader
  3. 644
      Assets/LowEndRenderLoop/LowEndRenderLoopVikingVillage.unity
  4. 184
      Assets/LowEndRenderLoop/LowEndRenderPipeline.cs
  5. 28
      Assets/ScriptableRenderLoop/RenderPasses/ShadowRenderPass.cs

2
Assets/LowEndRenderLoop/LowEndPipeline.asset


m_SupportsVertexLight: 0
m_EnableLightmaps: 1
m_EnableAmbientProbe: 1
m_EnableShadowFiltering: 1
m_ShadowFiltering: 0

32
Assets/LowEndRenderLoop/LowEndRenderLoopShader.shader


#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ SHADOWS_DEPTH
#pragma multi_compile _ SHADOWS_FILTERING
#pragma multi_compile _ SHADOWS_FILTERING_PCF
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 d3d11_9x glcore gles gles3
#pragma enable_d3d11_debug_symbols

half4 globalLightAtten[MAX_LIGHTS];
int4 globalLightCount; // x: pixelLightCount, y = totalLightCount (pixel + vert)
sampler2D g_tShadowBuffer;
sampler2D _ShadowMap;
float _PCFKernel[8];
half4x4 _WorldToShadow[MAX_SHADOW_CASCADES];

inline half ShadowAttenuation(half2 shadowCoord, half shadowCoordDepth)
{
half depth = tex2D(g_tShadowBuffer, shadowCoord).r;
half depth = tex2D(_ShadowMap, shadowCoord).r;
#if defined(UNITY_REVERSED_Z)
return step(depth, shadowCoordDepth);
#else

inline half ShadowFilteredAttenuation(half4 shadowCoord)
inline half ShadowPCF(half4 shadowCoord)
{
// GPU Gems 4x4 kernel with 4 taps.
half2 offset = (float)(frac(shadowCoord.xy * 0.5) > 0.25); // mod

float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorld.xyz, 1.0));
shadowCoord.z = saturate(shadowCoord.z);
#ifdef SHADOWS_FILTERING
half shadowAttenuation = ShadowFilteredAttenuation(shadowCoord);
#ifdef SHADOWS_FILTERING_VSM
half shadowAttenuation = ShadowVSM(shadowCoord);
#elif defined(SHADOWS_FILTERING_PCF)
half shadowAttenuation = ShadowPCF(shadowCoord);
#else
half shadowAttenuation = ShadowAttenuation(shadowCoord.xy, shadowCoord.z);
#endif

INITIALIZE_LIGHT(mainLight, 0);
#if DEBUG_CASCADES
return half4(EvaluateMainLight(mainLight, diffuse, specular, normal, i.posWS, viewDir), 1.0);
return half4(EvaluateMainLight(mainLight, diffuse, specularGloss, normal, i.posWS, viewDir), 1.0);
half3 directColor = EvaluateMainLight(mainLight, diffuse, specularGloss, normal, i.posWS, viewDir);
half3 directColor = EvaluateMainLight(mainLight, diffuse, specularGloss, normal, i.posWS, viewDir);
// Compute direct contribution from additional lights.
for (int lightIndex = 1; lightIndex < globalLightCount.x; ++lightIndex)

#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ SHADOWS_FILTERING_VSM
float4 vert(float4 position : POSITION) : SV_POSITION
inline void ApplyLinearBias(half4 clipPos)
float4 clipPos = UnityObjectToClipPos(position);
return clipPos;
float4 vert(float4 position : POSITION) : SV_POSITION
{
float4 clipPos = UnityObjectToClipPos(position);
ApplyLinearBias(clipPos);
return clipPos;
}
half4 frag() : SV_TARGET
{
return 0;

644
Assets/LowEndRenderLoop/LowEndRenderLoopVikingVillage.unity
文件差异内容过多而无法显示
查看文件

184
Assets/LowEndRenderLoop/LowEndRenderPipeline.cs


{
private readonly LowEndRenderPipeline m_Asset;
ShadowRenderPass m_ShadowPass;
private const int MAX_CASCADES = 4;
private int m_ShadowMapProperty;
private int m_DepthBufferBits = 24;
ShadowSliceData[] m_ShadowSlices = new ShadowSliceData[MAX_CASCADES];
public LowEndRenderPipelineInstance(LowEndRenderPipeline asset)
{

m_ShadowPass = new ShadowRenderPass(m_ShadowSettings);
m_ShadowMapProperty = Shader.PropertyToID("_ShadowMap");
}
public override void Render(ScriptableRenderContext context, Camera[] cameras)

context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
ShadowOutput shadowOutput;
m_ShadowPass.Render(context, cull, out shadowOutput);
SetupShadowShaderVariables(shadowOutput, context, camera.nearClipPlane, cullingParameters.shadowDistance);
// Render Shadow Map
bool shadowsRendered = RenderShadows(cull, context);
// Draw Opaques with support to one directional shadow cascade
// Setup camera matrices
// Setup light and shadow shader constants
if (shadowsRendered)
SetupShadowShaderVariables(context, camera.nearClipPlane, cullingParameters.shadowDistance, m_ShadowSettings.directionalLightCascadeCount);
// Rende Opaques
var settings = new DrawRendererSettings(cull, camera, new ShaderPassName("LowEndForwardBase"));
settings.sorting.flags = SortFlags.CommonOpaque;
settings.inputFilter.SetQueuesOpaque();

settings.rendererConfiguration = settings.rendererConfiguration | RendererConfiguration.PerObjectLightProbe;
context.DrawRenderers(ref settings);
// TODO: Check skybox shader
// Rende Alpha blended
settings.sorting.flags = SortFlags.CommonTransparent;
settings.inputFilter.SetQueuesTransparent();
context.DrawRenderers(ref settings);

m_ShadowSettings.shadowAtlasHeight = m_Asset.ShadowAtlasResolution;
m_ShadowSettings.maxShadowDistance = QualitySettings.shadowDistance;
m_ShadowSettings.maxShadowLightsSupported = 1;
m_ShadowSettings.shadowType = ShadowSettings.ShadowType.LIGHTSPACE;
m_ShadowSettings.renderTextureFormat = RenderTextureFormat.Depth;
switch (m_ShadowSettings.directionalLightCascadeCount)
{

cmd.SetGlobalVectorArray("globalLightAtten", lightAttenuations);
cmd.SetGlobalVectorArray("globalLightSpotDir", lightSpotDirections);
cmd.SetGlobalVector("globalLightCount", new Vector4(pixelLightCount, totalLightCount, 0.0f, 0.0f));
SetShadowKeywords(cmd);
void SetupShadowShaderVariables(ShadowOutput shadowOutput, ScriptableRenderContext context, float shadowNear, float shadowFar)
private bool RenderShadows(CullResults cullResults, ScriptableRenderContext context)
int cascadeCount = m_ShadowSettings.directionalLightCascadeCount;
VisibleLight[] lights = cullResults.visibleLights;
int lightCount = lights.Length;
int shadowResolution = 0;
int lightIndex = -1;
float shadowBias = 0.0f;
for (int i = 0; i < lightCount; ++i)
{
if (lights[i].light.shadows != LightShadows.None && lights[i].lightType == LightType.Directional)
{
lightIndex = i;
shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.shadowAtlasWidth,
m_ShadowSettings.shadowAtlasHeight, cascadeCount);
shadowBias = lights[i].light.shadowBias;
break;
}
}
if (lightIndex < 0)
return false;
Bounds bounds;
if (!cullResults.GetShadowCasterBounds(lightIndex, out bounds))
return false;
var setRenderTargetCommandBuffer = new CommandBuffer();
setRenderTargetCommandBuffer.name = "Render packed shadows";
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowMapProperty, m_ShadowSettings.shadowAtlasWidth, m_ShadowSettings.shadowAtlasHeight, m_DepthBufferBits, FilterMode.Bilinear, RenderTextureFormat.Depth, RenderTextureReadWrite.Linear);
setRenderTargetCommandBuffer.SetRenderTarget(new RenderTargetIdentifier(m_ShadowMapProperty));
setRenderTargetCommandBuffer.ClearRenderTarget(true, true, Color.green);
context.ExecuteCommandBuffer(setRenderTargetCommandBuffer);
setRenderTargetCommandBuffer.Dispose();
float shadowNearPlane = QualitySettings.shadowNearPlaneOffset;
Vector3 splitRatio = m_ShadowSettings.directionalLightCascades;
for (int cascadeIdx = 0; cascadeIdx < cascadeCount; ++cascadeIdx)
{
Matrix4x4 view, proj;
var settings = new DrawShadowsSettings(cullResults, lightIndex);
bool needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(lightIndex, cascadeIdx, cascadeCount, splitRatio, shadowResolution, shadowNearPlane, out view, out proj, out settings.splitData);
if (needRendering)
{
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view);
RenderShadowSlice(ref context, cascadeIdx, proj, view, settings, shadowBias);
}
}
return true;
}
private void SetupShadowSliceTransform(int cascadeIndex, int shadowResolution, Matrix4x4 proj, Matrix4x4 view)
{
// Assumes MAX_CASCADES = 4
m_ShadowSlices[cascadeIndex].atlasX = (cascadeIndex % 2) * shadowResolution;
m_ShadowSlices[cascadeIndex].atlasY = (cascadeIndex / 2) * shadowResolution;
m_ShadowSlices[cascadeIndex].shadowResolution = shadowResolution;
m_ShadowSlices[cascadeIndex].shadowTransform = Matrix4x4.identity;
var matScaleBias = Matrix4x4.identity;
matScaleBias.m00 = 0.5f;
matScaleBias.m11 = 0.5f;
matScaleBias.m22 = 0.5f;
matScaleBias.m03 = 0.5f;
matScaleBias.m23 = 0.5f;
matScaleBias.m13 = 0.5f;
// Later down the pipeline the proj matrix will be scaled to reverse-z in case of DX.
// We need account for that scale in the shadowTransform.
if (SystemInfo.usesReversedZBuffer)
matScaleBias.m22 = -0.5f;
var matTile = Matrix4x4.identity;
matTile.m00 = (float)m_ShadowSlices[cascadeIndex].shadowResolution / (float)m_ShadowSettings.shadowAtlasWidth;
matTile.m11 = (float)m_ShadowSlices[cascadeIndex].shadowResolution / (float)m_ShadowSettings.shadowAtlasHeight;
matTile.m03 = (float)m_ShadowSlices[cascadeIndex].atlasX / (float)m_ShadowSettings.shadowAtlasWidth;
matTile.m13 = (float)m_ShadowSlices[cascadeIndex].atlasY / (float)m_ShadowSettings.shadowAtlasHeight;
m_ShadowSlices[cascadeIndex].shadowTransform = matTile * matScaleBias * proj * view;
}
private void RenderShadowSlice(ref ScriptableRenderContext context, int cascadeIndex, Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings, float shadowBias)
{
var buffer = new CommandBuffer() { name = "RenderShadowMap" };
buffer.SetViewport(new Rect(m_ShadowSlices[cascadeIndex].atlasX, m_ShadowSlices[cascadeIndex].atlasY, m_ShadowSlices[cascadeIndex].shadowResolution, m_ShadowSlices[cascadeIndex].shadowResolution));
buffer.SetViewProjectionMatrices(view, proj);
buffer.SetGlobalVector("_ShadowBias", new Vector4(shadowBias, 0.0f, 0.0f, 0.0f));
context.ExecuteCommandBuffer(buffer);
buffer.Dispose();
context.DrawShadows(ref settings);
}
private int GetMaxTileResolutionInAtlas(int atlasWidth, int atlasHeight, int tileCount)
{
int resolution = Mathf.Min(atlasWidth, atlasHeight);
if (tileCount > Mathf.Log(resolution))
{
//Debug.LogError(String.Format("Cannot fit {0} tiles into current shadowmap atlas of size ({1}, {2}). ShadowMap Resolution set to zero.", tileCount, atlasWidth, atlasHeight));
return 0;
}
int currentTileCount = atlasWidth / resolution * atlasHeight / resolution;
while (currentTileCount < tileCount)
{
resolution = resolution >> 1;
currentTileCount = atlasWidth / resolution * atlasHeight / resolution;
}
return resolution;
}
void SetupShadowShaderVariables(ScriptableRenderContext context, float shadowNear, float shadowFar, int cascadeCount)
{
float shadowResolution = m_ShadowSlices[0].shadowResolution;
ShadowSliceData[] shadowSlices = shadowOutput.shadowSlices;
if (shadowSlices == null)
return;
1.0f / shadowSlices[0].shadowResolution);
1.0f / shadowResolution);
int shadowSliceCount = shadowSlices.Length;
for (int i = 0; i < shadowSliceCount; ++i)
shadowMatrices[i] = (shadowSliceCount >= i) ? shadowSlices[i].shadowTransform : Matrix4x4.identity;
for (int i = 0; i < cascadeCount; ++i)
shadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity;
float invShadowResolution = 1.0f / shadowSlices[0].shadowResolution;
float invShadowResolution = 1.0f / shadowResolution;
float[] pcfKernel = {-1.5f * invShadowResolution, 0.5f * invShadowResolution,
0.5f * invShadowResolution, 0.5f * invShadowResolution,
-1.5f * invShadowResolution, -0.5f * invShadowResolution,

setupShadow.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices);
setupShadow.SetGlobalVector("_PSSMDistancesAndShadowResolution", PSSMDistances);
setupShadow.SetGlobalFloatArray("_PCFKernel", pcfKernel);
SetShadowKeywords(setupShadow);
context.ExecuteCommandBuffer(setupShadow);
setupShadow.Dispose();
}

else
cmd.EnableShaderKeyword("SHADOWS_DEPTH");
if (m_Asset.EnableShadowFiltering)
cmd.EnableShaderKeyword("SHADOWS_FILTERING");
else
cmd.DisableShaderKeyword("SHADOWS_FILTERING");
switch (m_Asset.CurrShadowFiltering)
{
case LowEndRenderPipeline.ShadowFiltering.PCF:
cmd.EnableShaderKeyword("SHADOWS_FILTERING_PCF");
break;
default:
cmd.DisableShaderKeyword("SHADOWS_FILTERING_PCF");
break;
}
}
#endregion
}

{
return new LowEndRenderPipelineInstance(this);
}
#endregion
#endregion
public enum ShadowFiltering
{
PCF = 0,
NONE
}
public bool m_EnableShadowFiltering = false;
public ShadowFiltering m_ShadowFiltering = ShadowFiltering.NONE;
public bool SupportsVertexLight { get { return m_SupportsVertexLight;} private set { m_SupportsVertexLight = value; } }

public bool EnableShadowFiltering { get { return m_EnableShadowFiltering; } private set { m_EnableShadowFiltering = value; } }
public ShadowFiltering CurrShadowFiltering { get { return m_ShadowFiltering; } private set { m_ShadowFiltering = value; } }
public int ShadowAtlasResolution { get { return m_ShadowAtlasResolution; } private set { m_ShadowAtlasResolution = value; } }
#endregion

28
Assets/ScriptableRenderLoop/RenderPasses/ShadowRenderPass.cs


[System.Serializable]
public class ShadowSettings
{
public enum ShadowType : int
{
SCREENSPACE = 0,
LIGHTSPACE,
SHADOWTYPE_COUNT
}
public bool enabled;
public int shadowAtlasWidth;
public int shadowAtlasHeight;

public Vector3 directionalLightCascades;
public int maxShadowLightsSupported;
public RenderTextureFormat renderTextureFormat;
public ShadowType shadowType;
public static ShadowSettings Default
{

settings.directionalLightCascades = new Vector3(0.05F, 0.2F, 0.3F);
settings.directionalLightCascadeCount = 4;
settings.maxShadowDistance = 1000.0F;
settings.maxShadowLightsSupported = -1;
settings.renderTextureFormat = RenderTextureFormat.Shadowmap;
settings.shadowType = ShadowType.SCREENSPACE;
return settings;
}
}

AdditionalLightData additionalLight = lights[i].light.GetComponent<AdditionalLightData>();
int shadowResolution;
if (settings.shadowType != ShadowSettings.ShadowType.LIGHTSPACE)
shadowResolution = AdditionalLightData.GetShadowResolution(additionalLight);
else
shadowResolution = GetMaxTileResolutionInAtlas(settings.shadowAtlasWidth, settings.shadowAtlasHeight, settings.directionalLightCascadeCount);
shadowResolution = AdditionalLightData.GetShadowResolution(additionalLight);
InputShadowLightData light;
light.lightIndex = i;

var setRenderTargetCommandBuffer = new CommandBuffer();
setRenderTargetCommandBuffer.name = "Render packed shadows";
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowTexName, m_Settings.shadowAtlasWidth, m_Settings.shadowAtlasHeight, k_DepthBuffer, FilterMode.Bilinear, m_Settings.renderTextureFormat, RenderTextureReadWrite.Linear);
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowTexName, m_Settings.shadowAtlasWidth, m_Settings.shadowAtlasHeight, k_DepthBuffer, FilterMode.Bilinear, RenderTextureFormat.Shadowmap, RenderTextureReadWrite.Linear);
setRenderTargetCommandBuffer.SetRenderTarget(new RenderTargetIdentifier(m_ShadowTexName));
setRenderTargetCommandBuffer.ClearRenderTarget(true, true, Color.green);

matScaleBias.m23 = 0.5f;
matScaleBias.m13 = 0.5f;
// Later down the pipeline the proj matrix will be scaled to reverse-z in case of DX.
// We need account for that scale in the shadowTransform.
if (m_Settings.shadowType == ShadowSettings.ShadowType.LIGHTSPACE && SystemInfo.usesReversedZBuffer)
matScaleBias.m22 = -0.5f;
var matTile = Matrix4x4.identity;
matTile.m00 = (float)lightData.shadowResolution / (float)m_Settings.shadowAtlasWidth;
matTile.m11 = (float)lightData.shadowResolution / (float)m_Settings.shadowAtlasHeight;

//commandBuffer.ClearRenderTarget (true, true, Color.green);
commandBuffer.SetViewProjectionMatrices(view, proj);
if (m_Settings.shadowType == ShadowSettings.ShadowType.LIGHTSPACE)
commandBuffer.SetGlobalVector("_ShadowBias", new Vector4(shadowBias, 0.0f, 0.0f, 0.0f));
else
commandBuffer.SetGlobalVector("g_vLightDirWs", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z));
commandBuffer.SetGlobalVector("g_vLightDirWs", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z));
// commandBuffer.SetGlobalDepthBias (1.0F, 1.0F);

正在加载...
取消
保存