private static Vector3 ApplyWeights(Vector4 w, PositionedQuad root)
 {
     return
         (w.X * root.P0 +
          w.Y * root.P1 +
          w.Z * root.P2 +
          w.W * root.P3);
 }
 public PositionedQuad AsPositionedQuad(PositionedQuad root)
 {
     return(new PositionedQuad(
                ApplyWeights(W0, root),
                ApplyWeights(W1, root),
                ApplyWeights(W2, root),
                ApplyWeights(W3, root)
                ));
 }
    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);
    }
Esempio n. 4
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);
        }
    }
Esempio n. 5
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));
    }
Esempio n. 6
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);
    }