浏览代码

Added light sorting based on shadow, light types priorization and intensity. Effectively capping max vertex lights to 4 now.

/fptl_cleanup
Felipe Lira 8 年前
当前提交
9f125a27
共有 3 个文件被更改,包括 130 次插入56 次删除
  1. 1
      Assets/LowEndMobilePipeline/Editor/LowendUpgraders.cs
  2. 181
      Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs
  3. 4
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset

1
Assets/LowEndMobilePipeline/Editor/LowendUpgraders.cs


public StandardUpgrader(string oldShaderName)
{
RenameShader(oldShaderName, "ScriptableRenderPipeline/LowEndMobile/NonPBR");
RenameFloat("_Glossiness", "_Shininess");
}
}

181
Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs


using System;
using System.Collections.Generic;
public class LowEndMobilePipeline : RenderPipeline
public class LowEndMobilePipeline : RenderPipeline, IComparer<VisibleLight>
private static readonly int kMaxVertexLights = 4;
private int m_ShadowLightIndex = -1;
private readonly int[] m_LightTypePriority = new int[4] {2, 1, 2, 0}; // Spot and Point lights have max priority
private int m_ShadowMapProperty;
private RenderTargetIdentifier m_ShadowMapRTID;
private int m_DepthBufferBits = 24;

cullingParameters.shadowDistance = m_ShadowSettings.maxShadowDistance;
CullResults cull = CullResults.Cull(ref cullingParameters, context);
VisibleLight[] visibleLights = cull.visibleLights;
int pixelLightsCount, vertexLightsCount;
GetMaxSupportedLights(visibleLights.Length, out pixelLightsCount, out vertexLightsCount);
// TODO: handle shader keywords when no lights are present
SortLights(ref visibleLights, pixelLightsCount);
// TODO: Add remaining lights to SH
bool shadowsRendered = RenderShadows(cull, context);
bool shadowsRendered = false;
if (m_ShadowLightIndex > -1)
shadowsRendered = RenderShadows(cull, visibleLights[m_ShadowLightIndex], context);
// Draw Opaques with support to one directional shadow cascade
// Setup camera matrices
// Setup camera matrices and RT
// Clear RenderTarget to avoid tile initialization on mobile GPUs
// https://community.arm.com/graphics/b/blog/posts/mali-performance-2-how-to-correctly-handle-framebuffers
cmd.ClearRenderTarget(true, true, Color.black);
cmd.ClearRenderTarget(true, true, camera.backgroundColor);
SetupLightShaderVariables(cull.visibleLights, context);
SetupLightShaderVariables(visibleLights, pixelLightsCount, vertexLightsCount, context);
if (shadowsRendered)
SetupShadowShaderVariables(context, m_ShadowCasterCascadesCount);

context.DrawRenderers(ref settings);
// Release temporary RT
var discardRT = new CommandBuffer();
discardRT.ReleaseTemporaryRT(m_ShadowMapProperty);
context.ExecuteCommandBuffer(discardRT);

m_ShadowSettings.directionalLightCascades = m_Asset.Cascade4Split;
break;
}
}
private void GetMaxSupportedLights(int lightsCount, out int pixelLightsCount, out int vertexLightsCount)
{
pixelLightsCount = Mathf.Min(lightsCount, m_Asset.MaxSupportedPixelLights);
vertexLightsCount = (m_Asset.SupportsVertexLight) ? Mathf.Min(lightsCount - pixelLightsCount, kMaxVertexLights) : 0;
private void SetupLightShaderVariables(VisibleLight[] lights, ScriptableRenderContext context)
private void SetupLightShaderVariables(VisibleLight[] lights, int pixelLightCount, int vertexLightCount, ScriptableRenderContext context)
int totalLightCount = pixelLightCount + vertexLightCount;
int pixelLightCount = Mathf.Min(lights.Length, m_Asset.MaxSupportedPixelLights);
int vertexLightCount = (m_Asset.SupportsVertexLight)
? Mathf.Min(lights.Length - pixelLightCount, kMaxLights)
: 0;
int totalLightCount = Mathf.Min(pixelLightCount + vertexLightCount, kMaxLights);
for (int i = 0; i < totalLightCount; ++i)
{

cmd.Dispose();
}
private bool RenderShadows(CullResults cullResults, ScriptableRenderContext context)
private bool RenderShadows(CullResults cullResults, VisibleLight shadowLight, ScriptableRenderContext context)
VisibleLight[] lights = cullResults.visibleLights;
int lightCount = lights.Length;
if (shadowLight.lightType == LightType.Spot)
m_ShadowCasterCascadesCount = 1;
int shadowResolution = 0;
int lightIndex = -1;
for (int i = 0; i < lightCount; ++i)
{
LightType type = lights[i].lightType;
if (lights[i].light.shadows != LightShadows.None && (type == LightType.Directional || type == LightType.Spot))
{
lightIndex = i;
if (lights[i].lightType == LightType.Spot)
m_ShadowCasterCascadesCount = 1;
shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.shadowAtlasWidth,
m_ShadowSettings.shadowAtlasHeight, m_ShadowCasterCascadesCount);
break;
}
}
if (lightIndex < 0)
return false;
int shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.shadowAtlasWidth, m_ShadowSettings.shadowAtlasHeight, m_ShadowCasterCascadesCount);
if (!cullResults.GetShadowCasterBounds(lightIndex, out bounds))
if (!cullResults.GetShadowCasterBounds(m_ShadowLightIndex, out bounds))
return false;
var setRenderTargetCommandBuffer = new CommandBuffer();

