void ToSphericalHarmonicsL2(ref SphericalHarmonicsL2 sh) { SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 0, L0); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 1, L1_0); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 2, L1_1); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 3, L1_2); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 4, L2_0); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 5, L2_1); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 6, L2_2); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 7, L2_3); SphericalHarmonicsL2Utils.SetCoefficient(ref sh, 8, L2_4); }
private static void OnAdditionalProbesBakeCompleted() { UnityEditor.Experimental.Lightmapping.additionalBakedProbesCompleted -= OnAdditionalProbesBakeCompleted; var numCells = bakingCells.Count; // Fetch results of all cells for (int c = 0; c < numCells; ++c) { var cell = bakingCells[c].cell; if (cell.probePositions == null) { continue; } int numProbes = cell.probePositions.Length; Debug.Assert(numProbes > 0); int numUniqueProbes = bakingCells[c].numUniqueProbes; var sh = new NativeArray <SphericalHarmonicsL2>(numUniqueProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var validity = new NativeArray <float>(numUniqueProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var bakedProbeOctahedralDepth = new NativeArray <float>(numUniqueProbes * 64, Allocator.Temp, NativeArrayOptions.UninitializedMemory); UnityEditor.Experimental.Lightmapping.GetAdditionalBakedProbes(cell.index, sh, validity, bakedProbeOctahedralDepth); cell.sh = new SphericalHarmonicsL2[numProbes]; cell.validity = new float[numProbes]; for (int i = 0; i < numProbes; ++i) { int j = bakingCells[c].probeIndices[i]; SphericalHarmonicsL2 shv = sh[j]; // Compress the range of all coefficients but the DC component to [0..1] // Upper bounds taken from http://ppsloan.org/publications/Sig20_Advances.pptx // Divide each coefficient by DC*f to get to [-1,1] where f is from slide 33 for (int rgb = 0; rgb < 3; ++rgb) { var l0 = sh[j][rgb, 0]; if (l0 == 0.0f) { continue; } // TODO: We're working on irradiance instead of radiance coefficients // Add safety margin 2 to avoid out-of-bounds values float l1scale = 1.7320508f; // 3/(2*sqrt(3)) * 2 float l2scale = 3.5777088f; // 4/sqrt(5) * 2 // L_1^m shv[rgb, 1] = sh[j][rgb, 1] / (l0 * l1scale * 2.0f) + 0.5f; shv[rgb, 2] = sh[j][rgb, 2] / (l0 * l1scale * 2.0f) + 0.5f; shv[rgb, 3] = sh[j][rgb, 3] / (l0 * l1scale * 2.0f) + 0.5f; // L_2^-2 shv[rgb, 4] = sh[j][rgb, 4] / (l0 * l2scale * 2.0f) + 0.5f; shv[rgb, 5] = sh[j][rgb, 5] / (l0 * l2scale * 2.0f) + 0.5f; shv[rgb, 6] = sh[j][rgb, 6] / (l0 * l2scale * 2.0f) + 0.5f; shv[rgb, 7] = sh[j][rgb, 7] / (l0 * l2scale * 2.0f) + 0.5f; shv[rgb, 8] = sh[j][rgb, 8] / (l0 * l2scale * 2.0f) + 0.5f; // Assert coefficient range for (int coeff = 1; coeff < 9; ++coeff) { Debug.Assert(shv[rgb, coeff] >= 0.0f && shv[rgb, coeff] <= 1.0f); } } SphericalHarmonicsL2Utils.SetL0(ref cell.sh[i], new Vector3(shv[0, 0], shv[1, 0], shv[2, 0])); SphericalHarmonicsL2Utils.SetL1R(ref cell.sh[i], new Vector3(shv[0, 3], shv[0, 1], shv[0, 2])); SphericalHarmonicsL2Utils.SetL1G(ref cell.sh[i], new Vector3(shv[1, 3], shv[1, 1], shv[1, 2])); SphericalHarmonicsL2Utils.SetL1B(ref cell.sh[i], new Vector3(shv[2, 3], shv[2, 1], shv[2, 2])); cell.validity[i] = validity[j]; } for (int i = 0; i < numProbes; ++i) { int j = bakingCells[c].probeIndices[i]; SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 4, new Vector3(sh[j][0, 4], sh[j][1, 4], sh[j][2, 4])); SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 5, new Vector3(sh[j][0, 5], sh[j][1, 5], sh[j][2, 5])); SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 6, new Vector3(sh[j][0, 6], sh[j][1, 6], sh[j][2, 6])); SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 7, new Vector3(sh[j][0, 7], sh[j][1, 7], sh[j][2, 7])); SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 8, new Vector3(sh[j][0, 8], sh[j][1, 8], sh[j][2, 8])); } // Reset index UnityEditor.Experimental.Lightmapping.SetAdditionalBakedProbes(cell.index, null); DilateInvalidProbes(cell.probePositions, cell.bricks, cell.sh, cell.validity, bakingReferenceVolumeAuthoring.GetDilationSettings()); ProbeReferenceVolume.instance.cells[cell.index] = cell; } // Map from each scene to an existing reference volume var scene2RefVol = new Dictionary <Scene, ProbeReferenceVolumeAuthoring>(); foreach (var refVol in GameObject.FindObjectsOfType <ProbeReferenceVolumeAuthoring>()) { if (refVol.enabled) { scene2RefVol[refVol.gameObject.scene] = refVol; } } // Map from each reference volume to its asset var refVol2Asset = new Dictionary <ProbeReferenceVolumeAuthoring, ProbeVolumeAsset>(); foreach (var refVol in scene2RefVol.Values) { refVol2Asset[refVol] = ProbeVolumeAsset.CreateAsset(refVol.gameObject.scene); } // Put cells into the respective assets foreach (var cell in ProbeReferenceVolume.instance.cells.Values) { foreach (var scene in cellIndex2SceneReferences[cell.index]) { // This scene has a reference volume authoring component in it? ProbeReferenceVolumeAuthoring refVol = null; if (scene2RefVol.TryGetValue(scene, out refVol)) { var asset = refVol2Asset[refVol]; asset.cells.Add(cell); } } } // Connect the assets to their components foreach (var pair in refVol2Asset) { var refVol = pair.Key; var asset = pair.Value; refVol.volumeAsset = asset; if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.Iterative) { UnityEditor.EditorUtility.SetDirty(refVol); UnityEditor.EditorUtility.SetDirty(refVol.volumeAsset); } } UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); foreach (var refVol in refVol2Asset.Keys) { if (refVol.enabled && refVol.gameObject.activeSelf) { refVol.QueueAssetLoading(); } } }
public static void FillDataLocation(ref DataLocation loc, SphericalHarmonicsL2[] shl2, ProbeVolumeSHBands bands) { int numBricks = shl2.Length / kBrickProbeCountTotal; int shidx = 0; int bx = 0, by = 0, bz = 0; Color c = new Color(); for (int brickIdx = 0; brickIdx < shl2.Length; brickIdx += kBrickProbeCountTotal) { for (int z = 0; z < kBrickProbeCountPerDim; z++) { for (int y = 0; y < kBrickProbeCountPerDim; y++) { for (int x = 0; x < kBrickProbeCountPerDim; x++) { int ix = bx + x; int iy = by + y; int iz = bz + z; Vector3 L0 = SphericalHarmonicsL2Utils.GetCoefficient(shl2[shidx], 0); Vector3 L1R, L1G, L1B; SphericalHarmonicsL2Utils.GetL1(shl2[shidx], out L1R, out L1G, out L1B); // First texture will have L0 coefficients in RGB, and L1R.x in the alpha channel Color L0_L1Rx = new Color(L0.x, L0.y, L0.z, L1R.x); // Second texture will have L1_G coefficients in RGB and L1R.y in the alpha channel Color L1G_L1Ry = new Color(L1G.x, L1G.y, L1G.z, L1R.y); // Third texture will have L1_B coefficients in RGB and L1R.z in the alpha channel Color L1B_L1Rz = new Color(L1B.x, L1B.y, L1B.z, L1R.z); loc.TexL0_L1rx.SetPixel(ix, iy, iz, L0_L1Rx); loc.TexL1_G_ry.SetPixel(ix, iy, iz, L1G_L1Ry); loc.TexL1_B_rz.SetPixel(ix, iy, iz, L1B_L1Rz); if (bands == ProbeVolumeSHBands.SphericalHarmonicsL2) { Vector3 L2_0, L2_1, L2_2, L2_3, L2_4; SphericalHarmonicsL2Utils.GetL2(shl2[shidx], out L2_0, out L2_1, out L2_2, out L2_3, out L2_4); c.r = L2_0.x; c.g = L2_1.x; c.b = L2_2.x; c.a = L2_3.x; loc.TexL2_0.SetPixel(ix, iy, iz, c); c.r = L2_0.y; c.g = L2_1.y; c.b = L2_2.y; c.a = L2_3.y; loc.TexL2_1.SetPixel(ix, iy, iz, c); c.r = L2_0.z; c.g = L2_1.z; c.b = L2_2.z; c.a = L2_3.z; loc.TexL2_2.SetPixel(ix, iy, iz, c); c.r = L2_4.x; c.g = L2_4.y; c.b = L2_4.z; c.a = 1; loc.TexL2_3.SetPixel(ix, iy, iz, c); } shidx++; } } } // update the pool index bx += kBrickProbeCountPerDim; if (bx >= loc.width) { bx = 0; by += kBrickProbeCountPerDim; if (by >= loc.height) { by = 0; bz += kBrickProbeCountPerDim; Debug.Assert(bz < loc.depth || brickIdx == shl2.Length - kBrickProbeCountTotal, "Location depth exceeds data texture."); } } } loc.TexL0_L1rx.Apply(false); loc.TexL1_G_ry.Apply(false); loc.TexL1_B_rz.Apply(false); if (bands == ProbeVolumeSHBands.SphericalHarmonicsL2) { loc.TexL2_0.Apply(false); loc.TexL2_1.Apply(false); loc.TexL2_2.Apply(false); loc.TexL2_3.Apply(false); } }