浏览代码

Fixed shadow acne issues that were apparent in Metal.

/Branch_batcher
Felipe Lira 7 年前
当前提交
7ffb14f0
共有 5 个文件被更改,包括 71 次插入100 次删除
  1. 13
      Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs
  2. 6
      Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs
  3. 16
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs
  4. 102
      Assets/LowEndMobilePipeline/Shaders/LowEndMobilePipeline.shader
  5. 34
      Assets/LowEndMobilePipeline/Shaders/LowEndMobilePipelineCore.cginc

13
Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs


"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 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.");

private SerializedProperty m_EnableAmbientProbeProp;
private SerializedProperty m_ShadowTypeProp;
private SerializedProperty m_ShadowNearPlaneOffsetProp;
private SerializedProperty m_ShadowBiasProperty;
private SerializedProperty m_ShadowMinNormalBiasProperty;
private SerializedProperty m_ShadowNormalBiasProperty;
private SerializedProperty m_ShadowDistanceProp;
private SerializedProperty m_ShadowAtlasResolutionProp;
private SerializedProperty m_ShadowCascadesProp;

m_EnableAmbientProbeProp = serializedObject.FindProperty("m_EnableAmbientProbe");
m_ShadowTypeProp = serializedObject.FindProperty("m_ShadowType");
m_ShadowNearPlaneOffsetProp = serializedObject.FindProperty("m_ShadowNearPlaneOffset");
m_ShadowBiasProperty = serializedObject.FindProperty("m_ShadowBias");
m_ShadowMinNormalBiasProperty = serializedObject.FindProperty("m_MinShadowNormalBias");
m_ShadowNormalBiasProperty = serializedObject.FindProperty("m_ShadowNormalBias");
m_ShadowDistanceProp = serializedObject.FindProperty("m_ShadowDistance");
m_ShadowAtlasResolutionProp = serializedObject.FindProperty("m_ShadowAtlasResolution");
m_ShadowCascadesProp = serializedObject.FindProperty("m_ShadowCascades");

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

6
Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs


cmd.SetGlobalVectorArray("globalLightColor", m_LightColors);
cmd.SetGlobalVectorArray("globalLightAtten", m_LightAttenuations);
cmd.SetGlobalVectorArray("globalLightSpotDir", m_LightSpotDirections);
cmd.SetGlobalVector("globalLightCount", new Vector4(pixelLightCount, totalLightCount, 0.0f, 0.0f));
float shadowMinNormalBias = m_Asset.ShadowMinNormalBias;
float shadowNormalBias = m_Asset.ShadowNormalBias;
cmd.SetGlobalVector("globalLightData", new Vector4(pixelLightCount, totalLightCount, shadowMinNormalBias, shadowNormalBias));
SetShaderKeywords(cmd, vertexLightCount > 0);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();

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("_WorldLightDirAndBias",
new Vector4(-lightDir.x, -lightDir.y, -lightDir.z, m_Asset.ShadowBias));
context.ExecuteCommandBuffer(buffer);
buffer.Dispose();

16
Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs


[SerializeField] private float m_ShadowDistance = 50.0f;
[SerializeField] private float m_ShadowBias = 0.0005f;
[SerializeField] private float m_MinShadowNormalBias = 0.0005f;
[SerializeField] private float m_ShadowNormalBias = 0.05f;
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES;

private set { m_ShadowDistance = value; }
}
public float ShadowBias
public float ShadowMinNormalBias
get { return m_ShadowBias; }
private set { m_ShadowBias = value; }
get { return m_MinShadowNormalBias; }
private set { m_MinShadowNormalBias = value; }
}
public float ShadowNormalBias
{
get { return m_ShadowNormalBias; }
private set { m_ShadowNormalBias = value; }
}
public int CascadeCount

102
Assets/LowEndMobilePipeline/Shaders/LowEndMobilePipeline.shader


#if defined(_VERTEX_LIGHTS)
half4 diffuseAndSpecular = half4(1.0, 1.0, 1.0, 1.0);
for (int lightIndex = globalLightCount.x; lightIndex < globalLightCount.y; ++lightIndex)
for (int lightIndex = globalLightData.x; lightIndex < globalLightData.y; ++lightIndex)
#endif
#ifndef _SHADOW_CASCADES
o.shadowCoord = mul(_WorldToShadow[0], float4(o.posWS, 1.0));
#endif
#ifdef _LIGHT_PROBES_ON

half4 specularGloss;
SpecularGloss(i.uv01.xy, diffuse, alpha, specularGloss);
#ifdef _SHADOWS
half shadowAttenuation = ComputeShadowAttenuation(i);
#else
half shadowAttenuation = 1.0f;
#endif
for (int lightIndex = 0; lightIndex < globalLightCount.x; ++lightIndex)
for (int lightIndex = 0; lightIndex < globalLightData.x; ++lightIndex)
LightInput additionalLight;
INITIALIZE_LIGHT(additionalLight, lightIndex);
color += EvaluateOneLight(additionalLight, diffuse, specularGloss, normal, i.posWS, viewDir);
LightInput lightData;
half NdotL;
INITIALIZE_LIGHT(lightData, lightIndex);
color += EvaluateOneLight(lightData, diffuse, specularGloss, normal, i.posWS, viewDir, NdotL);
#ifdef _SHADOWS
color *= shadowAttenuation;
{
float bias = max(globalLightData.z, (1.0 - NdotL) * globalLightData.w);
color *= ComputeShadowAttenuation(i, i.normal * bias);
}
#endif
}
half3 emissionColor;

