浏览代码

Merge pull request #1178 from Unity-Technologies/decals/texture_atlas

Decals/texture atlas
/main
GitHub 6 年前
当前提交
bc2cc021
共有 18 个文件被更改,包括 495 次插入103 次删除
  1. 33
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Common.hlsl
  2. 170
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs
  3. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/GlobalDecalSettings.cs
  4. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/RenderLoopSettings/GlobalDecalSettingsUI.cs
  5. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/RenderLoopSettings/SerializedGlobalDecalSettings.cs
  6. 7
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs
  7. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs
  8. 9
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDUtils.cs
  9. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DBufferManager.cs
  10. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.cs
  11. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.cs.hlsl
  12. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.hlsl
  13. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalData.hlsl
  14. 103
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalUtilities.hlsl
  15. 33
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Blit.shader
  16. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassDBuffer.hlsl
  17. 195
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Texture2DAtlas.cs
  18. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Texture2DAtlas.cs.meta

33
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Common.hlsl


return float4(uv * 2.0 - 1.0, z, 1.0);
}
// draw procedural with 2 triangles has index order (0,1,2) (0,2,3)
// 0 - 0,0
// 1 - 0,1
// 2 - 1,1
// 3 - 1,0
float2 GetQuadTexCoord(uint vertexID)
{
uint topBit = vertexID >> 1;
uint botBit = (vertexID & 1);
float u = topBit;
float v = (topBit + botBit) & 1; // produces 0 for indices 0,3 and 1 for 1,2
#if UNITY_UV_STARTS_AT_TOP
v = 1.0 - v;
#endif
return float2(u, v);
}
// 0 - 0,1
// 1 - 0,0
// 2 - 1,0
// 3 - 1,1
float4 GetQuadVertexPosition(uint vertexID, float z = UNITY_NEAR_CLIP_VALUE)
{
uint topBit = vertexID >> 1;
uint botBit = (vertexID & 1);
float x = topBit;
float y = 1 - (topBit + botBit) & 1; // produces 1 for indices 0,3 and 0 for 1,2
return float4(x, y, z, 1.0);
}
#if !defined(SHADER_API_GLES)
// LOD dithering transition helper

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


using System.Collections.Generic;
using System;
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;

{
public const int kInvalidIndex = -1;
public const int kDecalAtlasSize = 128;
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(2048, kDecalAtlasSize, kDecalAtlasSize, TextureFormat.ARGB32, true);
}
return m_DecalAtlas;
}
}
public Camera CurrentCamera
{
get

static public float[] m_BoundingDistances = new float[1];
private Dictionary<int, DecalSet> m_DecalSets = new Dictionary<int, DecalSet>();
private TextureCache2D m_DecalAtlas = null;
// current camera
private Camera m_Camera;

private Texture2DAtlas m_Atlas = null;
public bool m_AllocationSuccess = true;
public Texture2DAtlas Atlas
{
get
{
if (m_Atlas == null)
{
m_Atlas = new Texture2DAtlas(HDUtils.hdrpSettings.decalSettings.atlasWidth, HDUtils.hdrpSettings.decalSettings.atlasHeight, RenderTextureFormat.ARGB32);
}
return m_Atlas;
}
}
public class TextureScaleBias : IComparable
{
public Texture m_Texture = null;
public Vector4 m_ScaleBias = Vector4.zero;
public int CompareTo(object obj)
{
TextureScaleBias other = obj as TextureScaleBias;
int size = m_Texture.width * m_Texture.height;
int otherSize = other.m_Texture.width * other.m_Texture.height;
if(size > otherSize)
{
return -1;
}
else if( size < otherSize)
{
return 1;
}
else
{
return 0;
}
}
}
private List<TextureScaleBias> m_TextureList = new List<TextureScaleBias>();
private void InitializeMaterialValues()
public void InitializeMaterialValues()
m_DiffuseTexture = m_Material.GetTexture("_BaseColorMap");
m_NormalTexture = m_Material.GetTexture("_NormalMap");
m_MaskTexture = m_Material.GetTexture("_MaskMap");
m_Diffuse.m_Texture = m_Material.GetTexture("_BaseColorMap");
m_Normal.m_Texture = m_Material.GetTexture("_NormalMap");
m_Mask.m_Texture = m_Material.GetTexture("_MaskMap");
m_Blend = m_Material.GetFloat("_DecalBlend");
}

