Evgenii Golubev 7 年前
当前提交
79a9ba87
共有 9 个文件被更改,包括 167 次插入88 次删除
  1. 1
      Assets/LowEndMobilePipeline/Editor/LowendUpgraders.cs
  2. 181
      Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs
  3. 4
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset
  4. 7
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-clustered.compute
  5. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild.compute
  6. 30
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl
  7. 21
      Assets/ScriptableRenderPipeline/fptl/TiledLightingUtils.hlsl
  8. 7
      Assets/ScriptableRenderPipeline/fptl/lightlistbuild-clustered.compute
  9. 2
      Assets/ScriptableRenderPipeline/fptl/lightlistbuild.compute

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

7
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-clustered.compute


{
for(int l=(int) t; l<((iNrCoarseLights+1)>>1); l += NR_THREADS)
{
const int l0 = coarseList[2*l+0], l1 = coarseList[min(2*l+1,iNrCoarseLights)];
const int l0 = coarseList[2*l+0], l1 = coarseList[min(2*l+1,iNrCoarseLights-1)];
const unsigned int clustIdxMi0 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l0].z), suggestedBase));
const unsigned int clustIdxMa0 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l0+g_iNrVisibLights].z), suggestedBase));
const unsigned int clustIdxMi1 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l1].z), suggestedBase));

{
int offs = 0;
for(int l=0; l<iNrCoarseLights; l++)
{ if(coarseList[l]!=0xffffffff) coarseList[offs++] = coarseList[l]; }
{
if(coarseList[l]!=0xffffffff)
coarseList[offs++] = coarseList[l];
}
lightOffsSph = offs;
}

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild.compute


for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS)
{
// We remap the prunedList index to the original LightData / EnvLightData indices
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2 * l - 1 + localOffs] - shiftIndex[category];
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[max(0,2 * l - 1 + localOffs)] - shiftIndex[category];
uint uHigh = prunedList[2 * l + 0 + localOffs] - shiftIndex[category];
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16);

30
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl


start = tileOffset;
}
uint FetchIndexTile(uint tileOffset, uint lightIndex)
{
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light
// Light index are store on 16bit
return (g_vLightListGlobal[DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1)] >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff;
}
#ifdef USE_FPTL_LIGHTLIST
uint GetTileSize()

uint FetchIndex(uint tileOffset, uint lightIndex)
{
return FetchIndexTile(tileOffset, lightIndex);
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light
// Light index are store on 16bit
return (g_vLightListGlobal[DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1)] >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff;
}
#elif defined(USE_CLUSTERED_LIGHTLIST)

lightCount = (dataPair >> 27) & 31;
}
uint FetchIndexCluster(uint tileOffset, uint lightIndex)
{
return g_vLightListGlobal[tileOffset + lightIndex];
}
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
if (_UseTileLightList)

uint FetchIndex(uint tileOffset, uint lightIndex)
{
uint offset = tileOffset + lightIndex;
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light
return FetchIndexTile(tileOffset, lightIndex);
else
return FetchIndexCluster(tileOffset, lightIndex);
offset = DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1);
// Avoid generated HLSL bytecode to always access g_vLightListGlobal with
// two different offsets, fixes out of bounds issue
uint value = g_vLightListGlobal[offset];
// Light index are store on 16bit
return (_UseTileLightList ? ((value >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff) : value);
}
#endif

21
Assets/ScriptableRenderPipeline/fptl/TiledLightingUtils.hlsl


uStart = tileOffs;
}
uint FetchIndexOpaque(const uint tileOffs, const uint l)
{
const uint l1 = l+1;
return (g_vLightListGlobal[ 16*tileOffs + (l1>>1)]>>((l1&1)*16))&0xffff;
}
#ifdef OPAQUES_ONLY
void GetCountAndStart(out uint uStart, out uint uNrLights, uint2 pixCoord, float linDepth, uint model)

uint FetchIndex(const uint tileOffs, const uint l)
{
return FetchIndexOpaque(tileOffs, l);
const uint l1 = l+1;
return (g_vLightListGlobal[ 16*tileOffs + (l1>>1)]>>((l1&1)*16))&0xffff;
}
#else

uint FetchIndex(const uint tileOffs, const uint l)
{
uint offs = tileOffs+l;
const uint l1 = l+1;
return FetchIndexOpaque(tileOffs, l);
else
return g_vLightListGlobal[ tileOffs+l ];
offs = 16*tileOffs + (l1>>1);
// Avoid generated HLSL bytecode to always access g_vLightListGlobal with
// two different offsets, fixes out of bounds issue
uint value = g_vLightListGlobal[offs];
return (g_isOpaquesOnlyEnabled ? ((value >>((l1&1)*16))&0xffff) : value);
}
#endif

7
Assets/ScriptableRenderPipeline/fptl/lightlistbuild-clustered.compute


{
for(int l=(int) t; l<((iNrCoarseLights+1)>>1); l += NR_THREADS)
{
const int l0 = coarseList[2*l+0], l1 = coarseList[min(2*l+1,iNrCoarseLights)];
const int l0 = coarseList[2*l+0], l1 = coarseList[min(2*l+1,iNrCoarseLights-1)];
const unsigned int clustIdxMi0 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l0].z), suggestedBase));
const unsigned int clustIdxMa0 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l0+g_iNrVisibLights].z), suggestedBase));
const unsigned int clustIdxMi1 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l1].z), suggestedBase));

{
int offs = 0;
for(int l=0; l<iNrCoarseLights; l++)
{ if(coarseList[l]!=0xffffffff) coarseList[offs++] = coarseList[l]; }
{
if(coarseList[l]!=0xffffffff)
coarseList[offs++] = coarseList[l];
}
lightOffsSph = offs;
}

2
Assets/ScriptableRenderPipeline/fptl/lightlistbuild.compute


const int nrDWords = ((nrLightsFinalClamped+1)+1)>>1;
for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS)
{
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2 * l - 1 + localOffs];
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[max(0,2 * l - 1 + localOffs)];
uint uHigh = prunedList[2 * l + 0 + localOffs];
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16);

正在加载...
取消
保存