浏览代码

Fixed shadow bias. Moved PCF filtering to _SOFT_SHADOWS. Made a few settings more user friendly.

/vr_sandbox
Felipe Lira 7 年前
当前提交
45ce8af5
共有 5 个文件被更改,包括 133 次插入79 次删除
  1. 50
      Assets/LowEndRenderPipeline/Editor/LDRenderPipelineInspector.cs
  2. 2
      Assets/LowEndRenderPipeline/LDRenderPipelineBasicScene.unity
  3. 8
      Assets/LowEndRenderPipeline/LowEndPipeline.asset
  4. 77
      Assets/LowEndRenderPipeline/LowEndRenderPipeline.cs
  5. 75
      Assets/LowEndRenderPipeline/Shaders/LDRenderPipe-Specular.shader

50
Assets/LowEndRenderPipeline/Editor/LDRenderPipelineInspector.cs


public static GUIContent renderingLabel = new GUIContent("Rendering");
public static GUIContent shadowLabel = new GUIContent("Shadows");
public static GUIContent enableVertexLightLabel = new GUIContent("Enable Vertex Light");
public static GUIContent enableLightmap = new GUIContent("Enable Lightmap");
public static GUIContent enableAmbientProbe = new GUIContent("Enable Ambient Probe");
public static GUIContent shadowType = new GUIContent("Shadow Type");
public static GUIContent shadowNearPlaneOffset = new GUIContent("Shadow Near Plane Offset");
public static GUIContent shadowDistante = new GUIContent("Shadow Distance");
public static GUIContent shadowAtlasResolution = new GUIContent("Shadow Atlas Resolution");
public static GUIContent shadowCascades = new GUIContent("Shadow Cascades");
public static GUIContent shadowCascadeSplit = new GUIContent("Shadow Cascade Split");
public static GUIContent shadowFiltering = new GUIContent("Shadow Filtering");
public static GUIContent maxPixelLights = new GUIContent("Max per-pixel lights supported", "Amount of dynamic lights processed in fragment shader. More than 1 per-pixel light is not recommended.");
public static GUIContent enableVertexLightLabel = new GUIContent("Enable Vertex Light", "Enable up to 4 per-vertex dynamic lights.");
public static GUIContent enableLightmap = new GUIContent("Enable Lightmap", "Only non-directional lightmaps are supported");
public static GUIContent enableAmbientProbe = new GUIContent("Enable Ambient Probe", "Uses light probes as ambient light source for non-lightmapped objects.");
public static GUIContent shadowType = new GUIContent("Shadow Type", "Single directional shadow supported. SOFT_SHADOWS applies shadow filtering.");
public static GUIContent shadowNearPlaneOffset = new GUIContent("Shadow Near Plane Offset", "Offset shadow near plane to account for large triangles being distorted by pancaking");
public static GUIContent shadowDistante = new GUIContent("Shadow Distance", "Max shadow drawing distance");
public static GUIContent shadowBias = new GUIContent("Shadow Bias");
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.");
public static GUIContent shadowCascades = new GUIContent("Shadow Cascades", "Number of cascades for directional shadows");
public static GUIContent shadowCascadeSplit = new GUIContent("Shadow Cascade Split", "Percentages to split shadow volume");
private SerializedProperty m_MaxPixelLights;
private SerializedProperty m_ShadowBiasProperty;
private SerializedProperty m_CascadeSplitProp;
private SerializedProperty m_ShadowFilteringProp;
private SerializedProperty m_ShadowCascade2SplitProp;
private SerializedProperty m_ShadowCascade4SplitProp;
m_MaxPixelLights = serializedObject.FindProperty("m_MaxPixelLights");
m_ShadowBiasProperty = serializedObject.FindProperty("m_ShadowBias");
m_CascadeSplitProp = serializedObject.FindProperty("m_CascadeSplit");
m_ShadowFilteringProp = serializedObject.FindProperty("m_ShadowFiltering");
m_ShadowCascade2SplitProp = serializedObject.FindProperty("m_Cascade2Split");
m_ShadowCascade4SplitProp = serializedObject.FindProperty("m_Cascade4Split");
}
public override void OnInspectorGUI()

EditorGUILayout.Space();
EditorGUILayout.LabelField(Styles.renderingLabel, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_MaxPixelLights, Styles.maxPixelLights);
EditorGUILayout.PropertyField(m_SupportsVertexLightProp, Styles.enableVertexLightLabel);
EditorGUILayout.PropertyField(m_EnableLightmapsProp, Styles.enableLightmap);
EditorGUILayout.PropertyField(m_EnableAmbientProbeProp, Styles.enableAmbientProbe);

