public void Fit(int roughnessIndex, int thetaIndex, NelderMead fitter, IBRDF brdf) { // Compute the roughness and cosTheta for this sample float roughness, cosTheta; GetRoughnessAndAngle(roughnessIndex, thetaIndex, tableResolution, parametrization, out roughness, out cosTheta); // Compute the matching view vector Vector3 tsView = new Vector3(Mathf.Sqrt(1 - cosTheta * cosTheta), 0, cosTheta); // Compute BRDF's magnitude and average direction LTCData currentLTCData; LTCDataUtilities.Initialize(out currentLTCData); LTCDataUtilities.ComputeAverageTerms(brdf, ref tsView, roughness, sampleCount, ref currentLTCData); // Otherwise use average direction as Z vector int previousLTCDataIndex = (thetaIndex - 1) * tableResolution + roughnessIndex; LTCData previousLTC = ltcData[previousLTCDataIndex]; currentLTCData.m11 = previousLTC.m11; currentLTCData.m22 = previousLTC.m22; currentLTCData.m13 = previousLTC.m13; LTCDataUtilities.Update(ref currentLTCData); // Find best-fit LTC lobe (scale, alphax, alphay) if (currentLTCData.magnitude > 1e-6) { double[] startFit = LTCDataUtilities.GetFittingParms(in currentLTCData); double[] resultFit = new double[startFit.Length]; int localSampleCount = sampleCount; currentLTCData.error = (float)fitter.FindFit(resultFit, startFit, (double)k_FitExploreDelta, (double)k_Tolerance, k_MaxIterations, (double[] parameters) => { LTCDataUtilities.SetFittingParms(ref currentLTCData, parameters, false); return(ComputeError(currentLTCData, brdf, localSampleCount, ref tsView, roughness)); }); currentLTCData.iterationsCount = fitter.m_lastIterationsCount; // Update LTC with final best fitting values LTCDataUtilities.SetFittingParms(ref currentLTCData, resultFit, false); } // Store new valid result int currentLTCDataIndex = thetaIndex * tableResolution + roughnessIndex; ltcData[currentLTCDataIndex] = currentLTCData; }
static public void FitInitial(BRDFGenerator brdfGenerator, NelderMead fitter, NativeArray <LTCData> ltcData, int roughnessIndex, int thetaIndex) { // Compute the roughness and cosTheta for this sample float roughness, cosTheta; GetRoughnessAndAngle(roughnessIndex, thetaIndex, brdfGenerator.tableResolution, brdfGenerator.parametrization, out roughness, out cosTheta); // Compute the matching view vector Vector3 tsView = new Vector3(Mathf.Sqrt(1 - cosTheta * cosTheta), 0, cosTheta); // Compute BRDF's magnitude and average direction LTCData currentLTCData; LTCDataUtilities.Initialize(out currentLTCData); LTCDataUtilities.ComputeAverageTerms(brdfGenerator.brdf, ref tsView, roughness, brdfGenerator.sampleCount, ref currentLTCData); // if theta == 0 the lobe is rotationally symmetric and aligned with Z = (0 0 1) currentLTCData.X.x = 1; currentLTCData.X.y = 0; currentLTCData.X.z = 0; currentLTCData.Y.x = 0; currentLTCData.Y.y = 1; currentLTCData.Y.z = 0; currentLTCData.Z.x = 0; currentLTCData.Z.y = 0; currentLTCData.Z.z = 1; if (roughnessIndex == (brdfGenerator.tableResolution - 1)) { // roughness = 1 or no available result currentLTCData.m11 = 1.0f; currentLTCData.m22 = 1.0f; } else { // init with roughness of previous fit LTCData previousLTC = ltcData[roughnessIndex + 1]; currentLTCData.m11 = previousLTC.m11; currentLTCData.m22 = previousLTC.m22; } currentLTCData.m13 = 0; LTCDataUtilities.Update(ref currentLTCData); // Find best-fit LTC lobe (scale, alphax, alphay) if (currentLTCData.magnitude > 1e-6) { double[] startFit = LTCDataUtilities.GetFittingParms(in currentLTCData); double[] resultFit = new double[startFit.Length]; currentLTCData.error = (float)fitter.FindFit(resultFit, startFit, k_FitExploreDelta, k_Tolerance, k_MaxIterations, (double[] parameters) => { LTCDataUtilities.SetFittingParms(ref currentLTCData, parameters, true); return(ComputeError(currentLTCData, brdfGenerator.brdf, brdfGenerator.sampleCount, ref tsView, roughness)); }); currentLTCData.iterationsCount = fitter.m_lastIterationsCount; // Update LTC with final best fitting values LTCDataUtilities.SetFittingParms(ref currentLTCData, resultFit, true); } // Store new valid result ltcData[roughnessIndex] = currentLTCData; }