示例#1
0
    private PackedLists <WeightedIndex> CalculateFormFactorsForColorComponent(
        ScatteringFormFactorCalculator formFactorCalculator,
        IMaterialSettings[] materialSettingsArray, int componentIdx)
    {
        var profiles = materialSettingsArray
                       .Select(baseMaterialSettings => {
            UberMaterialSettings materialSettings = baseMaterialSettings as UberMaterialSettings;
            if (materialSettings is null)
            {
                return(null);
            }

            if (materialSettings.thinWalled)
            {
                return(null);
            }

            var volumeSettings = new VolumeParameters(
                materialSettings.transmittedMeasurementDistance,
                materialSettings.transmittedColor[componentIdx],
                materialSettings.scatteringMeasurementDistance,
                materialSettings.sssAmount,
                materialSettings.sssDirection);
            ScatteringProfile profile = new ScatteringProfile(
                volumeSettings.SurfaceAlbedo,
                volumeSettings.MeanFreePathLength);
            return(profile);
        })
                       .ToArray();

        PackedLists <WeightedIndex> formFactors = formFactorCalculator.Calculate(profiles);

        return(formFactors);
    }
示例#2
0
    /**
     *  Finds a distance beyond which the maximum contribution is always imperceptible.
     */
    public static double FindImperceptibleDistance(this ScatteringProfile profile, double area)
    {
        double currentDistance     = 1;
        double currentContribution = profile.CalculateMaximumContribution(currentDistance, area);

        if (currentContribution < PerceptibilityThreshold)
        {
            //search smaller distances until we get to perceptibility
            while (currentContribution < PerceptibilityThreshold)
            {
                currentDistance = currentDistance / DistanceSearchStep;
                if (currentDistance < MinDistanceForSearch)
                {
                    break;
                }

                currentContribution = profile.CalculateMaximumContribution(currentDistance, area);
            }

            //the current contribution is just perceptible, so take one step back up to get to imperceptible
            return(currentDistance * DistanceSearchStep);
        }
        else
        {
            //search larger distances until we get to imperceptibility
            while (currentContribution >= PerceptibilityThreshold)
            {
                currentDistance     = currentDistance * DistanceSearchStep;
                currentContribution = profile.CalculateMaximumContribution(currentDistance, area);
            }

            return(currentDistance);
        }
    }
示例#3
0
    public static Vector4 IntegrateOverQuad(this ScatteringProfile profile, Vector3 receiverPosition, PositionedQuad quad)
    {
        int nearestIdx = quad.FindClosestCorner(receiverPosition);

        SubQuad orientedSubQuad = SubQuad.MakeRotatedWhole(nearestIdx);

        return(IntegrateOverSubQuad(profile, receiverPosition, quad, orientedSubQuad));
    }
    public void TestFindImperceptibleDistanceSearchingUp()
    {
        var    profile = new ScatteringProfile(1, 1e-1);
        double area    = 1;

        Assert.IsTrue(profile.CalculateMaximumContribution(ScatteringProfileExtensions.InitialDistanceForSearch, area) >= ScatteringProfileExtensions.PerceptibilityThreshold,
                      "search will be up");

        double distance = profile.FindImperceptibleDistance(area);

        Assert.IsTrue(profile.CalculateMaximumContribution(distance, area) < ScatteringProfileExtensions.PerceptibilityThreshold);
        Assert.IsTrue(profile.CalculateMaximumContribution(distance / ScatteringProfileExtensions.DistanceSearchStep, area) >= ScatteringProfileExtensions.PerceptibilityThreshold);
    }
    public void TestIntegrateOverQuad()
    {
        var     profile          = new ScatteringProfile(1, 0.1);
        Vector3 receiverPosition = new Vector3(0, 0, 0);
        float   sideLength       = 100;
        var     quad             = new PositionedQuad(
            new Vector3(sideLength, sideLength, 0),
            new Vector3(0, sideLength, 0),
            new Vector3(0, 0, 0),
            new Vector3(sideLength, 0, 0)
            );

        Vector4 contribution = profile.IntegrateOverQuad(receiverPosition, quad);

        //quad should cover 1/4 of total area
        //only vertex 2 is close, so contributions from other vertices should be negligible
        Assert.AreEqual(0.25, contribution[2], 5e-3);
        Assert.AreEqual(0, contribution[0], 5e-3);
        Assert.AreEqual(0, contribution[1], 5e-3);
        Assert.AreEqual(0, contribution[3], 5e-3);
    }
