您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
378 行
16 KiB
378 行
16 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
using System.Text;
|
|
using UnityEngine.Rendering;
|
|
|
|
using UnityObject = UnityEngine.Object;
|
|
|
|
namespace UnityEngine.Experimental.Rendering.HDPipeline
|
|
{
|
|
[Flags]
|
|
public enum ClearFlag
|
|
{
|
|
ClearNone = 0,
|
|
ClearColor = 1,
|
|
ClearDepth = 2
|
|
}
|
|
|
|
[Flags]
|
|
public enum StencilBits
|
|
{
|
|
None = Lit.MaterialId.LitStandard,
|
|
SSS = Lit.MaterialId.LitSSS,
|
|
ClearCoat = Lit.MaterialId.LitClearCoat,
|
|
All = 255 // 0xff
|
|
}
|
|
|
|
public class Utilities
|
|
{
|
|
public const RendererConfiguration kRendererConfigurationBakedLighting = RendererConfiguration.PerObjectLightProbe | RendererConfiguration.PerObjectLightmaps | RendererConfiguration.PerObjectLightProbeProxyVolume;
|
|
|
|
|
|
// Render Target Management.
|
|
public const ClearFlag kClearAll = ClearFlag.ClearDepth | ClearFlag.ClearColor;
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier buffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
|
|
{
|
|
var cmd = new CommandBuffer();
|
|
cmd.name = "";
|
|
cmd.SetRenderTarget(buffer, miplevel, cubemapFace);
|
|
if (clearFlag != ClearFlag.ClearNone)
|
|
cmd.ClearRenderTarget((clearFlag & ClearFlag.ClearDepth) != 0, (clearFlag & ClearFlag.ClearColor) != 0, clearColor);
|
|
renderContext.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier buffer, ClearFlag clearFlag = ClearFlag.ClearNone, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
|
|
{
|
|
SetRenderTarget(renderContext, buffer, clearFlag, Color.black, miplevel, cubemapFace);
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
|
|
{
|
|
SetRenderTarget(renderContext, colorBuffer, depthBuffer, ClearFlag.ClearNone, Color.black, miplevel, cubemapFace);
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
|
|
{
|
|
SetRenderTarget(renderContext, colorBuffer, depthBuffer, clearFlag, Color.black, miplevel, cubemapFace);
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown)
|
|
{
|
|
var cmd = new CommandBuffer();
|
|
cmd.name = "";
|
|
cmd.SetRenderTarget(colorBuffer, depthBuffer, miplevel, cubemapFace);
|
|
if (clearFlag != ClearFlag.ClearNone)
|
|
cmd.ClearRenderTarget((clearFlag & ClearFlag.ClearDepth) != 0, (clearFlag & ClearFlag.ClearColor) != 0, clearColor);
|
|
renderContext.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer)
|
|
{
|
|
SetRenderTarget(renderContext, colorBuffers, depthBuffer, ClearFlag.ClearNone, Color.black);
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag = ClearFlag.ClearNone)
|
|
{
|
|
SetRenderTarget(renderContext, colorBuffers, depthBuffer, clearFlag, Color.black);
|
|
}
|
|
|
|
public static void SetRenderTarget(ScriptableRenderContext renderContext, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor)
|
|
{
|
|
var cmd = new CommandBuffer();
|
|
cmd.name = "";
|
|
cmd.SetRenderTarget(colorBuffers, depthBuffer);
|
|
if (clearFlag != ClearFlag.ClearNone)
|
|
cmd.ClearRenderTarget((clearFlag & ClearFlag.ClearDepth) != 0, (clearFlag & ClearFlag.ClearColor) != 0, clearColor);
|
|
renderContext.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
|
|
// Miscellanous
|
|
public static Material CreateEngineMaterial(string shaderPath)
|
|
{
|
|
var mat = new Material(Shader.Find(shaderPath))
|
|
{
|
|
hideFlags = HideFlags.HideAndDontSave
|
|
};
|
|
return mat;
|
|
}
|
|
|
|
public static void Destroy(UnityObject obj)
|
|
{
|
|
if (obj != null)
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (Application.isPlaying)
|
|
UnityObject.Destroy(obj);
|
|
else
|
|
UnityObject.DestroyImmediate(obj);
|
|
#else
|
|
UnityObject.Destroy(obj);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public static void SafeRelease(ComputeBuffer buffer)
|
|
{
|
|
if (buffer != null)
|
|
buffer.Release();
|
|
}
|
|
|
|
public static string GetFieldPath<TType, TValue>(Expression<Func<TType, TValue>> expr)
|
|
{
|
|
MemberExpression me;
|
|
switch (expr.Body.NodeType)
|
|
{
|
|
case ExpressionType.Convert:
|
|
case ExpressionType.ConvertChecked:
|
|
var ue = expr.Body as UnaryExpression;
|
|
me = (ue != null ? ue.Operand : null) as MemberExpression;
|
|
break;
|
|
default:
|
|
me = expr.Body as MemberExpression;
|
|
break;
|
|
}
|
|
|
|
var members = new List<string>();
|
|
while (me != null)
|
|
{
|
|
members.Add(me.Member.Name);
|
|
me = me.Expression as MemberExpression;
|
|
}
|
|
|
|
var sb = new StringBuilder();
|
|
for (int i = members.Count - 1; i >= 0; i--)
|
|
{
|
|
sb.Append(members[i]);
|
|
if (i > 0) sb.Append('.');
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public class ProfilingSample
|
|
: IDisposable
|
|
{
|
|
bool disposed = false;
|
|
ScriptableRenderContext renderContext;
|
|
string name;
|
|
|
|
public ProfilingSample(string _name, ScriptableRenderContext _renderloop)
|
|
{
|
|
renderContext = _renderloop;
|
|
name = _name;
|
|
|
|
CommandBuffer cmd = new CommandBuffer();
|
|
cmd.name = "";
|
|
cmd.BeginSample(name);
|
|
renderContext.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
|
|
~ProfilingSample()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
}
|
|
|
|
// Protected implementation of Dispose pattern.
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposed)
|
|
return;
|
|
|
|
if (disposing)
|
|
{
|
|
CommandBuffer cmd = new CommandBuffer();
|
|
cmd.name = "";
|
|
cmd.EndSample(name);
|
|
renderContext.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
|
|
disposed = true;
|
|
}
|
|
}
|
|
|
|
public static Matrix4x4 GetViewProjectionMatrix(Matrix4x4 worldToViewMatrix, Matrix4x4 projectionMatrix)
|
|
{
|
|
// The actual projection matrix used in shaders is actually massaged a bit to work across all platforms
|
|
// (different Z value ranges etc.)
|
|
var gpuProj = GL.GetGPUProjectionMatrix(projectionMatrix, false);
|
|
var gpuVP = gpuProj * worldToViewMatrix * Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f)); // Need to scale -1.0 on Z to match what is being done in the camera.wolrdToCameraMatrix API.
|
|
|
|
return gpuVP;
|
|
}
|
|
|
|
public static HDCamera GetHDCamera(Camera camera)
|
|
{
|
|
HDCamera hdCamera = new HDCamera();
|
|
hdCamera.camera = camera;
|
|
hdCamera.screenSize = new Vector4(camera.pixelWidth, camera.pixelHeight, 1.0f / camera.pixelWidth, 1.0f / camera.pixelHeight);
|
|
|
|
// The actual projection matrix used in shaders is actually massaged a bit to work across all platforms
|
|
// (different Z value ranges etc.)
|
|
var gpuProj = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
|
|
var gpuVP = gpuProj * camera.worldToCameraMatrix;
|
|
|
|
hdCamera.viewProjectionMatrix = gpuVP;
|
|
hdCamera.invViewProjectionMatrix = gpuVP.inverse;
|
|
hdCamera.invProjectionMatrix = gpuProj.inverse;
|
|
|
|
return hdCamera;
|
|
}
|
|
|
|
public static void SetupMaterialHDCamera(HDCamera hdCamera, Material material)
|
|
{
|
|
material.SetVector("_ScreenSize", hdCamera.screenSize);
|
|
material.SetMatrix("_ViewProjMatrix", hdCamera.viewProjectionMatrix);
|
|
material.SetMatrix("_InvViewProjMatrix", hdCamera.invViewProjectionMatrix);
|
|
}
|
|
|
|
// TEMP: These functions should be implemented C++ side, for now do it in C#
|
|
public static void SetMatrixCS(CommandBuffer cmd, ComputeShader shadercs, string name, Matrix4x4 mat)
|
|
{
|
|
var data = new float[16];
|
|
|
|
for (int c = 0; c < 4; c++)
|
|
for (int r = 0; r < 4; r++)
|
|
data[4 * c + r] = mat[r, c];
|
|
|
|
cmd.SetComputeFloatParams(shadercs, name, data);
|
|
}
|
|
|
|
public static void SetMatrixArrayCS(CommandBuffer cmd, ComputeShader shadercs, string name, Matrix4x4[] matArray)
|
|
{
|
|
int numMatrices = matArray.Length;
|
|
var data = new float[numMatrices * 16];
|
|
|
|
for (int n = 0; n < numMatrices; n++)
|
|
for (int c = 0; c < 4; c++)
|
|
for (int r = 0; r < 4; r++)
|
|
data[16 * n + 4 * c + r] = matArray[n][r, c];
|
|
|
|
cmd.SetComputeFloatParams(shadercs, name, data);
|
|
}
|
|
|
|
public static void SetVectorArrayCS(CommandBuffer cmd, ComputeShader shadercs, string name, Vector4[] vecArray)
|
|
{
|
|
int numVectors = vecArray.Length;
|
|
var data = new float[numVectors * 4];
|
|
|
|
for (int n = 0; n < numVectors; n++)
|
|
for (int i = 0; i < 4; i++)
|
|
data[4 * n + i] = vecArray[n][i];
|
|
|
|
cmd.SetComputeFloatParams(shadercs, name, data);
|
|
}
|
|
|
|
public static void SetKeyword(Material m, string keyword, bool state)
|
|
{
|
|
if (state)
|
|
m.EnableKeyword(keyword);
|
|
else
|
|
m.DisableKeyword(keyword);
|
|
}
|
|
|
|
public static void SelectKeyword(Material material, string keyword1, string keyword2, bool enableFirst)
|
|
{
|
|
material.EnableKeyword (enableFirst ? keyword1 : keyword2);
|
|
material.DisableKeyword(enableFirst ? keyword2 : keyword1);
|
|
}
|
|
|
|
public static void SelectKeyword(Material material, string[] keywords, int enabledKeywordIndex)
|
|
{
|
|
material.EnableKeyword(keywords[enabledKeywordIndex]);
|
|
|
|
for (int i = 0; i < keywords.Length; i++)
|
|
{
|
|
if (i != enabledKeywordIndex)
|
|
{
|
|
material.DisableKeyword(keywords[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static HDRenderPipeline GetHDRenderPipeline()
|
|
{
|
|
HDRenderPipeline renderContext = GraphicsSettings.renderPipelineAsset as HDRenderPipeline;
|
|
if (renderContext == null)
|
|
{
|
|
Debug.LogWarning("SkyParameters component can only be used with HDRenderPipeline custom RenderPipeline.");
|
|
return null;
|
|
}
|
|
|
|
return renderContext;
|
|
}
|
|
|
|
static Mesh m_ScreenSpaceTriangle = null;
|
|
|
|
static Mesh GetScreenSpaceTriangle()
|
|
{
|
|
// If the assembly has been reloaded, the pointer will become NULL.
|
|
if (!m_ScreenSpaceTriangle)
|
|
{
|
|
m_ScreenSpaceTriangle = new Mesh
|
|
{
|
|
// Note: neither the vertex nor the index data is actually used if the vertex shader computes vertices
|
|
// using 'SV_VertexID'. However, there is currently no way to bind NULL vertex or index buffers.
|
|
vertices = new[] { new Vector3(-1, -1, 1), new Vector3(3, -1, 1), new Vector3(-1, 3, 1) },
|
|
triangles = new[] { 0, 1, 2 }
|
|
};
|
|
}
|
|
|
|
return m_ScreenSpaceTriangle;
|
|
}
|
|
|
|
// Draws a full screen triangle as a faster alternative to drawing a full-screen quad.
|
|
public static void DrawFullscreen(CommandBuffer commandBuffer, Material material, HDCamera camera,
|
|
RenderTargetIdentifier colorBuffer,
|
|
MaterialPropertyBlock properties = null, int shaderPassID = 0)
|
|
{
|
|
SetupMaterialHDCamera(camera, material);
|
|
commandBuffer.SetRenderTarget(colorBuffer);
|
|
commandBuffer.DrawMesh(GetScreenSpaceTriangle(), Matrix4x4.identity, material, 0, shaderPassID, properties);
|
|
}
|
|
|
|
// Draws a full screen triangle as a faster alternative to drawing a full-screen quad.
|
|
public static void DrawFullscreen(CommandBuffer commandBuffer, Material material, HDCamera camera,
|
|
RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthStencilBuffer,
|
|
MaterialPropertyBlock properties = null, int shaderPassID = 0)
|
|
{
|
|
SetupMaterialHDCamera(camera, material);
|
|
commandBuffer.SetRenderTarget(colorBuffer, depthStencilBuffer);
|
|
commandBuffer.DrawMesh(GetScreenSpaceTriangle(), Matrix4x4.identity, material, 0, shaderPassID, properties);
|
|
}
|
|
|
|
// Draws a full screen triangle as a faster alternative to drawing a full-screen quad.
|
|
public static void DrawFullscreen(CommandBuffer commandBuffer, Material material, HDCamera camera,
|
|
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthStencilBuffer,
|
|
MaterialPropertyBlock properties = null, int shaderPassID = 0)
|
|
{
|
|
SetupMaterialHDCamera(camera, material);
|
|
commandBuffer.SetRenderTarget(colorBuffers, depthStencilBuffer);
|
|
commandBuffer.DrawMesh(GetScreenSpaceTriangle(), Matrix4x4.identity, material, 0, shaderPassID, properties);
|
|
}
|
|
|
|
// Draws a full screen triangle as a faster alternative to drawing a full-screen quad.
|
|
// Important: the first RenderTarget must be created with 0 depth bits!
|
|
public static void DrawFullscreen(CommandBuffer commandBuffer, Material material, HDCamera camera,
|
|
RenderTargetIdentifier[] colorBuffers,
|
|
MaterialPropertyBlock properties = null, int shaderPassID = 0)
|
|
{
|
|
// It is currently not possible to have MRT without also setting a depth target.
|
|
// To work around this deficiency of the CommandBuffer.SetRenderTarget() API,
|
|
// we pass the first color target as the depth target. If it has 0 depth bits,
|
|
// no depth target ends up being bound.
|
|
DrawFullscreen(commandBuffer, material, camera, colorBuffers, colorBuffers[0], properties, shaderPassID);
|
|
}
|
|
}
|
|
}
|