您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
195 行
6.9 KiB
195 行
6.9 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Experimental.Rendering.HDPipeline;
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
namespace UnityEngine.Experimental.Rendering
|
|
{
|
|
public class AtlasAllocator
|
|
{
|
|
private class AtlasNode
|
|
{
|
|
public AtlasNode m_RightChild = null;
|
|
public AtlasNode m_BottomChild = null;
|
|
public Vector4 m_Rect = new Vector4(0, 0, 0, 0); // x,y is width and height (scale) z,w offset into atlas (bias)
|
|
|
|
public AtlasNode Allocate(int width, int height)
|
|
{
|
|
// not a leaf node, try children
|
|
if (m_RightChild != null)
|
|
{
|
|
AtlasNode node = m_RightChild.Allocate(width, height);
|
|
if (node == null)
|
|
{
|
|
node = m_BottomChild.Allocate(width, height);
|
|
}
|
|
return node;
|
|
}
|
|
|
|
//leaf node, check for fit
|
|
if ((width <= m_Rect.x) && (height <= m_Rect.y))
|
|
{
|
|
// perform the split
|
|
m_RightChild = new AtlasNode();
|
|
m_BottomChild = new AtlasNode();
|
|
|
|
if (width > height) // logic to decide which way to split
|
|
{ // +--------+------+
|
|
m_RightChild.m_Rect.z = m_Rect.z + width; // | | |
|
|
m_RightChild.m_Rect.w = m_Rect.w; // +--------+------+
|
|
m_RightChild.m_Rect.x = m_Rect.x - width; // | |
|
|
m_RightChild.m_Rect.y = height; // | |
|
|
// +---------------+
|
|
m_BottomChild.m_Rect.z = m_Rect.z;
|
|
m_BottomChild.m_Rect.w = m_Rect.w + height;
|
|
m_BottomChild.m_Rect.x = m_Rect.x;
|
|
m_BottomChild.m_Rect.y = m_Rect.y - height;
|
|
}
|
|
else
|
|
{ // +---+-----------+
|
|
m_RightChild.m_Rect.z = m_Rect.z + width; // | | |
|
|
m_RightChild.m_Rect.w = m_Rect.w; // | | |
|
|
m_RightChild.m_Rect.x = m_Rect.x - width; // +---+ +
|
|
m_RightChild.m_Rect.y = m_Rect.y; // | | |
|
|
// +---+-----------+
|
|
m_BottomChild.m_Rect.z = m_Rect.z;
|
|
m_BottomChild.m_Rect.w = m_Rect.w + height;
|
|
m_BottomChild.m_Rect.x = width;
|
|
m_BottomChild.m_Rect.y = m_Rect.y - height;
|
|
}
|
|
m_Rect.x = width;
|
|
m_Rect.y = height;
|
|
return this;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
if (m_RightChild != null)
|
|
{
|
|
m_RightChild.Release();
|
|
m_BottomChild.Release();
|
|
}
|
|
m_RightChild = null;
|
|
m_BottomChild = null;
|
|
}
|
|
}
|
|
|
|
private AtlasNode m_Root;
|
|
private int m_Width;
|
|
private int m_Height;
|
|
|
|
public AtlasAllocator(int width, int height)
|
|
{
|
|
m_Root = new AtlasNode();
|
|
m_Root.m_Rect.Set(width, height, 0, 0);
|
|
m_Width = width;
|
|
m_Height = height;
|
|
}
|
|
|
|
public bool Allocate(ref Vector4 result, int width, int height)
|
|
{
|
|
AtlasNode node = m_Root.Allocate(width, height);
|
|
if (node != null)
|
|
{
|
|
result = node.m_Rect;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
result = Vector4.zero;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
m_Root.Release();
|
|
m_Root = new AtlasNode();
|
|
m_Root.m_Rect.Set(m_Width, m_Height, 0, 0);
|
|
}
|
|
}
|
|
|
|
public class Texture2DAtlas
|
|
{
|
|
private RTHandleSystem.RTHandle m_AtlasTexture = null;
|
|
private int m_Width;
|
|
private int m_Height;
|
|
private RenderTextureFormat m_Format;
|
|
private AtlasAllocator m_AtlasAllocator = null;
|
|
private Dictionary<IntPtr, Vector4> m_AllocationCache = new Dictionary<IntPtr, Vector4>();
|
|
|
|
public RTHandleSystem.RTHandle AtlasTexture
|
|
{
|
|
get
|
|
{
|
|
return m_AtlasTexture;
|
|
}
|
|
}
|
|
|
|
public Texture2DAtlas(int width, int height, RenderTextureFormat format)
|
|
{
|
|
m_Width = width;
|
|
m_Height = height;
|
|
m_Format = format;
|
|
m_AtlasTexture = RTHandles.Alloc(m_Width,
|
|
m_Height,
|
|
1,
|
|
DepthBits.None,
|
|
m_Format,
|
|
FilterMode.Point,
|
|
TextureWrapMode.Clamp,
|
|
TextureDimension.Tex2D,
|
|
false,
|
|
false,
|
|
true,
|
|
false);
|
|
|
|
m_AtlasAllocator = new AtlasAllocator(width, height);
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
ResetAllocator();
|
|
RTHandles.Release(m_AtlasTexture);
|
|
}
|
|
|
|
public void ResetAllocator()
|
|
{
|
|
m_AtlasAllocator.Release();
|
|
m_AllocationCache.Clear();
|
|
}
|
|
|
|
public bool AddTexture(CommandBuffer cmd, ref Vector4 scaleBias, Texture texture)
|
|
{
|
|
IntPtr key = texture.GetNativeTexturePtr();
|
|
if (!m_AllocationCache.TryGetValue(key, out scaleBias))
|
|
{
|
|
int width = texture.width;
|
|
int height = texture.height;
|
|
if (m_AtlasAllocator.Allocate(ref scaleBias, width, height))
|
|
{
|
|
scaleBias.Scale(new Vector4(1.0f / m_Width, 1.0f / m_Height, 1.0f / m_Width, 1.0f / m_Height));
|
|
for (int mipLevel = 0; mipLevel < (texture as Texture2D).mipmapCount; mipLevel++)
|
|
{
|
|
cmd.SetRenderTarget(m_AtlasTexture, mipLevel);
|
|
HDUtils.BlitQuad(cmd, texture, new Vector4(1, 1, 0, 0), scaleBias, mipLevel, false);
|
|
}
|
|
m_AllocationCache.Add(key, scaleBias);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|