return m_NumResults;
}
private void GetDecalVolumeDataAndBound(Matrix4x4 decalToWorld, Matrix4x4 worldToView)
{
var influenceX = decalToWorld.GetColumn(0) * 0.5f;

normalToWorldBatch[instanceCount] = m_CachedNormalToWorld[decalIndex];
float fadeFactor = Mathf.Clamp((cullDistance - distanceToDecal) / (cullDistance * (1.0f - m_CachedDrawDistances[decalIndex].y)), 0.0f, 1.0f);
normalToWorldBatch[instanceCount].m03 = fadeFactor * m_Blend; // vector3 rotation matrix so bottom row and last column can be used for other data to save space
normalToWorldBatch[instanceCount].m13 = m_DiffuseTexIndex; // texture atlas indices needed for clustered
normalToWorldBatch[instanceCount].m23 = m_NormalTexIndex;
normalToWorldBatch[instanceCount].m33 = m_MaskTexIndex;
m_DecalDatas[m_DecalDatasCount].diffuseScaleBias = m_Diffuse.m_ScaleBias;
m_DecalDatas[m_DecalDatasCount].normalScaleBias = m_Normal.m_ScaleBias;
m_DecalDatas[m_DecalDatasCount].maskScaleBias = m_Mask.m_ScaleBias;
GetDecalVolumeDataAndBound(decalToWorldBatch[instanceCount], worldToView);
m_DecalDatasCount++;

}
}
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;
}
public void RemoveFromTextureCache()
public void AddToTextureList(ref List<TextureScaleBias> textureList)
if (m_DiffuseTexture != null)
if(m_Diffuse.m_Texture != null)
instance.TextureAtlas.RemoveEntryFromSlice(m_DiffuseTexture);
textureList.Add(m_Diffuse);
if (m_NormalTexture != null)
if (m_Normal.m_Texture != null)
instance.TextureAtlas.RemoveEntryFromSlice(m_NormalTexture);
textureList.Add(m_Normal);
if (m_MaskTexture != null)
if (m_Mask.m_Texture != null)
instance.TextureAtlas.RemoveEntryFromSlice(m_MaskTexture);
textureList.Add(m_Mask);
public void UpdateCachedMaterialData(CommandBuffer cmd)
{
InitializeMaterialValues(); // refresh in case they changed in the UI
UpdateTextureCache(cmd);
}
public void RenderIntoDBuffer(CommandBuffer cmd)
{

private Matrix4x4[] m_CachedNormalToWorld = new Matrix4x4[kDecalBlockSize];
private Vector2[] m_CachedDrawDistances = new Vector2[kDecalBlockSize]; // x - draw distance, y - fade scale
private Material m_Material;
private Texture m_DiffuseTexture = null;
private Texture m_NormalTexture = null;
private Texture m_MaskTexture = null;
private int m_DiffuseTexIndex = -1;
private int m_NormalTexIndex = -1;
private int m_MaskTexIndex = -1;
TextureScaleBias m_Diffuse = new TextureScaleBias();
TextureScaleBias m_Normal = new TextureScaleBias();
TextureScaleBias m_Mask = new TextureScaleBias();
}
public DecalHandle AddDecal(Transform transform, float drawDistance, float fadeScale, Material material)

decalSet.RemoveDecal(handle);
if (decalSet.Count == 0)
{
decalSet.RemoveFromTextureCache();
m_DecalSets.Remove(key);
}
}

public void SetAtlas(CommandBuffer cmd)
{
cmd.SetGlobalTexture(HDShaderIDs._DecalAtlasID, TextureAtlas.GetTexCache());
cmd.SetGlobalTexture(HDShaderIDs._DecalAtlas2DID, Atlas.AtlasTexture);
}
public void AddTexture(CommandBuffer cmd, TextureScaleBias textureScaleBias)
{
if (textureScaleBias.m_Texture != null)
{
if (!Atlas.AddTexture(cmd, ref textureScaleBias.m_ScaleBias,textureScaleBias.m_Texture))
{
m_AllocationSuccess = false;
}
}
else
{
textureScaleBias.m_ScaleBias = Vector4.zero;
}
public void UpdateCachedMaterialData(CommandBuffer cmd)
public void UpdateCachedMaterialData()
//instance.m_AllocationSuccess = true;
m_TextureList.Clear();
pair.Value.UpdateCachedMaterialData(cmd);
pair.Value.InitializeMaterialValues();
pair.Value.AddToTextureList(ref m_TextureList);
}
}
public void UpdateTextureAtlas(CommandBuffer cmd)
{
m_AllocationSuccess = true;
foreach (TextureScaleBias textureScaleBias in m_TextureList)
{
AddTexture(cmd, textureScaleBias);
}
if (!m_AllocationSuccess) // texture failed to find space in the atlas
{
m_TextureList.Sort(); // sort the texture list largest to smallest for better packing
Atlas.ResetAllocator(); // clear all allocations
// try again
m_AllocationSuccess = true;
foreach (TextureScaleBias textureScaleBias in m_TextureList)
{
AddTexture(cmd, textureScaleBias);
}
if(!m_AllocationSuccess) // still failed to allocate, decal atlas size needs to increase
{
Debug.LogWarning("Decal texture atlas out of space, decals on transparent geometry might not render correctly, atlas size can be changed in HDRenderPipelineAsset");
}
}
}