EditorGUILayout.LabelField(Styles.shadowLabel, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_ShadowTypeProp, Styles.shadowType);
EditorGUILayout.PropertyField(m_ShadowAtlasResolutionProp, Styles.shadowAtlasResolution);
EditorGUILayout.PropertyField(m_ShadowBiasProperty, Styles.shadowBias);
EditorGUILayout.PropertyField(m_ShadowAtlasResolutionProp, Styles.shadowAtlasResolution);
EditorGUILayout.PropertyField(m_CascadeSplitProp, Styles.shadowCascadeSplit);
EditorGUILayout.PropertyField(m_ShadowFilteringProp, Styles.shadowFiltering);
LowEndRenderPipeline.ShadowCascades cascades = (LowEndRenderPipeline.ShadowCascades) m_ShadowCascadesProp.intValue;
if (cascades == LowEndRenderPipeline.ShadowCascades.FOUR_CASCADES)
{
EditorGUILayout.PropertyField(m_ShadowCascade4SplitProp, Styles.shadowCascadeSplit);
}
else if (cascades == LowEndRenderPipeline.ShadowCascades.TWO_CASCADES)
{
EditorGUILayout.PropertyField(m_ShadowCascade2SplitProp, Styles.shadowCascadeSplit);
}
EditorGUI.indentLevel--;
serializedObject.ApplyModifiedProperties();

2
Assets/LowEndRenderPipeline/LDRenderPipelineBasicScene.unity


m_PVRFilteringAtrousPositionSigma: 1
m_LightingDataAsset: {fileID: 112000002, guid: 740b181ab47c46a47ae28377711d7097,
type: 2}
m_ShadowMaskMode: 2
m_ShadowMaskMode: 0
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2

8
Assets/LowEndRenderPipeline/LowEndPipeline.asset


m_Script: {fileID: 11500000, guid: ae13646e45aa3634da32df7c7da1c380, type: 3}
m_Name: LowEndPipeline
m_EditorClassIdentifier:
m_MaxPixelLights: 1
m_ShadowAtlasResolution: 1024
m_ShadowAtlasResolution: 1024
m_ShadowBias: 0.07
m_CascadeSplit: {x: 0.067, y: 0.2, z: 0.467}
m_ShadowFiltering: 1
m_Cascade2Split: 0.25
m_Cascade4Split: {x: 0.2, y: 0.5, z: 0.7}

77
Assets/LowEndRenderPipeline/LowEndRenderPipeline.cs


break;
case 2:
m_ShadowSettings.directionalLightCascades = new Vector3(m_Asset.CascadeSplit.x, 1.0f, 0.0f);
m_ShadowSettings.directionalLightCascades = new Vector3(m_Asset.Cascade2Split, 1.0f, 0.0f);
m_ShadowSettings.directionalLightCascades = m_Asset.CascadeSplit;
m_ShadowSettings.directionalLightCascades = m_Asset.Cascade4Split;
break;
}
}

Vector4[] lightAttenuations = new Vector4[kMaxLights];
Vector4[] lightSpotDirections = new Vector4[kMaxLights];
int pixelLightCount = Mathf.Min(lights.Length, QualitySettings.pixelLightCount);
int pixelLightCount = Mathf.Min(lights.Length, m_Asset.MaxSupportedPixelLights);
int vertexLightCount = (m_Asset.SupportsVertexLight) ? Mathf.Min(lights.Length - pixelLightCount, kMaxLights) : 0;
int totalLightCount = pixelLightCount + vertexLightCount;

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)

m_ShadowSettings.shadowAtlasHeight, cascadeCount);
shadowBias = lights[i].light.shadowBias;
break;
}
}

float shadowNearPlane = m_Asset.ShadowNearOffset;
Vector3 splitRatio = m_ShadowSettings.directionalLightCascades;
Vector3 lightDir = lights[lightIndex].light.transform.forward;
for (int cascadeIdx = 0; cascadeIdx < cascadeCount; ++cascadeIdx)
{
Matrix4x4 view, proj;

if (needRendering)
{
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view);
RenderShadowSlice(ref context, cascadeIdx, proj, view, settings, shadowBias);
RenderShadowSlice(ref context, lightDir, cascadeIdx, proj, view, settings);
}
}

