static void SetupPerFrameShaderConstants() { // When glossy reflections are OFF in the shader we set a constant color to use as indirect specular SphericalHarmonicsL2 ambientSH = RenderSettings.ambientProbe; Color linearGlossyEnvColor = new Color(ambientSH[0, 0], ambientSH[1, 0], ambientSH[2, 0]) * RenderSettings.reflectionIntensity; Color glossyEnvColor = CoreUtils.ConvertLinearToActiveColorSpace(linearGlossyEnvColor); Shader.SetGlobalVector(PerFrameBuffer._GlossyEnvironmentColor, glossyEnvColor); // Used when subtractive mode is selected Shader.SetGlobalVector(PerFrameBuffer._SubtractiveShadowColor, CoreUtils.ConvertSRGBToActiveColorSpace(RenderSettings.subtractiveShadowColor)); }
// Premultiplies the SH with the polynomial coefficients of SH basis functions, // which avoids using any constants during SH evaluation. // The resulting evaluation takes the form: // (c_0 - c_6) + c_1 y + c_2 z + c_3 x + c_4 x y + c_5 y z + c_6 (3 z^2) + c_7 x z + c_8 (x^2 - y^2) public static SphericalHarmonicsL2 PremultiplyCoefficients(SphericalHarmonicsL2 sh) { for (int c = 0; c < 3; c++) { for (int i = 0; i < 9; i++) { sh[c, i] *= ks[i]; } } return(sh); }
internal void FromSphericalHarmonicsL2(SphericalHarmonicsL2 sh) { L0 = new Vector3(sh[0, 0], sh[1, 0], sh[2, 0]); L1_0 = new Vector3(sh[0, 1], sh[1, 1], sh[2, 1]); L1_1 = new Vector3(sh[0, 2], sh[1, 2], sh[2, 2]); L1_2 = new Vector3(sh[0, 3], sh[1, 3], sh[2, 3]); L2_0 = new Vector3(sh[0, 4], sh[1, 4], sh[2, 4]); L2_1 = new Vector3(sh[0, 5], sh[1, 5], sh[2, 5]); L2_2 = new Vector3(sh[0, 6], sh[1, 6], sh[2, 6]); L2_3 = new Vector3(sh[0, 7], sh[1, 7], sh[2, 7]); L2_4 = new Vector3(sh[0, 8], sh[1, 8], sh[2, 8]); }
public static SphericalHarmonicsL2 RescaleCoefficients(SphericalHarmonicsL2 sh, float scalar) { for (int c = 0; c < 3; c++) { for (int i = 0; i < 9; i++) { sh[c, i] *= scalar; } } return(sh); }
// Undoes coefficient rescaling due to the convolution with the clamped cosine kernel // to obtain the canonical values of SH. public static SphericalHarmonicsL2 UndoCosineRescaling(SphericalHarmonicsL2 sh) { for (int c = 0; c < 3; c++) { for (int i = 0; i < 9; i++) { sh[c, i] *= invNormConsts[i]; } } return(sh); }
public SHProperties(SphericalHarmonicsL2 sh) { SHAr = GetSHA(sh, 0); SHAg = GetSHA(sh, 1); SHAb = GetSHA(sh, 2); SHBr = GetSHB(sh, 0); SHBg = GetSHB(sh, 1); SHBb = GetSHB(sh, 2); SHC = GetSHC(sh); }
byte[] SerializeLightProbes(LightProbes lightprobe) { if (this.lightProbes != null) { SphericalHarmonicsL2[] probeData = LightmapSettings.lightProbes.bakedProbes; Vector3[] probePositions = lightprobe.positions; float[] probeDataArray = new float[30 * probeData.Length]; int stride = 0; for (int i = 0; i < probeData.Length; i++) { Vector3 position = probePositions[i]; SphericalHarmonicsL2 probe = probeData[i]; probeDataArray[stride] = position.x; stride++; probeDataArray[stride] = position.y; stride++; probeDataArray[stride] = position.z; stride++; //Save all coefficients for this probe. for (int k = 0; k < 27; k++) { probeDataArray[stride + k] = probe[0, k]; } stride += 27; } byte[] serializedLightProbes = new byte[probeDataArray.Length * sizeof(float)]; int index = 0; for (int i = 0; i < probeDataArray.Length; i++) { byte[] serializedFloat = BitConverter.GetBytes(probeDataArray[i]); Buffer.BlockCopy(serializedFloat, 0, serializedLightProbes, index, serializedFloat.Length); index += 4; } return(serializedLightProbes); } //Do not return null, serializer will cry... return(new byte[10]); }
internal void ToSphericalHarmonicsShaderConstants(ProbeVolumeSHBands srcBands, NativeArray <float> shL0L1Data, NativeArray <float> shL2Data, int probeIdx) { var sh = new SphericalHarmonicsL2(); ToSphericalHarmonicsL2(ref sh); WriteToShaderCoeffsL0L1(ref sh, shL0L1Data, probeIdx * ProbeVolumeAsset.kL0L1ScalarCoefficientsCount); if (srcBands == ProbeVolumeSHBands.SphericalHarmonicsL2) { WriteToShaderCoeffsL2(ref sh, shL2Data, probeIdx * ProbeVolumeAsset.kL2ScalarCoefficientsCount); } }
public static float getFloatFromSH(SphericalHarmonicsL2 sh, int index) { // index = new int[] {0,1,2,4,5,6,8,9,10,12,13,14,16,17,18,20,21,22,24,25,26,3,7,11,15,19,23,27 }[index]; if (index >= 27) { return(0); } // rgb * 9 + coefficient int rgb = index / 9; int coefficient = index % 9; print("fetch:" + (rgb * 9 + coefficient)); return(sh[rgb, coefficient]); }
void SHAddPointLight(Vector3 probePosition, Vector3 position, float range, Color color, float intensity, ref SphericalHarmonicsL2 sh) { // From the point of view of an SH probe, point light looks no different than a directional light, // just attenuated and coming from the right direction. Vector3 probeToLight = position - probePosition; if (probeToLight.sqrMagnitude > range) { return; } float attenuation = 1.0F / (1.0F + 25.0F * probeToLight.sqrMagnitude / (range * range)); sh.AddDirectionalLight(probeToLight.normalized, color, intensity * attenuation); }
internal SphericalHarmonicsL2 ToSphericalHarmonicsL2() { SphericalHarmonicsL2 sh = new SphericalHarmonicsL2(); 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); return(sh); }
private void InitPreview(Rect r) { this.camera.backgroundColor = new Color(0.192156866f, 0.192156866f, 0.192156866f, 1f); if (QualitySettings.activeColorSpace == ColorSpace.Linear) { this.camera.backgroundColor = this.camera.backgroundColor.linear; } this.m_TargetRect = r; float scaleFactor = this.GetScaleFactor(r.width, r.height); int num = (int)(r.width * scaleFactor); int num2 = (int)(r.height * scaleFactor); if (!this.m_RenderTexture || this.m_RenderTexture.width != num || this.m_RenderTexture.height != num2) { if (this.m_RenderTexture) { UnityEngine.Object.DestroyImmediate(this.m_RenderTexture); this.m_RenderTexture = null; } RenderTextureFormat format = (!this.camera.allowHDR) ? RenderTextureFormat.ARGB32 : RenderTextureFormat.ARGBHalf; this.m_RenderTexture = new RenderTexture(num, num2, 16, format, RenderTextureReadWrite.Linear); this.m_RenderTexture.hideFlags = HideFlags.HideAndDontSave; this.camera.targetTexture = this.m_RenderTexture; Light[] lights = this.lights; for (int i = 0; i < lights.Length; i++) { Light light = lights[i]; light.enabled = true; } } this.m_SavedState = new SavedRenderTargetState(); EditorGUIUtility.SetRenderTextureNoViewport(this.m_RenderTexture); GL.LoadOrtho(); GL.LoadPixelMatrix(0f, (float)this.m_RenderTexture.width, (float)this.m_RenderTexture.height, 0f); ShaderUtil.rawViewportRect = new Rect(0f, 0f, (float)this.m_RenderTexture.width, (float)this.m_RenderTexture.height); ShaderUtil.rawScissorRect = new Rect(0f, 0f, (float)this.m_RenderTexture.width, (float)this.m_RenderTexture.height); GL.Clear(true, true, this.camera.backgroundColor); Light[] lights2 = this.lights; for (int j = 0; j < lights2.Length; j++) { Light light2 = lights2[j]; light2.enabled = true; } SphericalHarmonicsL2 ambientProbe = RenderSettings.ambientProbe; Unsupported.SetOverrideRenderSettings(this.previewScene.scene); RenderSettings.ambientProbe = ambientProbe; }
private static int set_ambientProbe(IntPtr L) { int result; try { SphericalHarmonicsL2 ambientProbe = (SphericalHarmonicsL2)ToLua.CheckObject(L, 2, typeof(SphericalHarmonicsL2)); RenderSettings.ambientProbe = ambientProbe; result = 0; } catch (Exception e) { result = LuaDLL.toluaL_exception(L, e, null); } return(result); }
static void DilateInvalidProbes(Vector3[] probePositions, List <Brick> bricks, SphericalHarmonicsL2[] sh, float[] validity, ProbeDilationSettings dilationSettings) { // For each brick List <DilationProbe> culledProbes = new List <DilationProbe>(); List <DilationProbe> nearProbes = new List <DilationProbe>(dilationSettings.maxDilationSamples); for (int brickIdx = 0; brickIdx < bricks.Count; brickIdx++) { // Find probes that are in bricks nearby CullDilationProbes(brickIdx, bricks, validity, dilationSettings, culledProbes); // Iterate probes in current brick for (int probeOffset = 0; probeOffset < 64; probeOffset++) { int probeIdx = brickIdx * 64 + probeOffset; // Skip valid probes if (validity[probeIdx] <= dilationSettings.dilationValidityThreshold) { continue; } // Find distance weighted probes nearest to current probe FindNearProbes(probeIdx, probePositions, dilationSettings, culledProbes, nearProbes, out float invDistSum); // Set invalid probe to weighted average of found neighboring probes var shAverage = new SphericalHarmonicsL2(); for (int nearProbeIdx = 0; nearProbeIdx < nearProbes.Count; nearProbeIdx++) { var nearProbe = nearProbes[nearProbeIdx]; float weight = nearProbe.dist / invDistSum; var target = sh[nearProbe.idx]; for (int c = 0; c < 9; ++c) { shAverage[0, c] += target[0, c] * weight; shAverage[1, c] += target[1, c] * weight; shAverage[2, c] += target[2, c] * weight; } } sh[probeIdx] = shAverage; validity[probeIdx] = validity[probeIdx]; } } }
public (Vector3[], SphericalHarmonicsL2[]) Import(glTF_VCAST_vci_LocationLighting_LightProbe[] lightProbes) { var positions = new List <Vector3>(); var coefficients = new List <SphericalHarmonicsL2>(); for (var idx = 0; idx < lightProbes.Length; ++idx) { var lightProbe = lightProbes[idx]; if (lightProbe == null) { continue; } var pos = lightProbe.position; if (pos == null || pos.Length != 3) { continue; } var coefR = lightProbe.sphericalHarmonicsCoefficientsRed; var coefG = lightProbe.sphericalHarmonicsCoefficientsGreen; var coefB = lightProbe.sphericalHarmonicsCoefficientsBlue; if (coefR == null || coefG == null || coefB == null) { continue; } if (coefR.Length != CoefCount || coefG.Length != CoefCount || coefB.Length != CoefCount) { continue; } var unityPos = new Vector3(-pos[0], pos[1], pos[2]); // invert X-axis var coef = new SphericalHarmonicsL2(); for (var lap = 0; lap < 9; ++lap) { coef[0, lap] = coefR[lap]; coef[1, lap] = coefG[lap]; coef[2, lap] = coefB[lap]; } positions.Add(unityPos); coefficients.Add(coef); } return(positions.ToArray(), coefficients.ToArray()); }
// Packs coefficients so that we can use Peter-Pike Sloan's shader code. // Does not perform premultiplication with coefficients of SH basis functions. // See SetSHEMapConstants() in "Stupid Spherical Harmonics Tricks". public static void PackCoefficients(Vector4[] packedCoeffs, SphericalHarmonicsL2 sh) { // Constant + linear for (int c = 0; c < 3; c++) { packedCoeffs[c].Set(sh[c, 3], sh[c, 1], sh[c, 2], sh[c, 0] - sh[c, 6]); } // Quadratic (4/5) for (int c = 0; c < 3; c++) { packedCoeffs[3 + c].Set(sh[c, 4], sh[c, 5], sh[c, 6] * 3.0f, sh[c, 7]); } // Quadratic (5) packedCoeffs[6].Set(sh[0, 8], sh[1, 8], sh[2, 8], 1.0f); }
// Function that fills the buffer with the ambient probe values unsafe void SetPreconvolvedAmbientLightProbe(ref ShaderVariablesClouds cb, HDCamera hdCamera, VolumetricClouds settings) { SphericalHarmonicsL2 probeSH = SphericalHarmonicMath.UndoCosineRescaling(m_SkyManager.GetAmbientProbe(hdCamera)); probeSH = SphericalHarmonicMath.RescaleCoefficients(probeSH, settings.ambientLightProbeDimmer.value); ZonalHarmonicsL2.GetCornetteShanksPhaseFunction(m_PhaseZHClouds, 0.0f); SphericalHarmonicsL2 finalSH = SphericalHarmonicMath.PremultiplyCoefficients(SphericalHarmonicMath.Convolve(probeSH, m_PhaseZHClouds)); SphericalHarmonicMath.PackCoefficients(m_PackedCoeffsClouds, finalSH); for (int i = 0; i < 7; i++) { for (int j = 0; j < 4; ++j) { cb._AmbientProbeCoeffs[i * 4 + j] = m_PackedCoeffsClouds[i][j]; } } }
public static int constructor(IntPtr l) { int result; try { SphericalHarmonicsL2 sphericalHarmonicsL = default(SphericalHarmonicsL2); LuaObject.pushValue(l, true); LuaObject.pushValue(l, sphericalHarmonicsL); result = 2; } catch (Exception e) { result = LuaObject.error(l, e); } return(result); }
private void LoadLightProbes(string path) { if (!string.IsNullOrEmpty(path)) { TextAsset data = Resources.Load <TextAsset>(path); using (var stream = new MemoryStream(data.bytes)) { using (var input = new BinaryReader(stream)) { int count = input.ReadInt32(); SphericalHarmonicsL2[] bakedProbes = new SphericalHarmonicsL2[count]; for (int i = 0; i < count; ++i) { bakedProbes[i].Clear(); for (int ch = 0; ch < 3; ++ch) { for (int coef = 0; coef < 9; ++coef) { bakedProbes[i][ch, coef] = input.ReadSingle(); } } } //if (LightmapSettings.lightProbes == null) //{ LightProbes probes = Instantiate(LightmapSettings.lightProbes) as LightProbes; probes.name = "Imported probes"; probes.bakedProbes = bakedProbes; LightmapSettings.lightProbes = probes; //} //LightmapSettings.lightProbes.bakedProbes = bakedProbes; //LightmapSettings.lightProbes = new LightProbes(); input.Close(); } stream.Close(); } Resources.UnloadAsset(data); } else { LoadLightProbeFromScene(); } }
void Update() { if (_block == null) { _block = new MaterialPropertyBlock(); _block.SetVectorArray(_baseColorId, _baseColors); _block.SetFloatArray(_metallicId, _metallic); _block.SetFloatArray(_smoothnessId, _smoothness); if (!_lightProbeVolume) { var positions = new Vector3[1023]; for (int i = 0; i < _matrices.Length; i++) { positions[i] = _matrices[i].GetColumn(3); } var lightProbes = new SphericalHarmonicsL2[1023]; var occlusionProbes = new Vector4[1023]; LightProbes.CalculateInterpolatedLightAndOcclusionProbes( positions, lightProbes, occlusionProbes ); _block.CopySHCoefficientArraysFrom(lightProbes); _block.CopyProbeOcclusionArrayFrom(occlusionProbes); } } Graphics.DrawMeshInstanced( _mesh, submeshIndex: 0, _material, _matrices, count: 1023, _block, ShadowCastingMode.On, receiveShadows: true, layer: 0, camera: null, _lightProbeVolume ? LightProbeUsage.UseProxyVolume : LightProbeUsage.CustomProvided, _lightProbeVolume ); }
public static int op_Multiply(IntPtr l) { int result; try { int total = LuaDLL.lua_gettop(l); if (LuaObject.matchType(l, total, 1, typeof(float), typeof(SphericalHarmonicsL2))) { float lhs; LuaObject.checkType(l, 1, out lhs); SphericalHarmonicsL2 rhs; LuaObject.checkValueType <SphericalHarmonicsL2>(l, 2, out rhs); SphericalHarmonicsL2 sphericalHarmonicsL = lhs * rhs; LuaObject.pushValue(l, true); LuaObject.pushValue(l, sphericalHarmonicsL); result = 2; } else if (LuaObject.matchType(l, total, 1, typeof(SphericalHarmonicsL2), typeof(float))) { SphericalHarmonicsL2 lhs2; LuaObject.checkValueType <SphericalHarmonicsL2>(l, 1, out lhs2); float rhs2; LuaObject.checkType(l, 2, out rhs2); SphericalHarmonicsL2 sphericalHarmonicsL2 = lhs2 * rhs2; LuaObject.pushValue(l, true); LuaObject.pushValue(l, sphericalHarmonicsL2); result = 2; } else { LuaObject.pushValue(l, false); LuaDLL.lua_pushstring(l, "No matched override function op_Multiply to call"); result = 2; } } catch (Exception e) { result = LuaObject.error(l, e); } return(result); }
// Premultiplies the SH with the polynomial coefficients of SH basis functions, // which avoids using any constants during SH evaluation. // The resulting evaluation takes the form: // (c_0 - c_6) + c_1 y + c_2 z + c_3 x + c_4 x y + c_5 y z + c_6 (3 z^2) + c_7 x z + c_8 (x^2 - y^2) public static SphericalHarmonicsL2 PremultiplyCoefficients(SphericalHarmonicsL2 sh) { const float k0 = 0.28209479177387814347f; // {0, 0} : 1/2 * sqrt(1/Pi) const float k1 = 0.48860251190291992159f; // {1, 0} : 1/2 * sqrt(3/Pi) const float k2 = 1.09254843059207907054f; // {2,-2} : 1/2 * sqrt(15/Pi) const float k3 = 0.31539156525252000603f; // {2, 0} : 1/4 * sqrt(5/Pi) const float k4 = 0.54627421529603953527f; // {2, 2} : 1/4 * sqrt(15/Pi) float[] ks = { k0, -k1, k1, -k1, k2, -k2, k3, -k2, k4 }; for (int c = 0; c < 3; c++) { for (int i = 0; i < 9; i++) { sh[c, i] *= ks[i]; } } return(sh); }
static void SetAmbientProbeShaderUniforms(CommandBuffer cmd, AmbientProbeData ambientProbeData) { // Ambient probe, i.e. direct sky contribution if (ms_AmbientProbeSC == null || ms_AmbientProbeSC.Length != 7) { ms_AmbientProbeSC = new Vector4[7]; } if (ambientProbeData != null) { cmd.SetGlobalVectorArray(Uniforms._AmbientProbeSH, ambientProbeData.sh); } else { SphericalHarmonicsL2 ambientProbe = RenderSettings.ambientProbe; // LightProbes.GetShaderConstantsFromNormalizedSH(ref ambientProbe, m_AmbientProbeSC); GetShaderConstantsFromNormalizedSH(ref ambientProbe, ms_AmbientProbeSC); cmd.SetGlobalVectorArray(Uniforms._AmbientProbeSH, ms_AmbientProbeSC); } }
// Ref: "Stupid Spherical Harmonics Tricks", p. 6. public static SphericalHarmonicsL2 Convolve(SphericalHarmonicsL2 sh, ZonalHarmonicsL2 zh) { for (int l = 0; l <= 2; l++) { float n = Mathf.Sqrt((4.0f * Mathf.PI) / (2 * l + 1)); float k = zh.coeffs[l]; float p = n * k; for (int m = -l; m <= l; m++) { int i = l * (l + 1) + m; for (int c = 0; c < 3; c++) { sh[c, i] *= p; } } } return(sh); }
public static int op_Addition(IntPtr l) { int result; try { SphericalHarmonicsL2 lhs; LuaObject.checkValueType <SphericalHarmonicsL2>(l, 1, out lhs); SphericalHarmonicsL2 rhs; LuaObject.checkValueType <SphericalHarmonicsL2>(l, 2, out rhs); SphericalHarmonicsL2 sphericalHarmonicsL = lhs + rhs; LuaObject.pushValue(l, true); LuaObject.pushValue(l, sphericalHarmonicsL); result = 2; } catch (Exception e) { result = LuaObject.error(l, e); } return(result); }
internal void PushProbeVolumesGlobalParamsDefault(HDCamera hdCamera, CommandBuffer cmd, int frameIndex) { cmd.SetGlobalInt(HDShaderIDs._EnableProbeVolumes, 0); cmd.SetGlobalBuffer(HDShaderIDs._ProbeVolumeBounds, s_VisibleProbeVolumeBoundsBufferDefault); cmd.SetGlobalBuffer(HDShaderIDs._ProbeVolumeDatas, s_VisibleProbeVolumeDataBufferDefault); cmd.SetGlobalInt(HDShaderIDs._ProbeVolumeCount, 0); cmd.SetGlobalTexture(HDShaderIDs._ProbeVolumeAtlasSH, TextureXR.GetBlackTexture3D()); cmd.SetGlobalTexture(HDShaderIDs._ProbeVolumeAtlasOctahedralDepth, Texture2D.blackTexture); cmd.SetGlobalInt(HDShaderIDs._ProbeVolumeLeakMitigationMode, (int)LeakMitigationMode.NormalBias); cmd.SetGlobalFloat(HDShaderIDs._ProbeVolumeNormalBiasWS, 0.0f); cmd.SetGlobalFloat(HDShaderIDs._ProbeVolumeBilateralFilterWeightMin, 0.0f); cmd.SetGlobalFloat(HDShaderIDs._ProbeVolumeBilateralFilterWeight, 0.0f); { // Need to populate ambient probe fallback even in the default case, // As if the feature is enabled in the ShaderConfig, but disabled in the HDRenderPipelineAsset, we need to fallback to ambient probe only. SphericalHarmonicsL2 ambientProbeFallbackSH = m_SkyManager.GetAmbientProbe(hdCamera); SphericalHarmonicMath.PackCoefficients(s_AmbientProbeFallbackPackedCoeffs, ambientProbeFallbackSH); cmd.SetGlobalVectorArray(HDShaderIDs._ProbeVolumeAmbientProbeFallbackPackedCoeffs, s_AmbientProbeFallbackPackedCoeffs); } }
private SphericalHarmonicsL2[] DeserializeLightProbes(int index) { var sphericalHarmonicsArray = new SphericalHarmonicsL2[lightingScenariosData.lightProbes.Length]; for (int i = 0; i < lightingScenariosData.lightProbes.Length; i++) { var sphericalHarmonics = new SphericalHarmonicsL2(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { sphericalHarmonics[j, k] = lightingScenariosData.lightProbes[i].coefficients[j * 9 + k]; } } sphericalHarmonicsArray[i] = sphericalHarmonics; } return(sphericalHarmonicsArray); }
// Undoes coefficient rescaling due to the convolution with the clamped cosine kernel // to obtain the canonical values of SH. public static SphericalHarmonicsL2 UndoCosineRescaling(SphericalHarmonicsL2 sh) { const float c0 = 0.28209479177387814347f; // 1/2 * sqrt(1/Pi) const float c1 = 0.32573500793527994772f; // 1/3 * sqrt(3/Pi) const float c2 = 0.27313710764801976764f; // 1/8 * sqrt(15/Pi) const float c3 = 0.07884789131313000151f; // 1/16 * sqrt(5/Pi) const float c4 = 0.13656855382400988382f; // 1/16 * sqrt(15/Pi) // Compute the inverse of SphericalHarmonicsL2::kNormalizationConstants. // See SetSHEMapConstants() in "Stupid Spherical Harmonics Tricks". float[] invNormConsts = { 1 / c0, -1 / c1, 1 / c1, -1 / c1, 1 / c2, -1 / c2, 1 / c3, -1 / c2, 1 / c4 }; for (int c = 0; c < 3; c++) { for (int i = 0; i < 9; i++) { sh[c, i] *= invNormConsts[i]; } } return(sh); }
unsafe void UpdateShaderVariablesGlobalProbeVolumesDefault(ref ShaderVariablesGlobal cb, HDCamera hdCamera) { cb._EnableProbeVolumes = 0; cb._ProbeVolumeCount = 0; cb._ProbeVolumeLeakMitigationMode = (int)LeakMitigationMode.NormalBias; cb._ProbeVolumeNormalBiasWS = 0.0f; cb._ProbeVolumeBilateralFilterWeightMin = 0.0f; cb._ProbeVolumeBilateralFilterWeight = 0.0f; // Need to populate ambient probe fallback even in the default case, // As if the feature is enabled in the ShaderConfig, but disabled in the HDRenderPipelineAsset, we need to fallback to ambient probe only. SphericalHarmonicsL2 ambientProbeFallbackSH = m_SkyManager.GetAmbientProbe(hdCamera); SphericalHarmonicMath.PackCoefficients(s_AmbientProbeFallbackPackedCoeffs, ambientProbeFallbackSH); for (int i = 0; i < 7; ++i) { for (int j = 0; j < 4; ++j) { cb._ProbeVolumeAmbientProbeFallbackPackedCoeffs[i * 4 + j] = s_AmbientProbeFallbackPackedCoeffs[i][j]; } } }
// Prepare L2 spherical harmonics values for efficient evaluation in a shader private static void GetShaderConstantsFromNormalizedSH(ref SphericalHarmonicsL2 ambientProbe, Vector4[] outCoefficients) { for (int channelIdx = 0; channelIdx < 3; ++channelIdx) { // Constant + Linear // In the shader we multiply the normal is not swizzled, so it's normal.xyz. // Swizzle the coefficients to be in { x, y, z, DC } order. outCoefficients[channelIdx].x = ambientProbe[channelIdx, 3]; outCoefficients[channelIdx].y = ambientProbe[channelIdx, 1]; outCoefficients[channelIdx].z = ambientProbe[channelIdx, 2]; outCoefficients[channelIdx].w = ambientProbe[channelIdx, 0] - ambientProbe[channelIdx, 6]; // Quadratic polynomials outCoefficients[channelIdx + 3].x = ambientProbe[channelIdx, 4]; outCoefficients[channelIdx + 3].y = ambientProbe[channelIdx, 5]; outCoefficients[channelIdx + 3].z = ambientProbe[channelIdx, 6] * 3.0f; outCoefficients[channelIdx + 3].w = ambientProbe[channelIdx, 7]; } // Final quadratic polynomial outCoefficients[6].x = ambientProbe[0, 8]; outCoefficients[6].y = ambientProbe[1, 8]; outCoefficients[6].z = ambientProbe[2, 8]; outCoefficients[6].w = 1.0f; }