Exemplo n.º 1
0
        public static unsafe Sphere *intersect(ref Ray r, out double t)
        {
            t = 1e20;
            Sphere *ret = null;

            fixed(Sphere *pStart = &spheres[0])
            {
                int sz = spheres.Length;

                for (Sphere *s = pStart; s != pStart + sz; ++s)
                {
                    double d = s->intersect(ref r);
                    if (d < t)
                    {
                        t   = d;
                        ret = s;
                    }
                }
            }

            return(ret);
        }
    static int DoSphereVsSpheres(Sphere *spheres, int numSpheres, float3 *centerPtr, float radius, out int numIntersections)
    {
        float3 center = *centerPtr;
        int    first  = numSpheres;
        int    n      = 0;

        for (int i = 0; i < numSpheres; i++)
        {
            float r = spheres[i].Radius + radius;
            if (math.distancesq(spheres[i].Position, center) < r * r)
            {
                if (i < first)
                {
                    first = i;
                }
                n++;
            }
        }

        numIntersections = n;

        return(first == numSpheres ? -1 : first);
    }
Exemplo n.º 3
0
        public static unsafe Vec radiance(ref Ray r, int depth, ref RandomLCG rand)
        {
            double  t;                                          // distance to intersection
            Sphere *obj = intersect(ref r, out t);

            if (obj == null)
            {
                return(Vec_Zero);                // if miss, return black
            }
            else
            {
                int  newDepth   = depth + 1;
                bool isMaxDepth = newDepth > 100;

                // Russian roulette for path termination
                bool isUseRR = newDepth > 5;
                bool isRR    = isUseRR && rand.NextNumber() < obj->maxC;

                if (isMaxDepth || (isUseRR && !isRR))
                {
                    return(obj->e);
                }
                else
                {
                    Vec f    = (isUseRR && isRR) ? obj->cc : obj->c;
                    var tmp1 = r.d.Mul(t);
                    Vec x    = r.o.Add(ref tmp1);
                    Vec n    = (x.Sub(ref obj->p)).Norm();
                    Vec nl   = n.Dot(ref r.d) < 0 ? n : n.Mul(-1);

                    if (obj->refl == MatType.DIFF)
                    {                     // Ideal DIFFUSE reflection
                        double r1  = 2 * M_PI * rand.NextNumber();
                        double r2  = rand.NextNumber();
                        double r2s = MathSqrt(r2);

                        Vec w  = nl;
                        Vec wo = w.x <-0.1 || w.x> 0.1 ? Vec_YAxis : Vec_XAxis;
                        Vec u  = (wo.Cross(ref w)).Norm();
                        Vec v  = w.Cross(ref u);

                        var tmp2 = v.Mul(MathSin(r1)).Mul(r2s);
                        var tmp3 = w.Mul(MathSqrt(1 - r2));
                        Vec d    = (u.Mul(MathCos(r1)).Mul(r2s).Add(ref tmp2).Add(ref tmp3)).Norm();

                        var tmp4 = new Ray(ref x, ref d);
                        var tmp5 = radiance(ref tmp4, newDepth, ref rand);
                        var tmp6 = f.Mul(ref tmp5);
                        return(obj->e.Add(ref tmp6));
                    }
                    else if (obj->refl == MatType.SPEC)                     // Ideal SPECULAR reflection
                    {
                        var tmp8  = n.Mul(2 * (n.Dot(ref r.d)));
                        var tmp9  = r.d.Sub(ref tmp8);
                        var tmp7  = new Ray(ref x, ref tmp9);
                        var tmp10 = radiance(ref tmp7, newDepth, ref rand);
                        var tmp11 = f.Mul(ref tmp10);
                        return(obj->e.Add(ref tmp11));
                    }
                    else
                    {                     // Ideal dielectric REFRACTION
                        var    tmp100  = n.Mul(2 * (n.Dot(ref r.d)));
                        var    tmp101  = r.d.Sub(ref tmp100);
                        Ray    reflRay = new Ray(ref x, ref tmp101);
                        bool   into    = n.Dot(ref nl) > 0;                     // Ray from outside going in?
                        double nc      = 1;
                        double nt      = 1.5;
                        double nnt     = into ? nc / nt : nt / nc;
                        double ddn     = r.d.Dot(ref nl);
                        double cos2t   = 1 - nnt * nnt * (1 - ddn * ddn);

                        if (cos2t < 0)                         // Total internal reflection
                        {
                            var tmp12 = radiance(ref reflRay, newDepth, ref rand);
                            var tmp13 = f.Mul(ref tmp12);
                            return(obj->e.Add(ref tmp13));
                        }
                        else
                        {
                            var    tmp14 = n.Mul((into ? 1 : -1) * (ddn * nnt + MathSqrt(cos2t)));
                            Vec    tdir  = (r.d.Mul(nnt).Sub(ref tmp14)).Norm();
                            double a     = nt - nc;
                            double b     = nt + nc;
                            double R0    = (a * a) / (b * b);
                            double c     = 1 - (into ? -ddn : tdir.Dot(ref n));
                            double Re    = R0 + (1 - R0) * c * c * c * c * c;
                            double Tr    = 1 - Re;
                            double P     = .25 + .5 * Re;
                            double RP    = Re / P;
                            double TP    = Tr / (1 - P);

                            Vec result;
                            if (newDepth > 2)
                            {
                                // Russian roulette and splitting for selecting reflection and/or refraction
                                if (rand.NextNumber() < P)
                                {
                                    result = radiance(ref reflRay, newDepth, ref rand).Mul(RP);
                                }
                                else
                                {
                                    var tmp15 = new Ray(ref x, ref tdir);
                                    result = radiance(ref tmp15, newDepth, ref rand).Mul(TP);
                                }
                            }
                            else
                            {
                                var tmp16 = new Ray(ref x, ref tdir);
                                var tmp17 = radiance(ref tmp16, newDepth, ref rand).Mul(Tr);
                                result = radiance(ref reflRay, newDepth, ref rand).Mul(Re).Add(ref tmp17);
                            }

                            var tmp18 = f.Mul(ref result);
                            return(obj->e.Add(ref tmp18));
                        }
                    }
                }
            }
        }
        public static unsafe bool Hit(this BvhNode n, NativeArray <Entity> entities, Ray r, float tMin, float tMax,
                                      ref Random rng, AccumulateJob.WorkingArea wa,
#if FULL_DIAGNOSTICS
                                      ref Diagnostics diagnostics,
#endif
                                      out HitRecord rec)
        {
            int       candidateCount = 0, nodeStackHeight = 1;
            BvhNode **nodeStackTail = wa.Nodes;
            Entity *  candidateListTail = wa.Entities - 1, candidateListHead = wa.Entities;
            float3    rayInvDirection = rcp(r.Direction);

            *nodeStackTail = &n;

            while (nodeStackHeight > 0)
            {
                BvhNode *nodePtr = *nodeStackTail--;
                nodeStackHeight--;

                if (!nodePtr->Bounds.Hit(r.Origin, rayInvDirection, tMin, tMax))
                {
                    continue;
                }
#if FULL_DIAGNOSTICS
                diagnostics.BoundsHitCount++;
#endif
                if (nodePtr->IsLeaf)
                {
                    *++candidateListTail = entities[nodePtr->EntityId];
                    candidateCount++;
                }
                else
                {
                    *++nodeStackTail = nodePtr->Left;
                    *++nodeStackTail = nodePtr->Right;
                    nodeStackHeight += 2;
                }
            }
#if FULL_DIAGNOSTICS
            diagnostics.CandidateCount = candidateCount;
#endif
            if (candidateCount == 0)
            {
                rec = default;
                return(false);
            }

#if BVH_SIMD
            // TODO: this is fully broken
            // skip SIMD codepath if there's only one
            if (candidateCount == 1)
            {
                return(candidateListHead->Hit(r, tMin, tMax, out rec));
            }

            var simdSpheresHead = (Sphere4 *)wa.Vectors;
            int simdBlockCount  = (int)ceil(candidateCount / 4.0f);

            float4 a = dot(r.Direction, r.Direction);
            int4   curId = int4(0, 1, 2, 3), hitId = -1;
            float4 hitT = tMax;

            Sphere4 *blockCursor     = simdSpheresHead;
            Entity * candidateCursor = candidateListHead;
            int      candidateIndex  = 0;
            for (int i = 0; i < simdBlockCount; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (candidateIndex < candidateCount)
                    {
                        Sphere *sphereData = candidateCursor->AsSphere;
                        float3  center     = sphereData->Center(r.Time);
                        blockCursor->CenterX[j]       = center.x;
                        blockCursor->CenterY[j]       = center.y;
                        blockCursor->CenterZ[j]       = center.z;
                        blockCursor->SquaredRadius[j] = sphereData->SquaredRadius;
                        ++candidateCursor;
                        ++candidateIndex;
                    }
                    else
                    {
                        blockCursor->CenterX[j]       = float.MaxValue;
                        blockCursor->CenterY[j]       = float.MaxValue;
                        blockCursor->CenterZ[j]       = float.MaxValue;
                        blockCursor->SquaredRadius[j] = 0;
                    }
                }

                float4 ocX = r.Origin.x - blockCursor->CenterX,
                       ocY = r.Origin.y - blockCursor->CenterY,
                       ocZ = r.Origin.z - blockCursor->CenterZ;

                float4 b            = ocX * r.Direction.x + ocY * r.Direction.y + ocZ * r.Direction.z;
                float4 c            = ocX * ocX + ocY * ocY + ocZ * ocZ - blockCursor->SquaredRadius;
                float4 discriminant = b * b - a * c;

                bool4 discriminantTest = discriminant > 0;

                if (any(discriminantTest))
                {
                    float4 sqrtDiscriminant = sqrt(discriminant);

                    float4 t0 = (-b - sqrtDiscriminant) / a;
                    float4 t1 = (-b + sqrtDiscriminant) / a;

                    float4 t    = select(t1, t0, t0 > tMin);
                    bool4  mask = discriminantTest & t > tMin & t < hitT;

                    hitId = select(hitId, curId, mask);
                    hitT  = select(hitT, t, mask);
                }

                curId += 4;
                ++blockCursor;
            }

            if (all(hitId == -1))
            {
                rec = default;
                return(false);
            }

            float   minDistance   = cmin(hitT);
            int     laneMask      = bitmask(hitT == minDistance);
            int     firstLane     = tzcnt(laneMask);
            int     closestId     = hitId[firstLane];
            Sphere *closestSphere = candidateListHead[closestId].AsSphere;
            float3  point         = r.GetPoint(minDistance);

            rec = new HitRecord(minDistance, point,
                                (point - closestSphere->Center(r.Time)) / closestSphere->Radius,
                                closestSphere->Material);

            return(true);
#else
            // iterative candidate tests (non-SIMD)
            bool anyHit = candidateListHead->Hit(r, tMin, tMax, ref rng, out rec);
            for (int i = 1; i < candidateCount; i++)
            {
                bool thisHit = candidateListHead[i].Hit(r, tMin, tMax, ref rng, out HitRecord thisRec);
                if (thisHit && (!anyHit || thisRec.Distance < rec.Distance))
                {
                    anyHit = true;
                    rec    = thisRec;
                }
            }
            if (anyHit)
            {
                return(true);
            }

            rec = default;
            return(false);
#endif
        }
 static int DoSphereVsSpheresSimd(Sphere *spheres, int numSpheres, float3 *center, float radius, out int numIntersections)
 {
     // YOUR SIMD CODE HERE
     numIntersections = 0;
     return(-1);
 }