float shadowNearPlane = m_Asset.ShadowNearOffset;
Vector3 splitRatio = m_ShadowSettings.directionalLightCascades;
Vector3 lightDir = Vector3.Normalize(lights[lightIndex].light.transform.forward);
Vector3 lightDir = Vector3.Normalize(shadowLight.light.transform.forward);
var settings = new DrawShadowsSettings(cullResults, lightIndex);
var settings = new DrawShadowsSettings(cullResults, m_ShadowLightIndex);
if (lights[lightIndex].lightType == LightType.Spot)
if (shadowLight.lightType == LightType.Spot)
needRendering = cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(lightIndex, out view, out proj,
needRendering = cullResults.ComputeSpotShadowMatricesAndCullingPrimitives(m_ShadowLightIndex, out view, out proj,
if (needRendering)
{
SetupShadowSliceTransform(0, shadowResolution, proj, view);
RenderShadowSlice(ref context, lightDir, 0, proj, view, settings);
}
if (!needRendering)
return false;
SetupShadowSliceTransform(0, shadowResolution, proj, view);
RenderShadowSlice(ref context, lightDir, 0, proj, view, settings);
else if (lights[lightIndex].lightType == LightType.Directional)
else if (shadowLight.lightType == LightType.Directional)
needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(lightIndex,
needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(m_ShadowLightIndex,
cascadeIdx, m_ShadowCasterCascadesCount, splitRatio, shadowResolution, shadowNearPlane, out view, out proj,
out settings.splitData);

if (needRendering)
{
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view);
RenderShadowSlice(ref context, lightDir, cascadeIdx, proj, view, settings);
}
if (!needRendering)
return false;
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view);
RenderShadowSlice(ref context, lightDir, cascadeIdx, proj, view, settings);
return false;
}
return true;

else
cmd.EnableShaderKeyword("_SHADOW_CASCADES");
switch (m_Asset.CurrShadowType)
ShadowType shadowType = (m_ShadowLightIndex != -1) ? m_Asset.CurrShadowType : ShadowType.NO_SHADOW;
switch (shadowType)
{
case ShadowType.NO_SHADOW:
cmd.DisableShaderKeyword("HARD_SHADOWS");

cmd.EnableShaderKeyword("SOFT_SHADOWS");
break;
}
}
// Finds main light and main shadow casters and places them in the beginning of array.
// Sort the remaining array based on custom IComparer criteria.
private void SortLights(ref VisibleLight[] lights, int pixelLightsCount)
{
m_ShadowLightIndex = -1;
if (lights.Length == 0)
return;
bool shadowsSupported = m_Asset.CurrShadowType != ShadowType.NO_SHADOW && pixelLightsCount > 0;
int mainLightIndex = -1;
for (int i = 0; i < lights.Length; ++i)
{
VisibleLight currLight = lights[i];
if (currLight.lightType == LightType.Directional)
if (mainLightIndex == -1 || currLight.light.intensity > lights[mainLightIndex].light.intensity)
mainLightIndex = i;
if (shadowsSupported && (currLight.light.shadows != LightShadows.None) && IsSupportedShadowType(currLight.lightType))
// Prefer directional shadows, if not sort by intensity
if (m_ShadowLightIndex == -1 || currLight.lightType > lights[m_ShadowLightIndex].lightType)
m_ShadowLightIndex = i;
}
// If supports a single directional light only, main light is main shadow light.
if (pixelLightsCount == 1 && m_ShadowLightIndex > -1)
mainLightIndex = m_ShadowLightIndex;
int startIndex = 0;
if (mainLightIndex > -1)
{
SwapLights(ref lights, 0, mainLightIndex);
startIndex++;
}
if (mainLightIndex != m_ShadowLightIndex && m_ShadowLightIndex > 0)
{
SwapLights(ref lights, 1, m_ShadowLightIndex);
m_ShadowLightIndex = 1;
startIndex++;
}
Array.Sort(lights, startIndex, lights.Length - startIndex, this);
}
private bool IsSupportedShadowType(LightType type)
{
return (type == LightType.Directional || type == LightType.Spot);
}
private void SwapLights(ref VisibleLight[] lights, int lhsIndex, int rhsIndex)
{
if (lhsIndex == rhsIndex)
return;
VisibleLight temp = lights[lhsIndex];
lights[lhsIndex] = lights[rhsIndex];
lights[rhsIndex] = temp;
}
// Prioritizes Spot and Point lights by intensity. If any directional light, it will be the main
// light and will not be considered in the computation.
// TODO: Move to a better sorting solution, e.g, prioritize lights per object.
public int Compare(VisibleLight lhs, VisibleLight rhs)
{
int lhsLightTypePriority = m_LightTypePriority[(int) lhs.lightType];
int rhsLightTypePriority = m_LightTypePriority[(int) rhs.lightType];
if (lhsLightTypePriority != rhsLightTypePriority)
return rhsLightTypePriority - lhsLightTypePriority;
return (int) (rhs.light.intensity - lhs.light.intensity);
}
}
}

4
Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset


m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3}
m_Name: LowEndMobilePipelineAsset
m_EditorClassIdentifier:
m_MaxPixelLights: 8
m_SupportsVertexLight: 0
m_MaxPixelLights: 1
m_SupportsVertexLight: 1
m_EnableLightmaps: 1
m_EnableAmbientProbe: 1
m_ShadowType: 1

正在加载...
取消
保存