using UnityEngine.Assertions; using UnityEngine.Rendering; namespace UnityEngine.Experimental.Rendering { public class EncodeBC6H { public static EncodeBC6H DefaultInstance; static readonly int _Source = Shader.PropertyToID("_Source"); static readonly int _Target = Shader.PropertyToID("_Target"); static readonly int _MipIndex = Shader.PropertyToID("_MipIndex"); static readonly int[] __Tmp_RT = { Shader.PropertyToID("__Tmp_RT0"), Shader.PropertyToID("__Tmp_RT1"), Shader.PropertyToID("__Tmp_RT2"), Shader.PropertyToID("__Tmp_RT3"), Shader.PropertyToID("__Tmp_RT4"), Shader.PropertyToID("__Tmp_RT5"), Shader.PropertyToID("__Tmp_RT6"), Shader.PropertyToID("__Tmp_RT7"), Shader.PropertyToID("__Tmp_RT8"), Shader.PropertyToID("__Tmp_RT9"), Shader.PropertyToID("__Tmp_RT10"), Shader.PropertyToID("__Tmp_RT11"), Shader.PropertyToID("__Tmp_RT12"), Shader.PropertyToID("__Tmp_RT13") }; readonly ComputeShader m_Shader; readonly int m_KEncodeFastCubemapMip; public EncodeBC6H(ComputeShader shader) { Assert.IsNotNull(shader); m_Shader = shader; m_KEncodeFastCubemapMip = m_Shader.FindKernel("KEncodeFastCubemapMip"); uint x, y, z; m_Shader.GetKernelThreadGroupSizes(m_KEncodeFastCubemapMip, out x, out y, out z); } // Only use mode11 of BC6H encoding /// /// Encode a Cubemap in BC6H. /// /// It will encode all faces and selected mips of the Cubemap. /// /// It uses only mode 11 of BC6H. /// /// Command buffer for execution /// The source Cubemap /// The size of the source Cubemap /// The compressed texture. /// It must be a BC6H Cubemap or Cubemap array with the same size as the source Cubemap /// Starting mip to encode /// Last mip to encode /// The index of the cubemap to store the compressed texture. /// /// Only relevant when target is a CubemapArray public void EncodeFastCubemap(CommandBuffer cmb, RenderTargetIdentifier source, int sourceSize, RenderTargetIdentifier target, int fromMip, int toMip, int targetArrayIndex = 0) { var maxMip = Mathf.Max(0, (int)(Mathf.Log(sourceSize) / Mathf.Log(2)) - 2); var actualFromMip = (int)Mathf.Clamp(fromMip, 0, maxMip); var actualToMip = (int)Mathf.Min(maxMip, Mathf.Max(toMip, actualFromMip)); // Convert TextureCube source to Texture2DArray var d = new RenderTextureDescriptor { autoGenerateMips = false, bindMS = false, colorFormat = RenderTextureFormat.ARGBInt, depthBufferBits = 0, dimension = TextureDimension.Tex2DArray, enableRandomWrite = true, msaaSamples = 1, volumeDepth = 6, sRGB = false, useMipMap = false, }; cmb.SetComputeTextureParam(m_Shader, m_KEncodeFastCubemapMip, _Source, source); for (var mip = actualFromMip; mip <= actualToMip; ++mip) { var size = (sourceSize >> mip) >> 2; d.width = size; d.height = size; cmb.GetTemporaryRT(__Tmp_RT[mip], d); } for (var mip = actualFromMip; mip <= actualToMip; ++mip) { var size = (sourceSize >> mip) >> 2; cmb.SetComputeTextureParam(m_Shader, m_KEncodeFastCubemapMip, _Target, __Tmp_RT[mip]); cmb.SetComputeIntParam(m_Shader, _MipIndex, mip); cmb.DispatchCompute(m_Shader, m_KEncodeFastCubemapMip, size, size, 6); } var startSlice = 6 * targetArrayIndex; for (var mip = actualFromMip; mip <= actualToMip; ++mip) { var rtMip = Mathf.Clamp(mip, actualFromMip, actualToMip); for (var faceId = 0; faceId < 6; ++faceId) cmb.CopyTexture(__Tmp_RT[rtMip], faceId, 0, target, startSlice + faceId, mip); } for (var mip = actualFromMip; mip <= actualToMip; ++mip) cmb.ReleaseTemporaryRT(__Tmp_RT[mip]); } } public static class BC6HExtensions { public static void BC6HEncodeFastCubemap(this CommandBuffer cmb, RenderTargetIdentifier source, int sourceSize, RenderTargetIdentifier target, int fromMip, int toMip, int targetArrayIndex = 0) { EncodeBC6H.DefaultInstance.EncodeFastCubemap(cmb, source, sourceSize, target, fromMip, toMip, targetArrayIndex); } } }