using System.Collections.Generic; using System.Runtime.CompilerServices; using Unity.Mathematics; using RuntimeResources = UnityEngine.Rendering.ProbeReferenceVolume.RuntimeResources; namespace UnityEngine.Rendering { static class ProbeVolumeConstantRuntimeResources { static ComputeBuffer m_SkySamplingDirectionsBuffer = null; static ComputeBuffer m_AntiLeakDataBuffer = null; [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void GetRuntimeResources(ref RuntimeResources rr) { rr.SkyPrecomputedDirections = m_SkySamplingDirectionsBuffer; rr.QualityLeakReductionData = m_AntiLeakDataBuffer; } internal static void Initialize() { if (m_SkySamplingDirectionsBuffer == null) { k_SkyDirections = GenerateSkyDirections(); m_SkySamplingDirectionsBuffer = new ComputeBuffer(k_SkyDirections.Length, 3 * sizeof(float)); m_SkySamplingDirectionsBuffer.SetData(k_SkyDirections); } if (m_AntiLeakDataBuffer == null) { m_AntiLeakDataBuffer = new ComputeBuffer(k_AntiLeakData.Length, sizeof(uint)); m_AntiLeakDataBuffer.SetData(k_AntiLeakData); } } public static Vector3[] GetSkySamplingDirections() { return k_SkyDirections; } internal static void Cleanup() { CoreUtils.SafeRelease(m_SkySamplingDirectionsBuffer); m_SkySamplingDirectionsBuffer = null; CoreUtils.SafeRelease(m_AntiLeakDataBuffer); m_AntiLeakDataBuffer = null; } #region Sky Directions Buffer generator const int NB_SKY_PRECOMPUTED_DIRECTIONS = 255; static Vector3[] k_SkyDirections = new Vector3[NB_SKY_PRECOMPUTED_DIRECTIONS]; static Vector3[] GenerateSkyDirections() { var skyDirections = new Vector3[NB_SKY_PRECOMPUTED_DIRECTIONS]; float sqrtNBpoints = Mathf.Sqrt((float)(NB_SKY_PRECOMPUTED_DIRECTIONS)); float phi = 0.0f; float phiMax = 0.0f; float thetaMax = 0.0f; // Spiral based sampling on sphere // See http://web.archive.org/web/20120331125729/http://www.math.niu.edu/~rusin/known-math/97/spherefaq // http://www.math.vanderbilt.edu/saffeb/texts/161.pdf for (int i=0; i < NB_SKY_PRECOMPUTED_DIRECTIONS; i++) { // theta from 0 to PI // phi from 0 to 2PI float h = -1.0f + (2.0f * i) / (NB_SKY_PRECOMPUTED_DIRECTIONS - 1.0f); float theta = Mathf.Acos(h); if (i == NB_SKY_PRECOMPUTED_DIRECTIONS - 1 || i==0) phi = 0.0f; else phi = phi + 3.6f / sqrtNBpoints * 1.0f / (Mathf.Sqrt(1.0f-h*h)); Vector3 pointOnSphere = new Vector3(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(theta) * Mathf.Sin(phi), Mathf.Cos(theta)); pointOnSphere.Normalize(); skyDirections[i] = pointOnSphere; phiMax = Mathf.Max(phiMax, phi); thetaMax = Mathf.Max(thetaMax, theta); } return skyDirections; } #endregion #region AntiLeak Buffer generator #if UNITY_EDITOR static uint3 GetSampleOffset(uint i) { return new uint3(i, i >> 1, i >> 2) & 1; } static int GetProbeIndex(int x, int y, int z) { return x + y * 2 + z * 4; } static uint BuildFace(int axis, int idx) { uint mask = 0; int[] coords = new int[3]; coords[axis] = idx; for (int i = 0; i < 2; i++) { coords[(axis + 1) % 3] = i; for (int j = 0; j < 2; j++) { coords[(axis + 2) % 3] = j; mask = mask | (uint)(1 << GetProbeIndex(coords[0], coords[1], coords[2])); } } return mask; } static bool TryGetEdge(uint validityMask, uint samplingMask, out uint edge, out uint3 offset) { for (int i = 0; i < 8; i++) { if ((validityMask & (1 << i)) == 0) continue; uint3 p = GetSampleOffset((uint)i); if (p.x == 0) { edge = (1u << i) | (1u << GetProbeIndex(1, (int)p.y, (int)p.z)); if ((validityMask & edge) == edge && (samplingMask & edge) == 0) { offset = 2 * p; offset.x = 1; return true; } } if (p.y == 0) { edge = (1u << i) | (1u << GetProbeIndex((int)p.x, 1, (int)p.z)); if ((validityMask & edge) == edge && (samplingMask & edge) == 0) { offset = 2 * p; offset.y = 1; return true; } } if (p.z == 0) { edge = (1u << i) | (1u << GetProbeIndex((int)p.x, (int)p.y, 1)); if ((validityMask & edge) == edge && (samplingMask & edge) == 0) { offset = 2 * p; offset.z = 1; return true; } } } edge = 0; offset = 0; return false; } static List ComputeMask(uint validityMask) { List samples = new(); // Cube sample if (validityMask == 0 || validityMask == 255) { samples.Add(1); return samples; } // track which probes are sampled uint samplingMask = 0; // Find face sample for (int i = 0; i < 6; i++) { int axis = i / 2; uint face = BuildFace(axis, i % 2); if ((validityMask & face) == face) // all face is valid, sample it { uint3 offset = 0; offset[axis] = (i % 2) == 0 ? 0u : 2u; offset[(axis + 1) % 3] = 1; offset[(axis + 2) % 3] = 1; samples.Add(offset); samplingMask = face; break; } } // Find edge samples while (true) { if (!TryGetEdge(validityMask, samplingMask, out uint edge, out uint3 offset)) break; samples.Add(offset); samplingMask |= edge; } // Find single probe samples for (int i = 0; i < 8; i++) { if (((1 << i) & (validityMask & ~samplingMask)) == 0) continue; samples.Add(2 * GetSampleOffset((uint)i)); samplingMask |= (uint)(1 << i); } return samples; } static uint PackSamplingDir(uint val) { // On a single axis there is up to 2 probes. A face or edge sample needs to sample in between the probes // We encode 0 as sample first probe, 1 as sample between probe, 2 as sample second probe (2 bits) // For faster decoding, we use a third bit that reduces ALU in shader return /* 2 bits */ (val << 1) | /* 1 bit */ ((~val & 2) >> 1); } static uint InvalidSampleMask() { // This is a special code that results in no sampling in shader without any additional ALU return 2 | (2 << 3) | (2 << 6); } static uint ComputeAntiLeakData(uint validityMask) { // This may generate more than 3 samples, but we limit to 3 var samples = ComputeMask(validityMask); uint mask = 0; for (int i = 0; i < 3; i++) { uint sampleMask; if (i < samples.Count) sampleMask = PackSamplingDir(samples[i].x) | (PackSamplingDir(samples[i].y) << 3) | (PackSamplingDir(samples[i].z) << 6); else sampleMask = InvalidSampleMask(); // 32bits - 9bits per samples (up to 3 samples) // Each sample encodes sampling on each axis (3axis * 3bits) // See PackSamplingDir for axis encoding mask |= sampleMask << (9 * i); } return mask; } //[UnityEditor.MenuItem("Edit/Rendering/Global Illumination/Generate AntiLeak Buffer")] static uint[] BuildAntiLeakDataArray() { uint[] antileak = new uint[256]; for (uint validityMask = 0; validityMask < 256; validityMask++) antileak[validityMask] = ComputeAntiLeakData(validityMask); string str = "static uint[] k_AntiLeakData = new uint[256] {\n"; for (int i = 0; i < 16; i++) { str += " "; for (int j = 0; j < 16; j++) { str += antileak[i * 16 + j] + (j == 15 ? ",\n" : ", "); } } str += " };"; Debug.Log(str); return antileak; } #endif // This is autogenerated using the MenuItem above -- do not edit by hand static uint[] k_AntiLeakData = new uint[256] { 38347995, 38347849, 38347852, 38347851, 38347873, 38347865, 38322764, 38322763, 38347876, 38324297, 38347868, 38324299, 38347875, 38324313, 38322780, 38347867, 38348041, 38347977, 38408780, 38408779, 38408801, 38408793, 69517900, 69517899, 38408804, 38324425, 38408796, 69519435, 38408803, 69519449, 69517916, 38408795, 38348044, 38410313, 38347980, 38410315, 38410337, 38410329, 38322892, 70304331, 38410340, 70305865, 38410332, 70305867, 38410339, 70305881, 70304348, 38410331, 38348043, 38410441, 38408908, 38347979, 38322955, 38409817, 69518028, 38322891, 38324491, 70305993, 38409820, 38324427, 38409827, 26351193, 25564764, 38323915, 38348065, 38421065, 38421068, 38421067, 38348001, 38421081, 38312161, 38388299, 38421092, 75810889, 38421084, 75810891, 38421091, 75810905, 38388316, 38421083, 38348057, 38421193, 38312217, 38416971, 38408929, 38347993, 69507297, 38312153, 38324505, 75811017, 38416988, 26358347, 38416995, 38324441, 69583452, 38320345, 38421260, 75896905, 38421196, 75896907, 38410465, 75896921, 38388428, 70369867, 75896932, 70305865, 75896924, 70305867, 75896931, 70305881, 70369884, 75896923, 38421259, 75897033, 38417100, 38421195, 38409953, 38410457, 69583564, 38377689, 75811083, 70305993, 75896412, 75811019, 75896419, 70306009, 70107740, 70301913, 38348068, 38422601, 38422604, 38422603, 38422625, 38422617, 76595788, 76595787, 38348004, 38310628, 38422620, 38389835, 38422627, 38389849, 76595804, 38422619, 38422793, 38422729, 76681804, 76681803, 76681825, 76681817, 69517900, 69517899, 38408932, 38389961, 76681820, 69584971, 76681827, 69584985, 69517916, 76681819, 38348060, 38310684, 38422732, 38418507, 38322972, 38418521, 76595916, 25573451, 38410468, 70292196, 38347996, 38310620, 38418531, 70371417, 38322908, 38318812, 38422795, 38418633, 76681932, 38422731, 76595979, 76682841, 69518028, 76595915, 38409956, 70371529, 38408924, 38376156, 76682851, 70109273, 69518044, 69513948, 38348067, 38310691, 38312227, 38422091, 38422753, 38422105, 76585185, 76661323, 38421220, 75797220, 38422108, 75876427, 38348003, 38310627, 38312163, 38311651, 38422809, 38422217, 76585241, 76689995, 76681953, 38422745, 69507297, 76585177, 38417124, 75876553, 76690012, 73779275, 38408931, 38389977, 69507299, 76593369, 38421276, 75797276, 38422220, 75905099, 38418657, 75905113, 76661452, 74564171, 75897060, 70292196, 38421212, 75797212, 38410467, 70292195, 38388444, 75805404, 38348059, 38310683, 38312219, 38422219, 38322971, 38418649, 25467163, 76650713, 38324507, 26252059, 38417116, 75862748, 38409955, 70371545, 69583580, 38347995, }; #endregion } }