public void Cleanup()
{
if (m_DecalAtlas != null)
m_DecalAtlas.Release();
if (m_Atlas != null)
m_Atlas.Release();
m_DecalAtlas = null;
m_Atlas = null;
}
}
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/GlobalDecalSettings.cs


public class GlobalDecalSettings
{
public int drawDistance = 1000;
public int atlasSize = 8192;
public int atlasWidth = 4096;
public int atlasHeight = 4096;
}
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/RenderLoopSettings/GlobalDecalSettingsUI.cs


EditorGUILayout.LabelField(_.GetContent("Decals"), EditorStyles.boldLabel);
++EditorGUI.indentLevel;
EditorGUILayout.PropertyField(d.drawDistance, _.GetContent("Draw Distance"));
EditorGUILayout.PropertyField(d.atlasSize, _.GetContent("Atlas Size"));
EditorGUILayout.PropertyField(d.atlasWidth, _.GetContent("Atlas Width"));
EditorGUILayout.PropertyField(d.atlasHeight, _.GetContent("Atlas Height"));
--EditorGUI.indentLevel;
}
}

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/RenderLoopSettings/SerializedGlobalDecalSettings.cs


public SerializedProperty root;
public SerializedProperty drawDistance;
public SerializedProperty atlasSize;
public SerializedProperty atlasWidth;
public SerializedProperty atlasHeight;
public SerializedGlobalDecalSettings(SerializedProperty root)
{

atlasSize = root.Find((GlobalDecalSettings s) => s.atlasSize);
atlasWidth = root.Find((GlobalDecalSettings s) => s.atlasWidth);
atlasHeight = root.Find((GlobalDecalSettings s) => s.atlasHeight);
}
}
}

7
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs


{
DecalSystem.instance.EndCull();
m_DbufferManager.vsibleDecalCount = DecalSystem.m_DecalsVisibleThisFrame;
DecalSystem.instance.UpdateCachedMaterialData(cmd); // textures, alpha or fade distances could've changed
DecalSystem.instance.CreateDrawData(); // prepare data is separate from draw
DecalSystem.instance.UpdateCachedMaterialData(); // textures, alpha or fade distances could've changed
DecalSystem.instance.UpdateTextureAtlas(cmd); // as this is only used for transparent pass, would've been nice not to have to do this if no transparent renderers are visible
DecalSystem.instance.CreateDrawData(); // prepare data is separate from draw
}
}
renderContext.SetupCameraProperties(camera, m_FrameSettings.enableStereo);

}
HDUtils.SetRenderTarget(cmd, hdCamera, m_CameraColorBuffer, m_CameraDepthStencilBuffer);
if (m_FrameSettings.enableDBuffer) // enable d-buffer flag value is being interpreted more like enable decals in general now that we have clustered
if ((m_FrameSettings.enableDBuffer) && (DecalSystem.m_DecalsVisibleThisFrame > 0)) // enable d-buffer flag value is being interpreted more like enable decals in general now that we have clustered
{
DecalSystem.instance.SetAtlas(cmd); // for clustered decals
}

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs


// all decal properties
public static readonly int _NormalToWorldID = Shader.PropertyToID("_NormalToWorld");
public static readonly int _DecalAtlas2DID = Shader.PropertyToID("_DecalAtlas2D");
public static readonly int _DecalAtlasID = Shader.PropertyToID("_DecalAtlas");
public static readonly int _DecalHTileTexture = Shader.PropertyToID("_DecalHTileTexture");
public static readonly int _DecalIndexShift = Shader.PropertyToID("_DecalIndexShift");

