您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
476 行
19 KiB
476 行
19 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.PostProcessing;
|
|
|
|
namespace UnityEngine.Experimental.Rendering
|
|
{
|
|
using UnityObject = UnityEngine.Object;
|
|
|
|
[Flags]
|
|
public enum ClearFlag
|
|
{
|
|
None = 0,
|
|
Color = 1,
|
|
Depth = 2,
|
|
|
|
All = Depth | Color
|
|
}
|
|
|
|
public static class CoreUtils
|
|
{
|
|
// Data useful for various cubemap processes.
|
|
// Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/bb204881(v=vs.85).aspx
|
|
static public readonly Vector3[] lookAtList =
|
|
{
|
|
new Vector3(1.0f, 0.0f, 0.0f),
|
|
new Vector3(-1.0f, 0.0f, 0.0f),
|
|
new Vector3(0.0f, 1.0f, 0.0f),
|
|
new Vector3(0.0f, -1.0f, 0.0f),
|
|
new Vector3(0.0f, 0.0f, 1.0f),
|
|
new Vector3(0.0f, 0.0f, -1.0f),
|
|
};
|
|
|
|
static public readonly Vector3[] upVectorList =
|
|
{
|
|
new Vector3(0.0f, 1.0f, 0.0f),
|
|
new Vector3(0.0f, 1.0f, 0.0f),
|
|
new Vector3(0.0f, 0.0f, -1.0f),
|
|
new Vector3(0.0f, 0.0f, 1.0f),
|
|
new Vector3(0.0f, 1.0f, 0.0f),
|
|
new Vector3(0.0f, 1.0f, 0.0f),
|
|
};
|
|
|
|
// Note: Color.Black have alpha channel set to 1. Most of the time we want alpha channel set to 0 as we use black to clear render target
|
|
public static Color clearColorAllBlack { get { return new Color(0f, 0f, 0f, 0f); } }
|
|
|
|
public const int editMenuPriority1 = 320;
|
|
public const int editMenuPriority2 = 331;
|
|
public const int assetCreateMenuPriority1 = 230;
|
|
public const int assetCreateMenuPriority2 = 241;
|
|
public const int gameObjectMenuPriority = 10;
|
|
|
|
static Cubemap m_BlackCubeTexture;
|
|
public static Cubemap blackCubeTexture
|
|
{
|
|
get
|
|
{
|
|
if (m_BlackCubeTexture == null)
|
|
{
|
|
m_BlackCubeTexture = new Cubemap(1, TextureFormat.ARGB32, false);
|
|
for (int i = 0; i < 6; ++i)
|
|
m_BlackCubeTexture.SetPixel((CubemapFace)i, 0, 0, Color.black);
|
|
m_BlackCubeTexture.Apply();
|
|
}
|
|
|
|
return m_BlackCubeTexture;
|
|
}
|
|
}
|
|
|
|
static Cubemap m_MagentaCubeTexture;
|
|
public static Cubemap magentaCubeTexture
|
|
{
|
|
get
|
|
{
|
|
if (m_MagentaCubeTexture == null)
|
|
{
|
|
m_MagentaCubeTexture = new Cubemap(1, TextureFormat.ARGB32, false);
|
|
for (int i = 0; i < 6; ++i)
|
|
m_MagentaCubeTexture.SetPixel((CubemapFace)i, 0, 0, Color.magenta);
|
|
m_MagentaCubeTexture.Apply();
|
|
}
|
|
|
|
return m_MagentaCubeTexture;
|
|
}
|
|
}
|
|
|
|
static Cubemap m_WhiteCubeTexture;
|
|
public static Cubemap whiteCubeTexture
|
|
{
|
|
get
|
|
{
|
|
if (m_WhiteCubeTexture == null)
|
|
{
|
|
m_WhiteCubeTexture = new Cubemap(1, TextureFormat.ARGB32, false);
|
|
for (int i = 0; i < 6; ++i)
|
|
m_WhiteCubeTexture.SetPixel((CubemapFace)i, 0, 0, Color.white);
|
|
m_WhiteCubeTexture.Apply();
|
|
}
|
|
|
|
return m_WhiteCubeTexture;
|
|
}
|
|
}
|
|
|
|
// Render Target Management.
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier buffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)
|
|
{
|
|
cmd.SetRenderTarget(buffer, miplevel, cubemapFace, depthSlice);
|
|
|
|
if (clearFlag != ClearFlag.None)
|
|
cmd.ClearRenderTarget((clearFlag & ClearFlag.Depth) != 0, (clearFlag & ClearFlag.Color) != 0, clearColor);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier buffer, ClearFlag clearFlag = ClearFlag.None, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)
|
|
{
|
|
SetRenderTarget(cmd, buffer, clearFlag, clearColorAllBlack, miplevel, cubemapFace, depthSlice);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)
|
|
{
|
|
SetRenderTarget(cmd, colorBuffer, depthBuffer, ClearFlag.None, clearColorAllBlack, miplevel, cubemapFace, depthSlice);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)
|
|
{
|
|
SetRenderTarget(cmd, colorBuffer, depthBuffer, clearFlag, clearColorAllBlack, miplevel, cubemapFace, depthSlice);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)
|
|
{
|
|
cmd.SetRenderTarget(colorBuffer, depthBuffer, miplevel, cubemapFace, depthSlice);
|
|
|
|
if (clearFlag != ClearFlag.None)
|
|
cmd.ClearRenderTarget((clearFlag & ClearFlag.Depth) != 0, (clearFlag & ClearFlag.Color) != 0, clearColor);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer)
|
|
{
|
|
SetRenderTarget(cmd, colorBuffers, depthBuffer, ClearFlag.None, clearColorAllBlack);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag = ClearFlag.None)
|
|
{
|
|
SetRenderTarget(cmd, colorBuffers, depthBuffer, clearFlag, clearColorAllBlack);
|
|
}
|
|
|
|
public static void SetRenderTarget(CommandBuffer cmd, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor)
|
|
{
|
|
cmd.SetRenderTarget(colorBuffers, depthBuffer);
|
|
|
|
if (clearFlag != ClearFlag.None)
|
|
cmd.ClearRenderTarget((clearFlag & ClearFlag.Depth) != 0, (clearFlag & ClearFlag.Color) != 0, clearColor);
|
|
}
|
|
|
|
public static RenderTexture CreateRenderTexture(RenderTextureDescriptor baseDesc, int depthBufferBits, RenderTextureFormat format,
|
|
RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default)
|
|
{
|
|
baseDesc.depthBufferBits = depthBufferBits;
|
|
baseDesc.colorFormat = format;
|
|
baseDesc.sRGB = (readWrite != RenderTextureReadWrite.Linear);
|
|
|
|
// Depth-only needs bindMS in order to use with CopyTexture
|
|
if ((format == RenderTextureFormat.Depth) && (baseDesc.msaaSamples > 1))
|
|
baseDesc.bindMS = true;
|
|
|
|
return new RenderTexture(baseDesc);
|
|
}
|
|
|
|
public static void CreateCmdTemporaryRT(CommandBuffer cmd, int nameID, RenderTextureDescriptor baseDesc,
|
|
int depthBufferBits, FilterMode filter, RenderTextureFormat format,
|
|
RenderTextureReadWrite readWrite = RenderTextureReadWrite.Default, int msaaSamplesOverride = 0, bool enableRandomWrite = false)
|
|
{
|
|
if (msaaSamplesOverride > 0)
|
|
UpdateRenderTextureDescriptor(ref baseDesc, depthBufferBits, format, readWrite, msaaSamplesOverride, enableRandomWrite);
|
|
else
|
|
UpdateRenderTextureDescriptor(ref baseDesc, depthBufferBits, format, readWrite, baseDesc.msaaSamples, enableRandomWrite);
|
|
|
|
|
|
cmd.GetTemporaryRT(nameID, baseDesc, filter);
|
|
}
|
|
|
|
public static void UpdateRenderTextureDescriptor(ref RenderTextureDescriptor baseDesc, int depthBufferBits, RenderTextureFormat format, RenderTextureReadWrite readWrite, int msaaSamples, bool enableRandomWrite)
|
|
{
|
|
baseDesc.depthBufferBits = depthBufferBits;
|
|
baseDesc.colorFormat = format;
|
|
baseDesc.sRGB = (readWrite != RenderTextureReadWrite.Linear);
|
|
|
|
Debug.Assert(!enableRandomWrite || (msaaSamples == 1));
|
|
baseDesc.msaaSamples = msaaSamples;
|
|
baseDesc.enableRandomWrite = enableRandomWrite;
|
|
}
|
|
|
|
public static void ClearCubemap(CommandBuffer cmd, RenderTargetIdentifier buffer, Color clearColor)
|
|
{
|
|
// We should have the option to clear mip maps here, but since RenderTargetIdentifier, we can't know the number to clear...
|
|
// So for now, we won't do it.
|
|
for (int i = 0; i < 6; ++i)
|
|
SetRenderTarget(cmd, buffer, ClearFlag.Color, clearColor, 0, (CubemapFace)i);
|
|
}
|
|
|
|
public static void ClearCubemap(CommandBuffer cmd, RenderTexture renderTexture, Color clearColor, bool clearMips = false)
|
|
{
|
|
int mipCount = 1;
|
|
if (renderTexture.useMipMap && clearMips)
|
|
{
|
|
mipCount = (int)Mathf.Log((float)renderTexture.width, 2.0f) + 1;
|
|
}
|
|
|
|
for (int i = 0; i < 6; ++i)
|
|
{
|
|
for (int mip = 0; mip < mipCount; ++mip)
|
|
{
|
|
SetRenderTarget(cmd, new RenderTargetIdentifier(renderTexture), ClearFlag.Color, clearColor, mip, (CubemapFace)i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draws a full screen triangle as a faster alternative to drawing a full screen quad.
|
|
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
|
|
MaterialPropertyBlock properties = null, int shaderPassId = 0)
|
|
{
|
|
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
|
|
}
|
|
|
|
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
|
|
RenderTargetIdentifier colorBuffer,
|
|
MaterialPropertyBlock properties = null, int shaderPassId = 0)
|
|
{
|
|
commandBuffer.SetRenderTarget(colorBuffer);
|
|
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
|
|
}
|
|
|
|
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
|
|
RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthStencilBuffer,
|
|
MaterialPropertyBlock properties = null, int shaderPassId = 0)
|
|
{
|
|
commandBuffer.SetRenderTarget(colorBuffer, depthStencilBuffer);
|
|
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
|
|
}
|
|
|
|
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
|
|
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthStencilBuffer,
|
|
MaterialPropertyBlock properties = null, int shaderPassId = 0)
|
|
{
|
|
commandBuffer.SetRenderTarget(colorBuffers, depthStencilBuffer);
|
|
commandBuffer.DrawProcedural(Matrix4x4.identity, material, shaderPassId, MeshTopology.Triangles, 3, 1, properties);
|
|
}
|
|
|
|
// Important: the first RenderTarget must be created with 0 depth bits!
|
|
public static void DrawFullScreen(CommandBuffer commandBuffer, Material material,
|
|
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, colorBuffers, colorBuffers[0], properties, shaderPassId);
|
|
}
|
|
|
|
// Post-processing misc
|
|
public static bool IsPostProcessingActive(PostProcessLayer layer)
|
|
{
|
|
return layer != null
|
|
&& layer.enabled;
|
|
}
|
|
|
|
public static bool IsTemporalAntialiasingActive(PostProcessLayer layer)
|
|
{
|
|
return IsPostProcessingActive(layer)
|
|
&& layer.antialiasingMode == PostProcessLayer.Antialiasing.TemporalAntialiasing
|
|
&& layer.temporalAntialiasing.IsSupported();
|
|
}
|
|
|
|
// Color space utilities
|
|
public static Color ConvertSRGBToActiveColorSpace(Color color)
|
|
{
|
|
return (QualitySettings.activeColorSpace == ColorSpace.Linear) ? color.linear : color;
|
|
}
|
|
|
|
public static Color ConvertLinearToActiveColorSpace(Color color)
|
|
{
|
|
return (QualitySettings.activeColorSpace == ColorSpace.Linear) ? color : color.gamma;
|
|
}
|
|
|
|
// Unity specifics
|
|
public static Material CreateEngineMaterial(string shaderPath)
|
|
{
|
|
var mat = new Material(Shader.Find(shaderPath))
|
|
{
|
|
hideFlags = HideFlags.HideAndDontSave
|
|
};
|
|
return mat;
|
|
}
|
|
|
|
public static Material CreateEngineMaterial(Shader shader)
|
|
{
|
|
var mat = new Material(shader)
|
|
{
|
|
hideFlags = HideFlags.HideAndDontSave
|
|
};
|
|
return mat;
|
|
}
|
|
|
|
public static void SetKeyword(CommandBuffer cmd, string keyword, bool state)
|
|
{
|
|
if (state)
|
|
cmd.EnableShaderKeyword(keyword);
|
|
else
|
|
cmd.DisableShaderKeyword(keyword);
|
|
}
|
|
|
|
// Caution: such a call should not be use interlaced with command buffer command, as it is immediate
|
|
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 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 IEnumerable<Type> GetAllAssemblyTypes()
|
|
{
|
|
return AppDomain.CurrentDomain.GetAssemblies()
|
|
.SelectMany(t =>
|
|
{
|
|
// Ugly hack to handle mis-versioned dlls
|
|
var innerTypes = new Type[0];
|
|
try
|
|
{
|
|
innerTypes = t.GetTypes();
|
|
}
|
|
catch { }
|
|
return innerTypes;
|
|
});
|
|
}
|
|
|
|
public static void Destroy(params UnityObject[] objs)
|
|
{
|
|
if (objs == null)
|
|
return;
|
|
|
|
foreach (var o in objs)
|
|
Destroy(o);
|
|
}
|
|
|
|
public static void SafeRelease(ComputeBuffer buffer)
|
|
{
|
|
if (buffer != null)
|
|
buffer.Release();
|
|
}
|
|
|
|
// Just a sort function that doesn't allocate memory
|
|
// Note: Shoud be repalc by a radix sort for positive integer
|
|
public static int Partition(uint[] numbers, int left, int right)
|
|
{
|
|
uint pivot = numbers[left];
|
|
while (true)
|
|
{
|
|
while (numbers[left] < pivot)
|
|
left++;
|
|
|
|
while (numbers[right] > pivot)
|
|
right--;
|
|
|
|
if (left < right)
|
|
{
|
|
uint temp = numbers[right];
|
|
numbers[right] = numbers[left];
|
|
numbers[left] = temp;
|
|
}
|
|
else
|
|
{
|
|
return right;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void QuickSort(uint[] arr, int left, int right)
|
|
{
|
|
// For Recursion
|
|
if (left < right)
|
|
{
|
|
int pivot = Partition(arr, left, right);
|
|
|
|
if (pivot > 1)
|
|
QuickSort(arr, left, pivot - 1);
|
|
|
|
if (pivot + 1 < right)
|
|
QuickSort(arr, pivot + 1, right);
|
|
}
|
|
}
|
|
|
|
public static Mesh CreateCubeMesh(Vector3 min, Vector3 max)
|
|
{
|
|
Mesh mesh = new Mesh();
|
|
|
|
Vector3[] vertices = new Vector3[8];
|
|
|
|
vertices[0] = new Vector3(min.x, min.y, min.z);
|
|
vertices[1] = new Vector3(max.x, min.y, min.z);
|
|
vertices[2] = new Vector3(max.x, max.y, min.z);
|
|
vertices[3] = new Vector3(min.x, max.y, min.z);
|
|
vertices[4] = new Vector3(min.x, min.y, max.z);
|
|
vertices[5] = new Vector3(max.x, min.y, max.z);
|
|
vertices[6] = new Vector3(max.x, max.y, max.z);
|
|
vertices[7] = new Vector3(min.x, max.y, max.z);
|
|
|
|
mesh.vertices = vertices;
|
|
|
|
int[] triangles = new int[36];
|
|
|
|
triangles[0] = 0; triangles[1] = 2; triangles[2] = 1;
|
|
triangles[3] = 0; triangles[4] = 3; triangles[5] = 2;
|
|
triangles[6] = 1; triangles[7] = 6; triangles[8] = 5;
|
|
triangles[9] = 1; triangles[10] = 2; triangles[11] = 6;
|
|
triangles[12] = 5; triangles[13] = 7; triangles[14] = 4;
|
|
triangles[15] = 5; triangles[16] = 6; triangles[17] = 7;
|
|
triangles[18] = 4; triangles[19] = 3; triangles[20] = 0;
|
|
triangles[21] = 4; triangles[22] = 7; triangles[23] = 3;
|
|
triangles[24] = 3; triangles[25] = 6; triangles[26] = 2;
|
|
triangles[27] = 3; triangles[28] = 7; triangles[29] = 6;
|
|
triangles[30] = 4; triangles[31] = 1; triangles[32] = 5;
|
|
triangles[33] = 4; triangles[34] = 0; triangles[35] = 1;
|
|
|
|
mesh.triangles = triangles;
|
|
return mesh;
|
|
}
|
|
|
|
public static void ResizeHTile(ref RenderTexture hTile, ref RenderTargetIdentifier hTileRT, RenderTextureDescriptor desc)
|
|
{
|
|
// We must use a RenderTexture and not GetTemporaryRT() as currently Unity only aloow to bind a RenderTexture for a UAV in a pixel shader
|
|
// We use 8x8 tiles in order to match the native GCN HTile as closely as possible.
|
|
desc.width = (desc.width + 7) / 8;
|
|
desc.height = (desc.height + 7) / 8;
|
|
// TODO: This fails allocation with MSAA enabled?
|
|
hTile = CreateRenderTexture(desc, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear); // DXGI_FORMAT_R8_UINT is not supported by Unity
|
|
hTile.filterMode = FilterMode.Point;
|
|
hTile.enableRandomWrite = true;
|
|
hTile.Create();
|
|
hTileRT = new RenderTargetIdentifier(hTile);
|
|
}
|
|
}
|
|
}
|