Exemple #1
0
        const int SAMPLES_COUNT = 50;                                   // Number of samples used to compute the average terms

        // compute the average direction of the BRDF
        public void     ComputeAverageTerms(IBRDF _BRDF, ref float3 _tsView, float _alpha)
        {
            magnitude = 0.0;
            fresnel   = 0.0;
            Z         = float3.Zero;
            error     = 0.0;

            double weight, pdf, eval;
            float3 tsLight = float3.Zero;
            float3 H       = float3.Zero;

            for (int j = 0; j < SAMPLES_COUNT; ++j)
            {
                for (int i = 0; i < SAMPLES_COUNT; ++i)
                {
                    float U1 = (i + 0.5f) / SAMPLES_COUNT;
                    float U2 = (j + 0.5f) / SAMPLES_COUNT;

                    // sample
                    _BRDF.GetSamplingDirection(ref _tsView, _alpha, U1, U2, ref tsLight);

                    // eval
                    eval = _BRDF.Eval(ref _tsView, ref tsLight, _alpha, out pdf);
                    if (pdf == 0.0f)
                    {
                        continue;
                    }

                    H = (_tsView + tsLight).Normalized;

                    // accumulate
                    weight = eval / pdf;
                    if (double.IsNaN(weight))
                    {
                        throw new Exception("NaN!");
                    }

                    magnitude += weight;
                    fresnel   += weight * Math.Pow(1 - Math.Max(0.0f, _tsView.Dot(H)), 5.0);
                    Z         += (float)weight * tsLight;
                }
            }
            magnitude /= SAMPLES_COUNT * SAMPLES_COUNT;
            fresnel   /= SAMPLES_COUNT * SAMPLES_COUNT;

            // Finish building the average TBN orthogonal basis
            Z.y = 0.0f;                         // clear y component, which should be zero with isotropic BRDFs
            float length = Z.Length;

            if (length > 0.0f)
            {
                Z /= length;
            }
            else
            {
                Z = float3.UnitZ;
            }
            X.Set(Z.z, 0, -Z.x);
            Y = float3.UnitY;
        }
Exemple #2
0
        static void     RunForm(IBRDF _BRDF, FileInfo _tableFileName, bool _usePreviousRoughnessForFitting)
        {
            FitterForm form = new FitterForm();

            form.RenderBRDF = true; // Change this to perform fitting without rendering each result (faster)

// Just enter view mode to visualize fitting
            form.UsePreviousRoughness = _usePreviousRoughnessForFitting;
//form.DoFitting = false;
//form.Paused = true;
//form.ReadOnly = true;

// Debug a specific case
//form.RoughnessIndex = 19;
//form.ThetaIndex = 40;

            form.UseAdaptiveFit = false;


            form.SetupBRDF(_BRDF, 64, _tableFileName);

            Application.Run(form);

//          ApplicationContext	ctxt = new ApplicationContext( form );
//          ctxt.ThreadExit += ctxt_ThreadExit;
//          Application.Run( ctxt );
//			ctxt.Dispose();
        }
 public BRDFGenerator(Type targetType, int tableResolution, int sampleCount, LTCTableParametrization parametrization, string outputDir)
 {
     this.type            = targetType;
     this.brdf            = (IBRDF)Activator.CreateInstance(targetType);
     this.shouldGenerate  = true;
     this.tableResolution = tableResolution;
     this.sampleCount     = sampleCount;
     this.outputDir       = outputDir;
     this.parametrization = parametrization;
 }
            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);
                }
            }
            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;
            }
        // Compute the error between the BRDF and the LTC using Multiple Importance Sampling
        static float ComputeError(LTCData ltcData, IBRDF brdf, int sampleCount, ref Vector3 _tsView, float _alpha)
        {
            Vector3 tsLight = Vector3.zero;

            double pdf_BRDF, eval_BRDF;
            double pdf_LTC, eval_LTC;

            float sumError = 0.0f;

            for (int j = 0; j < sampleCount; ++j)
            {
                for (int i = 0; i < sampleCount; ++i)
                {
                    float U1 = (i + 0.5f) / sampleCount;
                    float U2 = (j + 0.5f) / sampleCount;

                    // importance sample LTC
                    {
                        // sample
                        LTCDataUtilities.GetSamplingDirection(ltcData, U1, U2, ref tsLight);

                        eval_BRDF = brdf.Eval(ref _tsView, ref tsLight, _alpha, out pdf_BRDF);
                        eval_LTC  = (float)LTCDataUtilities.Eval(ltcData, ref tsLight);
                        pdf_LTC   = eval_LTC / ltcData.magnitude;

                        // error with MIS weight
                        float error = Mathf.Abs((float)(eval_BRDF - eval_LTC));
                        error = error * error * error;        // Use L3 norm to favor large values over smaller ones
                        if (error != 0.0f)
                        {
                            error /= (float)pdf_LTC + (float)pdf_BRDF;
                        }

                        if (double.IsNaN(error))
                        {
                            // SHOULD NEVER HAPPEN
                        }
                        sumError += error;
                    }

                    // importance sample BRDF
                    {
                        // sample
                        brdf.GetSamplingDirection(ref _tsView, _alpha, U1, U2, ref tsLight);

                        // error with MIS weight
                        eval_BRDF = brdf.Eval(ref _tsView, ref tsLight, _alpha, out pdf_BRDF);
                        eval_LTC  = LTCDataUtilities.Eval(ltcData, ref tsLight);
                        pdf_LTC   = eval_LTC / ltcData.magnitude;
                        float error = Mathf.Abs((float)(eval_BRDF - eval_LTC));
                        error = error * error * error;        // Use L3 norm to favor large values over smaller ones

                        if (error != 0.0f)
                        {
                            error /= (float)pdf_LTC + (float)pdf_BRDF;
                        }

                        if (double.IsNaN(error))
                        {
                            // SHOULD NEVER HAPPEN
                        }
                        sumError += error;
                    }
                }
            }

            return(sumError / ((float)sampleCount * sampleCount));
        }
Exemple #7
0
 public SphereShape(float radius, IBRDF brdf, ITexture texture)
 {
     this._radius = radius;
     this.BRDF = brdf;
     this.Texture = texture;
 }
Exemple #8
0
 public PlaneShape(IBRDF brdf, ITexture texture)
 {
     this.BRDF = brdf;
     this.Texture = texture;
     this.SetupCorners();
 }