public static readonly int _BlitTexture = Shader.PropertyToID("_BlitTexture");
public static readonly int _BlitScaleBias = Shader.PropertyToID("_BlitScaleBias");
public static readonly int _BlitMipLevel = Shader.PropertyToID("_BlitMipLevel");
public static readonly int _BlitScaleBiasRt = Shader.PropertyToID("_BlitScaleBiasRt");
public static readonly int _WorldScales = Shader.PropertyToID("_WorldScales");
public static readonly int _FilterKernels = Shader.PropertyToID("_FilterKernels");

9
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDUtils.cs


}
}
public static void BlitQuad(CommandBuffer cmd, Texture source, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear)
{
s_PropertyBlock.SetTexture(HDShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(HDShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(HDShaderIDs._BlitMipLevel, mipLevelTex);
cmd.DrawProcedural(Matrix4x4.identity, GetBlitMaterial(), bilinear ? 2 : 3, MeshTopology.Quads, 4, 1, s_PropertyBlock);
}
public static void BlitTexture(CommandBuffer cmd, RTHandle source, RTHandle destination, Vector4 scaleBias, float mipLevel, bool bilinear)
{
s_PropertyBlock.SetTexture(HDShaderIDs._BlitTexture, source);

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DBufferManager.cs


if (frameSettings.enableDBuffer)
{
cmd.SetGlobalInt(HDShaderIDs._EnableDBuffer, vsibleDecalCount > 0 ? 1 : 0);
cmd.SetGlobalVector(HDShaderIDs._DecalAtlasResolution, new Vector2(DecalSystem.kDecalAtlasSize, DecalSystem.kDecalAtlasSize));
cmd.SetGlobalVector(HDShaderIDs._DecalAtlasResolution, new Vector2(HDUtils.hdrpSettings.decalSettings.atlasWidth, HDUtils.hdrpSettings.decalSettings.atlasHeight));
BindBufferAsTextures(cmd);
}
else

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.cs


{
public Matrix4x4 worldToDecal;
public Matrix4x4 normalToWorld;
public Vector4 diffuseScaleBias;
public Vector4 normalScaleBias;
public Vector4 maskScaleBias;
};
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.cs.hlsl


{
float4x4 worldToDecal;
float4x4 normalToWorld;
float4 diffuseScaleBias;
float4 normalScaleBias;
float4 maskScaleBias;
};
//

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.hlsl


TEXTURE2D_ARRAY(_DecalAtlas);
SAMPLER(sampler_DecalAtlas);
TEXTURE2D(_DecalAtlas2D);
SAMPLER(_trilinear_clamp_sampler_DecalAtlas2D);
// Must be in sync with RT declared in HDRenderPipeline.cs ::Rebuild
void EncodeIntoDBuffer( DecalSurfaceData surfaceData,
out DBufferType0 outDBuffer0,

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalData.hlsl


#include "CoreRP/ShaderLibrary/Packing.hlsl"
#include "CoreRP/ShaderLibrary/Sampling/SampleUVMapping.hlsl"
void GetSurfaceData(float2 texCoordDS, float4x4 decalToWorld, out DecalSurfaceData surfaceData)
void GetSurfaceData(float2 texCoordDS, float4x4 normalToWorld, out DecalSurfaceData surfaceData)
float totalBlend = clamp(decalToWorld[0][3], 0.0f, 1.0f);
float totalBlend = clamp(normalToWorld[0][3], 0.0f, 1.0f);
totalBlend = surfaceData.baseColor.w; // base alpha affects aall other channels;
totalBlend = surfaceData.baseColor.w; // base alpha affects all other channels;
surfaceData.normalWS.xyz = mul((float3x3)decalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, texCoordDS))) * 0.5f + 0.5f;
surfaceData.normalWS.xyz = mul((float3x3)normalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, texCoordDS))) * 0.5f + 0.5f;
surfaceData.normalWS.w = totalBlend;
surfaceData.HTileMask |= DBUFFERHTILEBIT_NORMAL;
#endif

103
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, _trilinear_clamp_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, _trilinear_clamp_sampler_DecalAtlas2D, texCoords, lod);
src.w *= blend;
blend = src.w; // diffuse texture alpha affects all other channels
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);

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, _trilinear_clamp_sampler_DecalAtlas2D, texCoords, lod);
src.z = src.w;
src.w = blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);