m_ShadowSlices[cascadeIndex].shadowTransform = matTile * matScaleBias * proj * view;
}
private void RenderShadowSlice(ref ScriptableRenderContext context, int cascadeIndex, Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings, float shadowBias)
{
private void RenderShadowSlice(ref ScriptableRenderContext context, Vector3 lightDir, int cascadeIndex, Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings)
{
buffer.SetGlobalVector("_ShadowBias", new Vector4(shadowBias, 0.0f, 0.0f, 0.0f));
buffer.SetGlobalVector("_WorldLightDirAndBias", new Vector4(-lightDir.x, -lightDir.y, -lightDir.z, m_Asset.ShadowBias));
context.ExecuteCommandBuffer(buffer);
buffer.Dispose();

void SetShadowKeywords(CommandBuffer cmd)
{
if (m_Asset.CurrShadowType == LowEndRenderPipeline.ShadowType.NO_SHADOW)
cmd.DisableShaderKeyword("SHADOWS_DEPTH");
else
cmd.EnableShaderKeyword("SHADOWS_DEPTH");
switch (m_Asset.CurrShadowType)
{
case LowEndRenderPipeline.ShadowType.NO_SHADOW:
cmd.DisableShaderKeyword("HARD_SHADOWS");
cmd.DisableShaderKeyword("SOFT_SHADOWS");
break;
switch (m_Asset.CurrShadowFiltering)
{
case LowEndRenderPipeline.ShadowFiltering.PCF:
cmd.EnableShaderKeyword("SHADOWS_FILTERING_PCF");
case LowEndRenderPipeline.ShadowType.HARD_SHADOWS:
cmd.EnableShaderKeyword("HARD_SHADOWS");
cmd.DisableShaderKeyword("SOFT_SHADOWS");
default:
cmd.DisableShaderKeyword("SHADOWS_FILTERING_PCF");
case LowEndRenderPipeline.ShadowType.SOFT_SHADOWS:
cmd.DisableShaderKeyword("HARD_SHADOWS");
cmd.EnableShaderKeyword("SOFT_SHADOWS");
break;
}
}

#endregion
#region PipelineAssetSettings
public enum ShadowFiltering
{
PCF = 0,
NONE
}
public enum ShadowCascades
{
NO_CASCADES = 1,

{
NO_SHADOW = 0,
HARD_SHADOWS,
SOFT_SHADOWS,
public enum ShadowResolution
{
_512 = 512,
_1024 = 1024,
_2048 = 2048
}
[SerializeField]
private int m_MaxPixelLights = 1;
[SerializeField]
private bool m_SupportsVertexLight = true;

private ShadowType m_ShadowType = ShadowType.HARD_SHADOWS;
[SerializeField]
private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024;
[SerializeField]
private float m_ShadowNearPlaneOffset = 2.0f;
[SerializeField]

private int m_ShadowAtlasResolution = 1024;
private float m_ShadowBias = 0.0005f;
private Vector3 m_CascadeSplit = new Vector3(0.067f, 0.2f, 0.467f);
private float m_Cascade2Split = 0.25f;
private ShadowFiltering m_ShadowFiltering = ShadowFiltering.NONE;
private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f);
public int MaxSupportedPixelLights { get { return m_MaxPixelLights; } private set { m_MaxPixelLights = value; } }
public bool SupportsVertexLight { get { return m_SupportsVertexLight;} private set { m_SupportsVertexLight = value; } }

public ShadowType CurrShadowType { get { return m_ShadowType;} private set { m_ShadowType = value; } }
public int ShadowAtlasResolution { get { return (int)m_ShadowAtlasResolution; } private set { m_ShadowAtlasResolution = (ShadowResolution)value; } }
public float ShadowBias { get { return m_ShadowBias; } private set { m_ShadowBias = value; } }
public Vector3 CascadeSplit { get { return m_CascadeSplit; } private set { m_CascadeSplit = value; } }
public float Cascade2Split { get { return m_Cascade2Split; } private set { m_Cascade2Split = value; } }
public ShadowFiltering CurrShadowFiltering { get { return m_ShadowFiltering; } private set { m_ShadowFiltering = value; } }
public Vector3 Cascade4Split { get { return m_Cascade4Split; } private set { m_Cascade4Split = value; } }
public int ShadowAtlasResolution { get { return m_ShadowAtlasResolution; } private set { m_ShadowAtlasResolution = value; } }
#endregion
}

75
Assets/LowEndRenderPipeline/Shaders/LDRenderPipe-Specular.shader


#pragma shader_feature _NORMALMAP
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ SHADOWS_DEPTH
#pragma multi_compile _ SHADOWS_FILTERING_PCF
#pragma multi_compile _ HARD_SHADOWS SOFT_SHADOWS
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 d3d11_9x glcore gles gles3 metal
#pragma enable_d3d11_debug_symbols

inline half ShadowPCF(half4 shadowCoord)
{
// GPU Gems 4x4 kernel with 4 taps.
half2 offset = (float)(frac(shadowCoord.xy * 0.5) > 0.25); // mod
offset.y += offset.x; // y ^= x in floating point
offset *= _PSSMDistancesAndShadowResolution.w;
// TODO: simulate textureGatherOffset not available, simulate it
half2 offset = half2(0, 0);
half attenuation = ShadowAttenuation(shadowCoord.xy + half2(_PCFKernel[0], _PCFKernel[1]) + offset, shadowCoord.z) +
ShadowAttenuation(shadowCoord.xy + half2(_PCFKernel[2], _PCFKernel[3]) + offset, shadowCoord.z) +
ShadowAttenuation(shadowCoord.xy + half2(_PCFKernel[4], _PCFKernel[5]) + offset, shadowCoord.z) +

inline half3 EvaluateMainLight(LightInput lightInput, half3 diffuseColor, half4 specularGloss, half3 normal, float4 posWorld, half3 viewDir)
{
int cascadeIndex = ComputeCascadeIndex(posWorld.w);
float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorld.xyz, 1.0));
shadowCoord.z = saturate(shadowCoord.z);
#ifdef SHADOWS_FILTERING_PCF
half shadowAttenuation = ShadowPCF(shadowCoord);
#else
half shadowAttenuation = ShadowAttenuation(shadowCoord.xy, shadowCoord.z);
#endif
half3 color = EvaluateOneLight(lightInput, diffuseColor, specularGloss, normal, posWorld, viewDir);
#if DEBUG_CASCADES
half3 cascadeColors[MAX_SHADOW_CASCADES] = { half3(1.0, 0.0, 0.0), half3(0.0, 1.0, 0.0), half3(0.0, 0.0, 1.0), half3(1.0, 0.0, 1.0) };

half3 color = EvaluateOneLight(lightInput, diffuseColor, specularGloss, normal, posWorld, viewDir);
#if defined(HARD_SHADOWS) || defined(SOFT_SHADOWS)
int cascadeIndex = ComputeCascadeIndex(posWorld.w);
float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorld.xyz, 1.0));
shadowCoord.z = saturate(shadowCoord.z);
#ifdef SHADOWS_DEPTH
#ifdef SOFT_SHADOWS
half shadowAttenuation = ShadowPCF(shadowCoord);
#else
half shadowAttenuation = ShadowAttenuation(shadowCoord.xy, shadowCoord.z);
#endif
return color * shadowAttenuation;
#else
return color;

Name "SHADOW_CASTER"
Tags { "Lightmode" = "ShadowCaster" }
ZWrite On ZTest LEqual Cull Front
ZWrite On ZTest LEqual
CGPROGRAM
#pragma target 2.0

float4 _ShadowBias;
float4 _WorldLightDirAndBias;
inline void ApplyLinearBias(half4 clipPos)
struct VertexInput
{
float4 pos : POSITION;
float3 normal : NORMAL;
};
// Similar to UnityClipSpaceShadowCasterPos but using LDPipeline lightdir and bias and applying near plane clamp
float4 ClipSpaceShadowCasterPos(float4 vertex, float3 normal)
float4 wPos = mul(unity_ObjectToWorld, vertex);
if (_WorldLightDirAndBias.w > 0.0)
{
float3 wNormal = UnityObjectToWorldNormal(normal);
// apply normal offset bias (inset position along the normal)
// bias needs to be scaled by sine between normal and light direction
// (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/)
//
// _WorldLightDirAndBias.w shadow bias defined in LRRenderPipeline asset
float shadowCos = dot(wNormal, _WorldLightDirAndBias.xyz);
float shadowSine = sqrt(1 - shadowCos*shadowCos);
float normalBias = _WorldLightDirAndBias.w * shadowSine;
wPos.xyz -= wNormal * normalBias;
}
float4 clipPos = mul(UNITY_MATRIX_VP, wPos);
clipPos.z -= _ShadowBias.x;
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE);
clipPos.z += _ShadowBias.x;
clipPos.z = max(clipPos.z, UNITY_NEAR_CLIP_VALUE);
return clipPos;
float4 vert(float4 position : POSITION) : SV_POSITION
float4 vert(VertexInput i) : SV_POSITION
float4 clipPos = UnityObjectToClipPos(position);
ApplyLinearBias(clipPos);
return clipPos;
return ClipSpaceShadowCasterPos(i.pos, i.normal);
}
half4 frag() : SV_TARGET

正在加载...
取消
保存