示例#6
0
    private static Vector4 IntegrateOverSubQuad(ScatteringProfile profile, Vector3 receiverPosition, PositionedQuad root, SubQuad subQuad)
    {
        var    quad = subQuad.AsPositionedQuad(root);
        double area = quad.Area;

        //this assume that P0 is the closest point to the receiver
        double closestDistance     = Vector3.Distance(receiverPosition, quad.P0);
        double maximumContribution = profile.CalculateMaximumContribution(closestDistance, area);

        if (maximumContribution < SubdivisionThreshold)
        {
            double distance = Vector3.Distance(receiverPosition, quad.Center);
            return(subQuad.CenterWeight * (float)(area * profile.CalculateDiffuseReflectance(distance)));
        }
        else
        {
            Vector4 total = Vector4.Zero;
            foreach (SubQuad subSubQuad in subQuad.Split())
            {
                total += IntegrateOverSubQuad(profile, receiverPosition, root, subSubQuad);
            }
            return(total);
        }
    }
示例#7
0
    public static double CalculateMaximumContribution(this ScatteringProfile profile, double nearRadius, double area)
    {
        double farRadius = Sqrt(Sqr(nearRadius) + area / PI);

        return(profile.EvaluateCDF(farRadius) - profile.EvaluateCDF(nearRadius));
    }
示例#8
0
    /**
     *  Returns form factors unnormalized by receiver
     */
    private double[][] CalculateRawFormFactors(ScatteringProfile[] profilesBySurface)
    {
        double[][] formFactors = new double[vertexCount][];         //indexed by (receiver, transmitter)
        for (int receiverIdx = 0; receiverIdx < vertexCount; receiverIdx++)
        {
            formFactors[receiverIdx] = new double[vertexCount];
        }

        var stopwatch = Stopwatch.StartNew();

        int transmitterCount = faces.Length;

        for (int transmitterIdx = 0; transmitterIdx < transmitterCount; ++transmitterIdx)
        {
            if (transmitterIdx % 1000 == 0)
            {
                double fractionComplete          = transmitterIdx / (double)transmitterCount;
                double estimatedRemainingSeconds = stopwatch.ElapsedMilliseconds / 1000.0 / fractionComplete;
                Console.WriteLine(fractionComplete + ": " + estimatedRemainingSeconds);
            }

            int transmitterLabel = connectedComponentLabels.FaceLabels[transmitterIdx];

            int surfaceIdx            = surfaceMap[transmitterIdx];
            ScatteringProfile profile = profilesBySurface[surfaceIdx];
            if (profile == null)
            {
                //not a scattering surface
                continue;
            }

            Quad           transmitter           = faces[transmitterIdx];
            PositionedQuad positionedTransmitter = PositionedQuad.Make(vertexPositions, transmitter);
            double         transmitterArea       = positionedTransmitter.Area;

            if (profile.meanFreePath == 0)
            {
                //edge case: no scattering
                //split the face contribution evenly amongst its four corners
                double contribution = 0.25 * profile.surfaceAlbedo * transmitterArea;
                formFactors[transmitter.Index0][transmitter.Index0] = contribution;
                formFactors[transmitter.Index1][transmitter.Index1] = contribution;
                formFactors[transmitter.Index2][transmitter.Index2] = contribution;
                formFactors[transmitter.Index3][transmitter.Index3] = contribution;
                continue;
            }

            double     imperceptibleDistance     = profile.FindImperceptibleDistance(transmitterArea);
            var        transmitterBoundingSphere = positionedTransmitter.BoundingSphere;
            var        receiverBoundingSphere    = new BoundingSphere(transmitterBoundingSphere.Center, (float)(transmitterBoundingSphere.Radius + imperceptibleDistance));
            List <int> receiverIndices           = receiverCollisionTree.GetPointsInSphere(receiverBoundingSphere);

            Vector4[] contributions = receiverIndices
                                      .Select(receiverIdx => {
                int receiverLabel = connectedComponentLabels.VertexLabels[receiverIdx];
                if (receiverLabel != transmitterLabel)
                {
                    return(Vector4.Zero);
                }

                Vector3 receiverPosition = vertexPositions[receiverIdx];
                Vector4 contribution     = profile.IntegrateOverQuad(receiverPosition, positionedTransmitter);
                return(contribution);
            }).ToArray();

            double totalContribution = contributions.Sum(v => v.X + v.Y + v.Z + v.W);

            double normalizationFactor = profile.surfaceAlbedo * transmitterArea / totalContribution;

            for (int i = 0; i < contributions.Length; ++i)
            {
                int     receiverIdx  = receiverIndices[i];
                Vector4 contribution = contributions[i];

                formFactors[receiverIdx][transmitter.Index0] += normalizationFactor * contribution[0];
                formFactors[receiverIdx][transmitter.Index1] += normalizationFactor * contribution[1];
                formFactors[receiverIdx][transmitter.Index2] += normalizationFactor * contribution[2];
                formFactors[receiverIdx][transmitter.Index3] += normalizationFactor * contribution[3];
            }
        }

        return(formFactors);
    }