您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

325 行
13 KiB

using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
namespace UnityEngine.Experimental.Rendering.LightweightPipeline
{
public sealed class ScriptableRenderer
{
// Lights are culled per-object. In platforms that don't use StructuredBuffer
// the engine will set 4 light indices in the following constant unity_4LightIndices0
// Additionally the engine set unity_4LightIndices1 but LWRP doesn't use that.
const int k_MaxConstantLocalLights = 4;
// LWRP uses a fixed constant buffer to hold light data. This must match the value of
// MAX_VISIBLE_LIGHTS 16 in Input.hlsl
const int k_MaxVisibleLocalLights = 16;
const int k_MaxVertexLights = 4;
public int maxSupportedLocalLightsPerPass
{
get
{
return useComputeBufferForPerObjectLightIndices ? k_MaxVisibleLocalLights : k_MaxConstantLocalLights;
}
}
// TODO: Profile performance of using ComputeBuffer on mobiles that support it
public static bool useComputeBufferForPerObjectLightIndices
{
get
{
// TODO: Graphics Emulation are breaking StructuredBuffers disabling it for now until
// we have a fix for it
return false;
// return SystemInfo.supportsComputeShaders &&
// SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLCore &&
// !Application.isMobilePlatform &&
// Application.platform != RuntimePlatform.WebGLPlayer;
}
}
public int maxVisibleLocalLights { get { return k_MaxVisibleLocalLights; } }
public int maxSupportedVertexLights { get { return k_MaxVertexLights; } }
public PostProcessRenderContext postProcessingContext { get; private set; }
public ComputeBuffer perObjectLightIndices { get; private set; }
static Mesh s_FullscreenMesh = null;
static Mesh fullscreenMesh
{
get
{
if (s_FullscreenMesh != null)
return s_FullscreenMesh;
float topV = 1.0f;
float bottomV = 0.0f;
Mesh mesh = new Mesh { name = "Fullscreen Quad" };
mesh.SetVertices(new List<Vector3>
{
new Vector3(-1.0f, -1.0f, 0.0f),
new Vector3(-1.0f, 1.0f, 0.0f),
new Vector3(1.0f, -1.0f, 0.0f),
new Vector3(1.0f, 1.0f, 0.0f)
});
mesh.SetUVs(0, new List<Vector2>
{
new Vector2(0.0f, bottomV),
new Vector2(0.0f, topV),
new Vector2(1.0f, bottomV),
new Vector2(1.0f, topV)
});
mesh.SetIndices(new[] { 0, 1, 2, 2, 1, 3 }, MeshTopology.Triangles, 0, false);
mesh.UploadMeshData(true);
return mesh;
}
}
List<ScriptableRenderPass> m_ActiveRenderPassQueue = new List<ScriptableRenderPass>();
List<ShaderPassName> m_LegacyShaderPassNames = new List<ShaderPassName>()
{
new ShaderPassName("Always"),
new ShaderPassName("ForwardBase"),
new ShaderPassName("PrepassBase"),
new ShaderPassName("Vertex"),
new ShaderPassName("VertexLMRGBM"),
new ShaderPassName("VertexLM"),
};
const string k_ReleaseResourcesTag = "Release Resources";
readonly Material[] m_Materials;
public ScriptableRenderer(LightweightPipelineAsset pipelineAsset)
{
m_Materials = new[]
{
CoreUtils.CreateEngineMaterial("Hidden/InternalErrorShader"),
CoreUtils.CreateEngineMaterial(pipelineAsset.copyDepthShader),
CoreUtils.CreateEngineMaterial(pipelineAsset.samplingShader),
CoreUtils.CreateEngineMaterial(pipelineAsset.blitShader),
CoreUtils.CreateEngineMaterial(pipelineAsset.screenSpaceShadowShader),
};
postProcessingContext = new PostProcessRenderContext();
}
public void Dispose()
{
if (perObjectLightIndices != null)
{
perObjectLightIndices.Release();
perObjectLightIndices = null;
}
for (int i = 0; i < m_Materials.Length; ++i)
CoreUtils.Destroy(m_Materials[i]);
}
public void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
m_ActiveRenderPassQueue[i].Execute(this, context, ref renderingData);
DisposePasses(ref context);
}
public Material GetMaterial(MaterialHandles handle)
{
int handleID = (int)handle;
if (handleID >= m_Materials.Length)
{
Debug.LogError(string.Format("Material {0} is not registered.",
Enum.GetName(typeof(MaterialHandles), handleID)));
return null;
}
return m_Materials[handleID];
}
public void Clear()
{
m_ActiveRenderPassQueue.Clear();
}
public void EnqueuePass(ScriptableRenderPass pass)
{
m_ActiveRenderPassQueue.Add(pass);
}
public void SetupPerObjectLightIndices(ref CullResults cullResults, ref LightData lightData)
{
if (lightData.totalAdditionalLightsCount == 0)
return;
List<VisibleLight> visibleLights = lightData.visibleLights;
int[] perObjectLightIndexMap = cullResults.GetLightIndexMap();
int directionalLightCount = 0;
// Disable all directional lights from the perobject light indices
// Pipeline handles them globally
for (int i = 0; i < visibleLights.Count; ++i)
{
VisibleLight light = visibleLights[i];
if (light.lightType == LightType.Directional)
{
perObjectLightIndexMap[i] = -1;
++directionalLightCount;
}
else
perObjectLightIndexMap[i] -= directionalLightCount;
}
cullResults.SetLightIndexMap(perObjectLightIndexMap);
// if not using a compute buffer, engine will set indices in 2 vec4 constants
// unity_4LightIndices0 and unity_4LightIndices1
if (useComputeBufferForPerObjectLightIndices)
{
int lightIndicesCount = cullResults.GetLightIndicesCount();
if (lightIndicesCount > 0)
{
if (perObjectLightIndices == null)
{
perObjectLightIndices = new ComputeBuffer(lightIndicesCount, sizeof(int));
}
else if (perObjectLightIndices.count < lightIndicesCount)
{
perObjectLightIndices.Release();
perObjectLightIndices = new ComputeBuffer(lightIndicesCount, sizeof(int));
}
cullResults.FillLightIndices(perObjectLightIndices);
}
}
}
public void RenderPostProcess(CommandBuffer cmd, ref CameraData cameraData, RenderTextureFormat colorFormat, RenderTargetIdentifier source, RenderTargetIdentifier dest, bool opaqueOnly)
{
Camera camera = cameraData.camera;
postProcessingContext.Reset();
postProcessingContext.camera = camera;
postProcessingContext.source = source;
postProcessingContext.sourceFormat = colorFormat;
postProcessingContext.destination = dest;
postProcessingContext.command = cmd;
postProcessingContext.flip = !cameraData.isStereoEnabled && camera.targetTexture == null;
if (opaqueOnly)
cameraData.postProcessLayer.RenderOpaqueOnly(postProcessingContext);
else
cameraData.postProcessLayer.Render(postProcessingContext);
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
public void RenderObjectsWithError(ScriptableRenderContext context, ref CullResults cullResults, Camera camera, FilterRenderersSettings filterSettings, SortFlags sortFlags)
{
Material errorMaterial = GetMaterial(MaterialHandles.Error);
if (errorMaterial != null)
{
DrawRendererSettings errorSettings = new DrawRendererSettings(camera, m_LegacyShaderPassNames[0]);
for (int i = 1; i < m_LegacyShaderPassNames.Count; ++i)
errorSettings.SetShaderPassName(i, m_LegacyShaderPassNames[i]);
errorSettings.sorting.flags = sortFlags;
errorSettings.rendererConfiguration = RendererConfiguration.None;
errorSettings.SetOverrideMaterial(errorMaterial, 0);
context.DrawRenderers(cullResults.visibleRenderers, ref errorSettings, filterSettings);
}
}
public static RenderTextureDescriptor CreateRenderTextureDescriptor(ref CameraData cameraData, float scaler = 1.0f)
{
Camera camera = cameraData.camera;
RenderTextureDescriptor desc;
float renderScale = cameraData.renderScale;
if (cameraData.isStereoEnabled)
{
return XRGraphicsConfig.eyeTextureDesc;
}
else
{
desc = new RenderTextureDescriptor(camera.pixelWidth, camera.pixelHeight);
}
desc.colorFormat = cameraData.isHdrEnabled ? RenderTextureFormat.DefaultHDR :
RenderTextureFormat.Default;
desc.enableRandomWrite = false;
desc.sRGB = true;
desc.width = (int)((float)desc.width * renderScale * scaler);
desc.height = (int)((float)desc.height * renderScale * scaler);
return desc;
}
public static bool RequiresIntermediateColorTexture(ref CameraData cameraData, RenderTextureDescriptor baseDescriptor)
{
if (cameraData.isOffscreenRender)
return false;
bool isScaledRender = !Mathf.Approximately(cameraData.renderScale, 1.0f);
bool isTargetTexture2DArray = baseDescriptor.dimension == TextureDimension.Tex2DArray;
return cameraData.isSceneViewCamera || isScaledRender || cameraData.isHdrEnabled ||
cameraData.postProcessEnabled || cameraData.requiresOpaqueTexture || isTargetTexture2DArray || !cameraData.isDefaultViewport;
}
public static ClearFlag GetCameraClearFlag(Camera camera)
{
ClearFlag clearFlag = ClearFlag.None;
CameraClearFlags cameraClearFlags = camera.clearFlags;
if (cameraClearFlags != CameraClearFlags.Nothing)
{
clearFlag |= ClearFlag.Depth;
if (cameraClearFlags == CameraClearFlags.Color || cameraClearFlags == CameraClearFlags.Skybox)
clearFlag |= ClearFlag.Color;
}
return clearFlag;
}
public static RendererConfiguration GetRendererConfiguration(int localLightsCount)
{
RendererConfiguration configuration = RendererConfiguration.PerObjectReflectionProbes | RendererConfiguration.PerObjectLightmaps | RendererConfiguration.PerObjectLightProbe;
if (localLightsCount > 0)
{
if (useComputeBufferForPerObjectLightIndices)
configuration |= RendererConfiguration.ProvideLightIndices;
else
configuration |= RendererConfiguration.PerObjectLightIndices8;
}
return configuration;
}
public static void RenderFullscreenQuad(CommandBuffer cmd, Material material, MaterialPropertyBlock properties = null, int shaderPassId = 0)
{
cmd.DrawMesh(fullscreenMesh, Matrix4x4.identity, material, 0, shaderPassId, properties);
}
public static void CopyTexture(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier dest, Material material)
{
// TODO: In order to issue a copyTexture we need to also check if source and dest have same size
//if (SystemInfo.copyTextureSupport != CopyTextureSupport.None)
// cmd.CopyTexture(source, dest);
//else
cmd.Blit(source, dest, material);
}
void DisposePasses(ref ScriptableRenderContext context)
{
CommandBuffer cmd = CommandBufferPool.Get(k_ReleaseResourcesTag);
for (int i = 0; i < m_ActiveRenderPassQueue.Count; ++i)
m_ActiveRenderPassQueue[i].FrameCleanup(cmd);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}