float ComputeTextureLOD(float2 uvdx, float2 uvdy, float2 scale)
{
float2 ddx_ = scale * uvdx;
float2 ddy_ = scale * uvdy;
float d = max(dot(ddx_, ddx_), dot(ddy_, ddy_));
return max(0.5 * log2(d), 0.0);
}
void AddDecalContribution(PositionInputs posInput, inout SurfaceData surfaceData, inout float alpha)
{
if(_EnableDBuffer)

decalCount = _DecalCount;
decalStart = 0;
#endif
uint i = 0;
UNITY_LOOP
for (i = 0; i < decalCount; i++)
// get world space ddx/ddy for adjacent pixels to be used later in mipmap lod calculation
float3 positionWSDdx = ddx(positionWS);
float3 positionWSDdy = ddy(positionWS);
for (uint i = 0; i < decalCount; i++)
positionDS = positionDS * float3(1.0, -1.0, 1.0) + float3(0.5, 0.0f, 0.5);
float decalBlend = decalData.normalToWorld[0][3];
int diffuseIndex = decalData.normalToWorld[1][3];
int normalIndex = decalData.normalToWorld[2][3];
int maskIndex = decalData.normalToWorld[3][3];
float lod = ComputeTextureLOD(positionDS.xz, _DecalAtlasResolution);
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
positionDS = positionDS * float3(1.0, -1.0, 1.0) + float3(0.5, 0.0f, 0.5); // decal clip space
if ((all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f)))
{
// clamp by half a texel to avoid sampling neighboring textures in the atlas
float2 clampAmount = float2(0.5f / _DecalAtlasResolution.x, 0.5f / _DecalAtlasResolution.y);
float2 diffuseMin = decalData.diffuseScaleBias.zw + clampAmount; // offset into atlas is in .zw
float2 diffuseMax = decalData.diffuseScaleBias.zw + decalData.diffuseScaleBias.xy - clampAmount; // scale relative to full atlas size is in .xy so total texture extent in atlas is (1,1) * scale
float2 normalMin = decalData.normalScaleBias.zw + clampAmount;
float2 normalMax = decalData.normalScaleBias.zw + decalData.normalScaleBias.xy - clampAmount;
float2 maskMin = decalData.maskScaleBias.zw + clampAmount;
float2 maskMax = decalData.maskScaleBias.zw + decalData.maskScaleBias.xy - clampAmount;
float2 sampleDiffuse = clamp(positionDS.xz * decalData.diffuseScaleBias.xy + decalData.diffuseScaleBias.zw, diffuseMin, diffuseMax);
float2 sampleNormal = clamp(positionDS.xz * decalData.normalScaleBias.xy + decalData.normalScaleBias.zw, normalMin, normalMax);
float2 sampleMask = clamp(positionDS.xz * decalData.maskScaleBias.xy + decalData.maskScaleBias.zw, maskMin, maskMax);
// need to compute the mipmap LOD manually because we are sampling inside a loop
float3 positionDSDdx = mul(decalData.worldToDecal, float4(positionWSDdx, 0.0)).xyz; // transform the derivatives to decal space, any translation is irrelevant
float3 positionDSDdy = mul(decalData.worldToDecal, float4(positionWSDdy, 0.0)).xyz;
float2 sampleDiffuseDdx = positionDSDdx.xz * decalData.diffuseScaleBias.xy; // factor in the atlas scale
float2 sampleDiffuseDdy = positionDSDdy.xz * decalData.diffuseScaleBias.xy;
float lodDiffuse = ComputeTextureLOD(sampleDiffuseDdx, sampleDiffuseDdy, _DecalAtlasResolution);
float2 sampleNormalDdx = positionDSDdx.xz * decalData.normalScaleBias.xy;
float2 sampleNormalDdy = positionDSDdy.xz * decalData.normalScaleBias.xy;
float lodNormal = ComputeTextureLOD(sampleNormalDdx, sampleNormalDdy, _DecalAtlasResolution);
// Verified that lod calculation works with a test texture, looking at the shader code in Razor the lod calculation is outside the dynamic branches where the texture fetch happens,
// however compiler was placing it inside the branch that was rejecting the pixel, which was causing incorrect lod to be calculated for any 2x2 quad where any of the pixels were rejected,
// so had to use alpha blend of 0 instead of branching to solve that issue."
float2 sampleMaskDdx = positionDSDdx.xz * decalData.maskScaleBias.xy;
float2 sampleMaskDdy = positionDSDdy.xz * decalData.maskScaleBias.xy;
float lodMask = ComputeTextureLOD(sampleMaskDdx, sampleMaskDdy, _DecalAtlasResolution);
float decalBlend = decalData.normalToWorld[0][3];
if(diffuseIndex != -1)
{
ApplyBlendDiffuse(DBuffer0, mask, positionDS.xz, diffuseIndex, DBUFFERHTILEBIT_DIFFUSE, decalBlend, lod);
alpha = alpha < decalBlend ? decalBlend : alpha; // use decal alpha if it higher than transparent alpha
}
if((decalData.diffuseScaleBias.x > 0) && (decalData.diffuseScaleBias.y > 0))
{
ApplyBlendDiffuse(DBuffer0, mask, sampleDiffuse, DBUFFERHTILEBIT_DIFFUSE, decalBlend, lodDiffuse);
alpha = alpha < decalBlend ? decalBlend : alpha; // use decal alpha if it is higher than transparent alpha
}
if(normalIndex != -1)
{
ApplyBlendNormal(DBuffer1, mask, positionDS.xz, normalIndex, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend, lod);
}
if ((decalData.normalScaleBias.x > 0) && (decalData.normalScaleBias.y > 0))
{
ApplyBlendNormal(DBuffer1, mask, sampleNormal, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend, lodNormal);
}
if(maskIndex != -1)
{
ApplyBlendMask(DBuffer2, mask, positionDS.xz, maskIndex, DBUFFERHTILEBIT_MASK, decalBlend, lod);
if ((decalData.maskScaleBias.x > 0) && (decalData.maskScaleBias.y > 0))
{
ApplyBlendMask(DBuffer2, mask, sampleMask, DBUFFERHTILEBIT_MASK, decalBlend, lodMask);
}
}
}
#else