#pragma vertex vert
#pragma fragment frag
float4 _WorldLightDirAndBias;
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 vert(float4 pos : POSITION) : SV_POSITION
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);
float4 clipPos = UnityObjectToClipPos(pos);
#if defined(UNITY_REVERSED_Z)
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE);
#else

}
float4 vert(VertexInput i) : SV_POSITION
{
return ClipSpaceShadowCasterPos(i.pos, i.normal);
}
half4 frag() : SV_TARGET

ENDCG
}
// This pass it not used during regular rendering, only for lightmap baking.
Pass
{
Name "LD_META"
Tags{ "LightMode" = "Meta" }
// This pass it not used during regular rendering, only for lightmap baking.
Pass
{
Name "LD_META"
Tags{ "LightMode" = "Meta" }
Cull Off
Cull Off
CGPROGRAM
#pragma vertex vert_meta
#pragma fragment frag_meta
CGPROGRAM
#pragma vertex vert_meta
#pragma fragment frag_meta
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature EDITOR_VISUALIZATION
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature EDITOR_VISUALIZATION
#include "UnityStandardMeta.cginc"
ENDCG
}
#include "UnityStandardMeta.cginc"
ENDCG
Fallback "Standard (Specular setup)"
CustomEditor "LowendMobilePipelineMaterialEditor"
}
Fallback "Standard (Specular setup)"
CustomEditor "LowendMobilePipelineMaterialEditor"
}

34
Assets/LowEndMobilePipeline/Shaders/LowEndMobilePipelineCore.cginc


#endif
half4 viewDir : TEXCOORD5; // xyz: viewDir
UNITY_FOG_COORDS_PACKED(6, half4) // x: fogCoord, yzw: vertexColor
#ifndef _SHADOW_CASCADES
float4 shadowCoord : TEXCOORD7;
#endif
float4 hpos : SV_POSITION;
};

float4 globalLightPos[MAX_LIGHTS];
half4 globalLightSpotDir[MAX_LIGHTS];
half4 globalLightAtten[MAX_LIGHTS];
int4 globalLightCount; // x: pixelLightCount, y = totalLightCount (pixel + vert)
float4 globalLightData; // x: pixelLightCount, y = totalLightCount (pixel + vert), z = minShadowNormalBiasOffset, w = shadowNormalBiasOffset
half4x4 _WorldToShadow[MAX_SHADOW_CASCADES];
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES];
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES];
half _Shininess;
samplerCUBE _Cube;

return 4 - dot(weights, fixed4(4, 3, 2, 1));
}
inline half ShadowAttenuation(half3 shadowCoord)
inline half ShadowAttenuation(float3 shadowCoord)
half depth = tex2D(_ShadowMap, shadowCoord).r;
float depth = tex2D(_ShadowMap, shadowCoord).r;
#if defined(UNITY_REVERSED_Z)
return step(depth, shadowCoord.z);
#else

return attenuation * 0.25;
}
inline half3 EvaluateOneLight(LightInput lightInput, half3 diffuseColor, half4 specularGloss, half3 normal, float3 posWorld, half3 viewDir)
inline half3 EvaluateOneLight(LightInput lightInput, half3 diffuseColor, half4 specularGloss, half3 normal, float3 posWorld, half3 viewDir, out half NdotL)
{
float3 posToLight = lightInput.pos.xyz;
posToLight -= posWorld * lightInput.pos.w;

half3 lightDir = posToLight * rsqrt(distanceSqr);
float3 lightDir = posToLight * rsqrt(distanceSqr);
half SdotL = saturate(dot(lightInput.spotDir.xyz, lightDir));
lightAtten *= saturate((SdotL - lightInput.atten.x) / lightInput.atten.y);

half NdotL = saturate(dot(normal, lightDir));
NdotL = saturate(dot(normal, lightDir));
half3 halfVec = normalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));

#endif
}
inline half ComputeShadowAttenuation(v2f i)
inline half ComputeShadowAttenuation(v2f i, float3 offset)
#ifndef _SHADOW_CASCADES
half4 shadowCoord;
shadowCoord = i.shadowCoord;
#else
half4 shadowCoord;
int cascadeIndex = ComputeCascadeIndex(i.posWS);
float3 posWorldOffsetNormal = i.posWS + offset;
int cascadeIndex = 0;
#ifdef _SHADOW_CASCADES
cascadeIndex = ComputeCascadeIndex(i.posWS);
shadowCoord = mul(_WorldToShadow[cascadeIndex], half4(i.posWS, 1.0));
else
float4 shadowCoord = mul(_WorldToShadow[cascadeIndex], float4(posWorldOffsetNormal, 1.0));
shadowCoord.xyz /= shadowCoord.w;
shadowCoord.z = saturate(shadowCoord.z);

正在加载...
取消
保存