123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Rendering;
- using System;
- using UnityEngine.Profiling;
- using Unity.Collections;
- namespace EPOOutline
- {
- public static class BlitUtility
- {
- private static readonly int MainTexHash = Shader.PropertyToID("_MainTex");
- private static Vector4[] normals = new Vector4[]
- {
- new Vector4(-0.578f, -0.578f, -0.578f),
- new Vector4(0.578f, -0.578f, -0.578f),
- new Vector4(0.578f, 0.578f, -0.578f),
- new Vector4(-0.578f, 0.578f, -0.578f),
- new Vector4(-0.578f, 0.578f, 0.578f),
- new Vector4(0.578f, 0.578f, 0.578f),
- new Vector4(0.578f, -0.578f, 0.578f),
- new Vector4(-0.578f, -0.578f, 0.578f)
- };
- private static Vector4[] tempVertecies =
- {
- new Vector4(-0.5f, -0.5f, -0.5f, 1),
- new Vector4(0.5f, -0.5f, -0.5f, 1),
- new Vector4(0.5f, 0.5f, -0.5f, 1),
- new Vector4(-0.5f, 0.5f, -0.5f, 1),
- new Vector4(-0.5f, 0.5f, 0.5f, 1),
- new Vector4(0.5f, 0.5f, 0.5f, 1),
- new Vector4(0.5f, -0.5f, 0.5f, 1),
- new Vector4(-0.5f, -0.5f, 0.5f, 1)
- };
- private static VertexAttributeDescriptor[] vertexParams =
- new VertexAttributeDescriptor[]
- {
- new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 4),
- new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32)
- };
- public struct MeshSetupResult
- {
- public readonly int VertexIndex;
- public readonly int TriangleIndex;
- public MeshSetupResult(int vertexIndex, int triangleIndex)
- {
- VertexIndex = vertexIndex;
- TriangleIndex = triangleIndex;
- }
- }
- private static ushort[] indecies = new ushort[4096 * 5];
- private static Vertex[] vertices = new Vertex[4096];
- private static Matrix4x4[] matrices = new Matrix4x4[4096];
- private static int itemsToDraw = 0;
- private static bool? supportsInstancing;
- private static bool SupportsInstancing
- {
- get
- {
- if (supportsInstancing.HasValue)
- return supportsInstancing.Value;
- supportsInstancing = SystemInfo.supportsInstancing;
- return supportsInstancing.Value;
- }
- }
- [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
- public struct Vertex
- {
- public Vector4 Position;
- public Vector3 Normal;
- }
- private static void UpdateBounds(Renderer renderer, OutlineTarget target)
- {
- if (target.renderer is MeshRenderer)
- {
- var meshFilter = renderer.GetComponent<MeshFilter>();
- if (meshFilter.sharedMesh != null)
- meshFilter.sharedMesh.RecalculateBounds();
- }
- else if (target.renderer is SkinnedMeshRenderer)
- {
- var skinedMeshRenderer = renderer as SkinnedMeshRenderer;
- if (skinedMeshRenderer.sharedMesh != null)
- skinedMeshRenderer.sharedMesh.RecalculateBounds();
- }
- }
- public static void PrepareForRendering(OutlineParameters parameters)
- {
- if (parameters.BlitMesh == null)
- parameters.BlitMesh = parameters.MeshPool.AllocateMesh();
- var result = SupportsInstancing ?
- SetupForInstancing(parameters) :
- SetupForBruteForce(parameters);
- if (!result.HasValue)
- return;
- const MeshUpdateFlags flags = MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds | MeshUpdateFlags.DontValidateIndices;
-
- parameters.BlitMesh.SetVertexBufferParams(result.Value.VertexIndex, attributes: vertexParams);
- parameters.BlitMesh.SetVertexBufferData(vertices, 0, 0, result.Value.VertexIndex, 0, flags);
- parameters.BlitMesh.SetIndexBufferParams(result.Value.TriangleIndex, IndexFormat.UInt16);
- parameters.BlitMesh.SetIndexBufferData(indecies, 0, 0, result.Value.TriangleIndex, flags);
- parameters.BlitMesh.subMeshCount = 1;
- parameters.BlitMesh.SetSubMesh(0, new SubMeshDescriptor(0, result.Value.TriangleIndex, MeshTopology.Triangles), flags);
- }
- private static MeshSetupResult? SetupForInstancing(OutlineParameters parameters)
- {
- if (vertices.Length < 8)
- {
- Array.Resize(ref vertices, 16);
- Array.Resize(ref indecies, vertices.Length * 5);
- }
- MeshSetupResult? result = null;
- var triangleIndex = 0;
- var currentIndex = 0;
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 3);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 3);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 3);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- for (var index = 0; index < 8; index++)
- {
- vertices[currentIndex++] = new Vertex()
- {
- Position = tempVertecies[index],
- Normal = normals[index]
- };
- }
- result = new MeshSetupResult(currentIndex, triangleIndex);
- var itemIndex = 0;
- foreach (var outlinable in parameters.OutlinablesToRender)
- {
- if (outlinable.DrawingMode != OutlinableDrawingMode.Normal)
- continue;
- foreach (var target in outlinable.OutlineTargets)
- {
- var renderer = target.Renderer;
- if (!target.IsVisible)
- continue;
- var pretransformedBounds = false;
- var bounds = new Bounds();
- if (target.BoundsMode == BoundsMode.Manual)
- {
- bounds = target.Bounds;
- var size = bounds.size;
- var rendererScale = renderer.transform.localScale;
- size.x /= rendererScale.x;
- size.y /= rendererScale.y;
- size.z /= rendererScale.z;
- bounds.size = size;
- }
- else
- {
- if (target.BoundsMode == BoundsMode.ForceRecalculate)
- UpdateBounds(target.Renderer, target);
- var meshRenderer = renderer as MeshRenderer;
- var index = (meshRenderer == null ? 0 : meshRenderer.subMeshStartIndex) + target.SubmeshIndex;
- var filter = meshRenderer == null ? null : meshRenderer.GetComponent<MeshFilter>();
- var mesh = filter == null ? null : filter.sharedMesh;
-
- if (mesh != null && mesh.subMeshCount > index)
- {
- bounds = mesh.GetSubMesh(index).bounds;
- pretransformedBounds = meshRenderer.isPartOfStaticBatch;
- }
- else
- {
- pretransformedBounds = true;
- bounds = renderer.bounds;
- }
- }
- if (pretransformedBounds)
- matrices[itemIndex++] = Matrix4x4.TRS(bounds.center, Quaternion.identity, bounds.size);
- else
- {
- var targetTransform = target.renderer.transform;
- var size = bounds.size;
- matrices[itemIndex++] = targetTransform.localToWorldMatrix * Matrix4x4.Translate(bounds.center) * Matrix4x4.Scale(size);
- }
- }
- }
- itemsToDraw = itemIndex;
- return result;
- }
- private static MeshSetupResult? SetupForBruteForce(OutlineParameters parameters)
- {
- const int numberOfVertices = 8;
- var currentIndex = 0;
- var triangleIndex = 0;
- var expectedCount = 0;
- foreach (var outlinable in parameters.OutlinablesToRender)
- expectedCount += numberOfVertices * outlinable.OutlineTargets.Count;
- if (vertices.Length < expectedCount)
- {
- Array.Resize(ref vertices, expectedCount * 2);
- Array.Resize(ref indecies, vertices.Length * 5);
- }
- foreach (var outlinable in parameters.OutlinablesToRender)
- {
- if (outlinable.DrawingMode != OutlinableDrawingMode.Normal)
- continue;
- foreach (var target in outlinable.OutlineTargets)
- {
- var renderer = target.Renderer;
- if (!target.IsVisible)
- continue;
- var pretransformedBounds = false;
- var bounds = new Bounds();
- if (target.BoundsMode == BoundsMode.Manual)
- {
- bounds = target.Bounds;
- var size = bounds.size;
- var rendererScale = renderer.transform.localScale;
- size.x /= rendererScale.x;
- size.y /= rendererScale.y;
- size.z /= rendererScale.z;
- bounds.size = size;
- }
- else
- {
- if (target.BoundsMode == BoundsMode.ForceRecalculate)
- UpdateBounds(target.Renderer, target);
- var meshRenderer = renderer as MeshRenderer;
- var index = (meshRenderer == null ? 0 : meshRenderer.subMeshStartIndex) + target.SubmeshIndex;
- var filter = meshRenderer == null ? null : meshRenderer.GetComponent<MeshFilter>();
- var mesh = filter == null ? null : filter.sharedMesh;
- if (mesh != null && mesh.subMeshCount > index)
- bounds = mesh.GetSubMesh(index).bounds;
- else
- {
- pretransformedBounds = true;
- bounds = renderer.bounds;
- }
- }
- Vector4 boundsSize = bounds.size;
- boundsSize.w = 1;
- var boundsCenter = (Vector4)bounds.center;
- var transformMatrix = Matrix4x4.identity;
- var normalTransformMatrix = Matrix4x4.identity;
- if (!pretransformedBounds && (target.BoundsMode == BoundsMode.Manual || !renderer.isPartOfStaticBatch))
- {
- transformMatrix = target.renderer.transform.localToWorldMatrix;
- normalTransformMatrix = Matrix4x4.Rotate(renderer.transform.rotation);
- }
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 3);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 3);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)(currentIndex + 2);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 3);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 4);
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)(currentIndex + 5);
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- indecies[triangleIndex++] = (ushort)(currentIndex + 7);
- indecies[triangleIndex++] = (ushort)currentIndex;
- indecies[triangleIndex++] = (ushort)(currentIndex + 1);
- indecies[triangleIndex++] = (ushort)(currentIndex + 6);
- for (var index = 0; index < numberOfVertices; index++)
- {
- var normal = normalTransformMatrix * normals[index];
- var vert = tempVertecies[index];
- var scaledVert = new Vector4(vert.x * boundsSize.x, vert.y * boundsSize.y, vert.z * boundsSize.z, 1);
- var vertex = new Vertex()
- {
- Position = transformMatrix * (boundsCenter + scaledVert),
- Normal = normal
- };
- vertices[currentIndex++] = vertex;
- }
- }
- }
- return new MeshSetupResult(currentIndex, triangleIndex);
- }
- public static void Blit(OutlineParameters parameters, RenderTargetIdentifier source, RenderTargetIdentifier destination, RenderTargetIdentifier destinationDepth, Material material, CommandBuffer targetBuffer, int pass = -1, Rect? viewport = null)
- {
- var buffer = targetBuffer == null ? parameters.Buffer : targetBuffer;
- buffer.SetRenderTarget(destination, destinationDepth);
- if (viewport.HasValue)
- parameters.Buffer.SetViewport(viewport.Value);
- buffer.SetGlobalTexture(MainTexHash, source);
- if (SupportsInstancing)
- buffer.DrawMeshInstanced(parameters.BlitMesh, 0, material, pass, matrices, itemsToDraw);
- else
- buffer.DrawMesh(parameters.BlitMesh, Matrix4x4.identity, material, 0, pass);
- }
- public static void Draw(OutlineParameters parameters, RenderTargetIdentifier target, RenderTargetIdentifier depth, Material material, Rect? viewport = null)
- {
- parameters.Buffer.SetRenderTarget(target, depth);
- if (viewport.HasValue)
- parameters.Buffer.SetViewport(viewport.Value);
- if (SupportsInstancing)
- parameters.Buffer.DrawMeshInstanced(parameters.BlitMesh, 0, material, -1, matrices, itemsToDraw);
- else
- parameters.Buffer.DrawMesh(parameters.BlitMesh, Matrix4x4.identity, material, 0, -1);
- }
- }
- }
|