浏览代码

changed to use a 2d texture atlas instead of texture 2d array for decals rendered in the transparent pass

/main
Paul Melamed 6 年前
当前提交
19e30640
共有 3 个文件被更改,包括 99 次插入90 次删除
  1. 41
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs
  2. 39
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalUtilities.hlsl
  3. 109
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Texture2DAtlas.cs

41
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs


public class DecalSystem
{
public const int kInvalidIndex = -1;
public const int kDecalAtlasWidth = 128;
public const int kDecalAtlasHeight = 128;
const int kDecalAtlasSlices = 256; // 128x128x256 argb32 = 16MB......
public class DecalHandle
{
public DecalHandle(int index, int materialID)

}
}
public TextureCache2D TextureAtlas
{
get
{
if (m_DecalAtlas == null)
{
m_DecalAtlas = new TextureCache2D("DecalAtlas");
m_DecalAtlas.AllocTextureArray(kDecalAtlasSlices, kDecalAtlasWidth, kDecalAtlasHeight, TextureFormat.ARGB32, true);
}
return m_DecalAtlas;
}
}
public Camera CurrentCamera
{
get

private Texture2DAtlas m_Atlas = null;
public static int kDecalAtlasWidth = 4096;
public static int kDecalAtlasHeight= 4096;
public Texture2DAtlas Atlas
{
get

m_Atlas = new Texture2DAtlas(4096, 4096, RenderTextureFormat.ARGB32);
m_Atlas = new Texture2DAtlas(kDecalAtlasWidth, kDecalAtlasHeight, RenderTextureFormat.ARGB32);
}
return m_Atlas;
}

void UpdateTextureCache(CommandBuffer cmd)
{
// m_DiffuseTexIndex = (m_DiffuseTexture != null) ? instance.TextureAtlas.FetchSlice(cmd, m_DiffuseTexture) : -1;
// m_NormalTexIndex = (m_NormalTexture != null) ? instance.TextureAtlas.FetchSlice(cmd, m_NormalTexture) : -1;
// m_MaskTexIndex = (m_MaskTexture != null) ? instance.TextureAtlas.FetchSlice(cmd, m_MaskTexture) : -1;
m_NormalScaleBias = (m_NormalTexture != null) ? instance.Atlas.AddTexture(cmd, m_NormalTexture) : Vector4.zero;
m_MaskScaleBias = (m_MaskTexture != null) ? instance.Atlas.AddTexture(cmd, m_MaskTexture) : Vector4.zero;
if (m_DiffuseTexture != null)
{
instance.TextureAtlas.RemoveEntryFromSlice(m_DiffuseTexture);
}
if (m_NormalTexture != null)
{
instance.TextureAtlas.RemoveEntryFromSlice(m_NormalTexture);
}
if (m_MaskTexture != null)
{
instance.TextureAtlas.RemoveEntryFromSlice(m_MaskTexture);
}
}
public void UpdateCachedMaterialData(CommandBuffer cmd)

// updates textures, texture atlas indices and blend value
public void UpdateCachedMaterialData(CommandBuffer cmd)
{
Atlas.ResetAllocator();
foreach (var pair in m_DecalSets)
{
pair.Value.UpdateCachedMaterialData(cmd);

39
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalUtilities.hlsl


// Caution: We can't compute LOD inside a dynamic loop. The gradient are not accessible.
// we need to find a way to calculate mips. For now just fetch first mip of the decals
void ApplyBlendNormal(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float3x3 decalToWorld, float blend, float lod)
void ApplyBlendNormal(inout float4 dst, inout int matMask, float2 texCoords, int mapMask, float3x3 decalToWorld, float blend, float lod)
src.xyz = mul(decalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, lod))) * 0.5f + 0.5f;
src.xyz = mul(decalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, sampler_DecalAtlas2D, texCoords, lod))) * 0.5f + 0.5f;
src.w = blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);
dst.w = dst.w * (1.0f - src.w);

void ApplyBlendDiffuse(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, inout float blend, float lod)
void ApplyBlendDiffuse(inout float4 dst, inout int matMask, float2 texCoords, int mapMask, inout float blend, float lod)
//float4 src = SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, lod);
float4 src = SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, sampler_DecalAtlas2D, texCoords, lod);
src.w *= blend;
blend = src.w; // diffuse texture alpha affects all other channels

}
void ApplyBlendMask(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float blend, float lod)
void ApplyBlendMask(inout float4 dst, inout int matMask, float2 texCoords, int mapMask, float blend, float lod)
float4 src = SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, lod);
float4 src = SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, sampler_DecalAtlas2D, texCoords, lod);
src.z = src.w;
src.w = blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);

decalStart = 0;
#endif
float3 positionWS = GetAbsolutePositionWS(posInput.positionWS);
uint i = 0;
for (i = 0; i < decalCount; i++)
for (uint i = 0; i < decalCount; i++)
int diffuseIndex = decalData.normalToWorld[1][3];
int normalIndex = decalData.normalToWorld[2][3];
int maskIndex = decalData.normalToWorld[3][3];
positionDS.xz = positionDS.xz * decalData.diffuseScaleBias.xy + decalData.diffuseScaleBias.zw;
float lod = ComputeTextureLOD(positionDS.xz, _DecalAtlasResolution * decalData.diffuseScaleBias.xy);
float2 sampleDiffuse = positionDS.xz * decalData.diffuseScaleBias.xy + decalData.diffuseScaleBias.zw;
float2 sampleNormal = positionDS.xz * decalData.normalScaleBias.xy + decalData.normalScaleBias.zw;
float2 sampleMask = positionDS.xz * decalData.maskScaleBias.xy + decalData.maskScaleBias.zw;
float lodDiffuse = ComputeTextureLOD(sampleDiffuse, _DecalAtlasResolution * decalData.diffuseScaleBias.xy);
float lodNormal = ComputeTextureLOD(sampleNormal, _DecalAtlasResolution * decalData.normalScaleBias.xy);
float lodMask = ComputeTextureLOD(sampleMask, _DecalAtlasResolution * decalData.maskScaleBias.xy);
decalBlend = ((all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f))) ? decalBlend : 0; // use blend of 0 instead of an 'if' because compiler moves the lod calculation inside the 'if' which causes incorrect values
// if any of the pixels in the 2x2 quad gets rejected