33
ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Blit.shader


SamplerState sampler_PointClamp;
SamplerState sampler_LinearClamp;
uniform float4 _BlitScaleBias;
uniform float4 _BlitScaleBiasRt;
uniform float _BlitMipLevel;
struct Attributes

output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID) * _BlitScaleBias.xy + _BlitScaleBias.zw;
return output;
}
Varyings VertQuad(Attributes input)
{
Varyings output;
output.positionCS = GetQuadVertexPosition(input.vertexID) * float4(_BlitScaleBiasRt.x, _BlitScaleBiasRt.y, 1, 1) + float4(_BlitScaleBiasRt.z, _BlitScaleBiasRt.w, 0, 0);
output.positionCS.xy = output.positionCS.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f); //convert to -1..1
output.texcoord = GetQuadTexCoord(input.vertexID) * _BlitScaleBias.xy + _BlitScaleBias.zw;
return output;
}
float4 FragNearest(Varyings input) : SV_Target
{

#pragma fragment FragBilinear
ENDHLSL
}
// 2: Nearest quad
Pass
{
ZWrite Off ZTest Always Blend Off Cull Off
HLSLPROGRAM
#pragma vertex VertQuad
#pragma fragment FragNearest
ENDHLSL
}
// 3: Bilinear quad
Pass
{
ZWrite Off ZTest Always Blend Off Cull Off
HLSLPROGRAM
#pragma vertex VertQuad
#pragma fragment FragBilinear
ENDHLSL
}
}
Fallback Off

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassDBuffer.hlsl


clip(1.0 - positionDS); // Clip value above one
DecalSurfaceData surfaceData;
float4x4 decalToWorld = UNITY_ACCESS_INSTANCED_PROP(matrix, _NormalToWorld);
GetSurfaceData(positionDS.xz, decalToWorld, surfaceData);
float4x4 normalToWorld = UNITY_ACCESS_INSTANCED_PROP(matrix, _NormalToWorld);
GetSurfaceData(positionDS.xz, normalToWorld, surfaceData);
// have to do explicit test since compiler behavior is not defined for RW resources and discard instructions
if((all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f)))

195
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Texture2DAtlas.cs


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 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 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 = RTHandle.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();
RTHandle.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;
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Texture2DAtlas.cs.meta


fileFormatVersion: 2
guid: 081cfbdef2e1c014aa1d1c9aa16fb952
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存