public void Execute(int roughnessIndex) { // Create the fitter NelderMead fitter = new NelderMead(3); IBRDF brdf = LTCAreaLight.GetBRDFInterface(lightingModel); // Compute all the missing LTCData (0 of the first line is already done) for (int thetaIndex = 1; thetaIndex < tableResolution; thetaIndex++) { Fit(roughnessIndex, thetaIndex, fitter, brdf); } }
static public void ExecuteFittingJob(BRDFGenerator brdfGenerator, bool parallel) { // When dispatching the table on the two dimensions (X, Y) a set of constrains apply: // - Every element (Xi, Yi) has a dependency on the previous one on the same column. // - The first element of a column has a dependency on the first element of the previous column. // - The element (0,0) doesn't have a dependency on any element. // To be able to dispatch this as a job, we need to compute the first line linearly and then dispatch every column starting from the second element. using (var ltcData = new NativeArray <LTCData>(brdfGenerator.tableResolution * brdfGenerator.tableResolution, Allocator.TempJob)) { // Create the fitter NelderMead fitter = new NelderMead(3); Debug.Log("Running fitting job on the " + brdfGenerator.type.Name + " BRDF."); // Fill the first line for (int roughnessIndex = brdfGenerator.tableResolution - 1; roughnessIndex >= 0; roughnessIndex--) { FitInitial(brdfGenerator, fitter, ltcData, roughnessIndex, 0); } BRDFGeneratorJob brdfJob = new BRDFGeneratorJob { ltcData = ltcData, tableResolution = brdfGenerator.tableResolution, sampleCount = brdfGenerator.sampleCount, lightingModel = brdfGenerator.brdf.GetLightingModel(), parametrization = brdfGenerator.parametrization, }; if (parallel) { // Create, run the job and wait for its completion. JobHandle fittingJob = brdfJob.Schedule(brdfGenerator.tableResolution, 1); fittingJob.Complete(); } else { for (int i = 0; i < brdfGenerator.tableResolution; ++i) { brdfJob.Execute(i); } } Debug.Log("Fitting done. Exporting the file"); // Export the table to disk string BRDFName = brdfGenerator.type.Name; FileInfo CSharpFileName = new FileInfo(Path.Combine(brdfGenerator.outputDir, "LtcData." + BRDFName + ".cs")); ExportToCSharp(ltcData, brdfGenerator.tableResolution, brdfGenerator.parametrization, CSharpFileName, BRDFName); } }
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; }