if(diffuseIndex != -1)
if((decalData.diffuseScaleBias.x > 0) && (decalData.diffuseScaleBias.y > 0))
ApplyBlendDiffuse(DBuffer0, mask, positionDS.xz, diffuseIndex, DBUFFERHTILEBIT_DIFFUSE, decalBlend, lod);
ApplyBlendDiffuse(DBuffer0, mask, sampleDiffuse, DBUFFERHTILEBIT_DIFFUSE, decalBlend, lodDiffuse);
if(normalIndex != -1)
if ((decalData.normalScaleBias.x > 0) && (decalData.normalScaleBias.y > 0))
ApplyBlendNormal(DBuffer1, mask, positionDS.xz, normalIndex, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend, lod);
ApplyBlendNormal(DBuffer1, mask, sampleNormal, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend, lodNormal);
if(maskIndex != -1)
if ((decalData.maskScaleBias.x > 0) && (decalData.maskScaleBias.y > 0))
ApplyBlendMask(DBuffer2, mask, positionDS.xz, maskIndex, DBUFFERHTILEBIT_MASK, decalBlend, lod);
ApplyBlendMask(DBuffer2, mask, sampleMask, DBUFFERHTILEBIT_MASK, decalBlend, lodMask);
}
}
#else

109
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Texture2DAtlas.cs


{
public AtlasNode m_RightChild = null;
public AtlasNode m_BottomChild = null;
public Rect m_Rect = new Rect(0,0,0,0);
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)
{

}
//leaf node, check for fit
if ((width <= m_Rect.width) && (height <= m_Rect.height))
if ((width <= m_Rect.x) && (height <= m_Rect.y))
if (width > height) // logic to decide which way to split +--------+------+
{ // | | |
m_RightChild.m_Rect.x = m_Rect.x + width; // | | |
m_RightChild.m_Rect.y = m_Rect.y; // +--------+------+
m_RightChild.m_Rect.width = m_Rect.width - width; // | |
m_RightChild.m_Rect.height = height; // | |
// +---------------+
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.y = m_Rect.y + height;
m_BottomChild.m_Rect.width = m_Rect.width;
m_BottomChild.m_Rect.height = m_Rect.height - height;
m_BottomChild.m_Rect.y = m_Rect.y - height;
{ // +---+-----------+
m_RightChild.m_Rect.x = m_Rect.x + width; // | | |
m_RightChild.m_Rect.y = m_Rect.y; // | | |
m_RightChild.m_Rect.width = m_Rect.width - width; // +---+ +
m_RightChild.m_Rect.height = m_Rect.height; // | | |
// | | |
m_BottomChild.m_Rect.x = m_Rect.x; // +---+-----------+
m_BottomChild.m_Rect.y = m_Rect.y + height;
m_BottomChild.m_Rect.width = m_Rect.width;
m_BottomChild.m_Rect.height = m_Rect.height - height;
{ // +---+-----------+
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.width = width;
m_Rect.height = height;
m_Rect.x = width;
m_Rect.y = height;
public void Release()
{
if (m_RightChild != null)
{
m_RightChild.Release();
m_BottomChild.Release();
}
m_RightChild = null;
m_BottomChild = null;
}
private int m_Width;
private int m_Height;
m_Root.m_Rect.Set(0, 0, width, height);
m_Root.m_Rect.Set(width, height, 0, 0);
m_Width = width;
m_Height = height;
public Rect Allocate(int width, int height)
public Vector4 Allocate(int width, int height)
{
AtlasNode node = m_Root.Allocate(width, height);
if(node != null)

else
{
return new Rect(0, 0, 0, 0);
return new Vector4(0, 0, 0, 0);
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 RenderTextureFormat m_Format;
private AtlasAllocator m_AtlasAllocator = null;
public RTHandle AtlasTexture
{

false,
true,
false);
m_AtlasAllocator = new AtlasAllocator(width, height);
}
public void Release()

public void ResetAllocator()
{
m_AtlasAllocator.Release();
}
float scaleW = (float)texture.width / m_Width;
float scaleH = (float) texture.height / m_Height;
Vector4 scaleBias = new Vector4(scaleW, scaleH, 0, 0);
for (int mipLevel = 0; mipLevel < (texture as Texture2D).mipmapCount; mipLevel++)
int width = texture.width;
int height = texture.height;
Vector4 scaleBias = m_AtlasAllocator.Allocate(width, height);
if ((scaleBias.x > 0) && (scaleBias.y > 0))
{
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);
}
return scaleBias;
}
else
cmd.SetRenderTarget(m_AtlasTexture, mipLevel);
HDUtils.BlitQuad(cmd, texture, new Vector4(1, 1, 0, 0), scaleBias, mipLevel, false);
return new Vector4(0,0,0,0);
return scaleBias;
}
}
}
正在加载...
取消
保存