예제 #1
0
        protected override void Raycast(ref State state, ref TriangleSoA container)
        {
            Ray   ray = state.ray;
            float minDist = state.minDist, maxDist = state.maxDist;
            int   rayIndex = state.rayIndex;

            HitInfo[] hits    = state.hits;
            HitInfo   hitInfo = new HitInfo();

            for (int i = 0; i < container.objectCount; i++)
            {
                // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
                Vector3 e1, e2;
                Vector3 p1 = container.p1[i];
                Vector3 p2 = container.p2[i];
                Vector3 p3 = container.p3[i];

                e1 = p2 - p1;
                e2 = p3 - p1;
                Vector3 h = Vector3.Cross(ray.direction, e2);
                float   a = Vector3.Dot(e1, h);
                if (a > -Epsilon && a < Epsilon)
                {
                    continue;
                }

                float   f = 1.0f / a;
                Vector3 s = ray.origin - p1;
                float   u = f * Vector3.Dot(s, h);
                if (u < 0 || u > 1)
                {
                    continue;
                }

                Vector3 q = Vector3.Cross(s, e1);
                float   v = f * Vector3.Dot(ray.direction, q);
                if (v < 0 || (u + v) > 1)
                {
                    continue;
                }

                float t = f * Vector3.Dot(e2, q);
                if (t > minDist && t <= maxDist)
                {
                    hitInfo.distance = t;
                    hitInfo.material = container.material[i];
                    ray.GetPointOptimized(t, ref hitInfo.point);

                    // Barycentric normal
                    Vector3 v0 = p2 - p1, v1 = p3 - p1, v2 = hitInfo.point - p1;
                    float   d00   = Vector3.Dot(v0, v0);
                    float   d01   = Vector3.Dot(v0, v1);
                    float   d11   = Vector3.Dot(v1, v1);
                    float   d20   = Vector3.Dot(v2, v0);
                    float   d21   = Vector3.Dot(v2, v1);
                    float   denom = d00 * d11 - d01 * d01;
                    float   baryV = (d11 * d20 - d01 * d21) / denom;
                    float   baryW = (d00 * d21 - d01 * d20) / denom;
                    float   baryU = 1.0f - baryV - baryW;

                    hitInfo.normal = container.n1[i] * baryU + container.n2[i] * baryV + container.n3[i] * baryW;
                    if (BitHelper.GetBit(ref state.hitMask, rayIndex))
                    {
                        HitInfo.ExchangeIfBetter(ref hits[rayIndex], hitInfo);
                    }
                    else
                    {
                        hits[rayIndex] = hitInfo;
                        BitHelper.SetBit(ref state.hitMask, rayIndex);
                    }
                }
            }
        }
예제 #2
0
파일: Sphere.cs 프로젝트: kennux/PathTracer
        protected override void Raycast(ref State state, ref SphereSoA container)
        {
            Ray   ray = state.ray;
            float minDist = state.minDist, maxDist = state.maxDist;
            int   rayIndex = state.rayIndex;

            HitInfo[] hits    = state.hits;
            HitInfo   hitInfo = new HitInfo();

            for (int j = 0; j < container.objectCount; j++)
            {
                // Inlined and optimized math
                Vector3 center = container.center[j];
                Vector3 oc     = ray.origin - center;
                float   b      = Vector3.Dot(oc, ray.direction);
                if (b > 0f) // Behind?
                {
                    continue;
                }

                bool  hasHit          = false;
                float c               = oc.LengthSquared();
                float discriminantSqr = b * b - (c - container.radiusSq[j]);
                if (discriminantSqr > 0)
                {
                    float discriminant = Mathf.Sqrt(discriminantSqr);
                    hitInfo.distance = (-b - discriminant);
                    if (hitInfo.distance < maxDist && hitInfo.distance > minDist)
                    {
                        ray.GetPointOptimized(hitInfo.distance, ref hitInfo.point);
                        hitInfo.normal   = (hitInfo.point - center) * container.invRadius[j];
                        hitInfo.material = container.material[j];
                        hasHit           = true;
                    }
                    else
                    {
                        hitInfo.distance = (-b + discriminant);
                        if (hitInfo.distance < maxDist && hitInfo.distance > minDist)
                        {
                            ray.GetPointOptimized(hitInfo.distance, ref hitInfo.point);
                            hitInfo.normal   = (hitInfo.point - center) * container.invRadius[j];
                            hitInfo.material = container.material[j];
                            hasHit           = true;
                        }
                    }
                }

                if (hasHit)
                {
                    if (BitHelper.GetBit(ref state.hitMask, rayIndex))
                    {
                        HitInfo.ExchangeIfBetter(ref state.hits[rayIndex], hitInfo);
                    }
                    else
                    {
                        hits[rayIndex] = hitInfo;
                        BitHelper.SetBit(ref state.hitMask, rayIndex);
                    }
                }
            }
        }
예제 #3
0
파일: Tracer.cs 프로젝트: kennux/PathTracer
        public static void TraceTile(TileTraceParameters tile, float[] backbuffer, out long rayCount)
        {
            InitBatchArray(ref _rays);
            InitBatchArray(ref _hits);
            InitBatchArray(ref _localColor);

            Ray[]     rays       = _rays;
            HitInfo[] hits       = _hits;
            Vector3[] localColor = _localColor;
            uint      rndState   = FastRandom.Seed();

            rayCount = 0;

            for (int x = tile.xStart; x < tile.xEnd; x++)
            {
                for (int y = tile.yStart; y < tile.yEnd; y++)
                {
                    Vector3 color = new Vector3(0, 0, 0);
                    // Sample bouncing batches
                    for (int b = 0; b < tile.runtimeParams.sampleBatchCount; b++)
                    {
                        // Calculate batch info
                        int batchStart = b * tile.runtimeParams.batchSize, batchEnd = batchStart + tile.runtimeParams.batchSize;
                        int batchRayCount = Math.Min(batchEnd, tile.parameters.samplesPerPixel);
                        batchRayCount -= batchStart;

                        uint  hitMask = 0;
                        uint  bounces = uint.MaxValue;
                        float u = x * tile.runtimeParams.invWidth, v = y * tile.runtimeParams.invHeight;

                        // Get initial rays
                        tile.parameters.camera.GetRays(u, v, rays, batchRayCount, ref rndState);

                        // Reset local colors
                        for (int i = 0; i < batchRayCount; i++)
                        {
                            localColor[i] = tile.parameters.ambientLight;
                        }

                        Vector3 atten;
                        int     bounceCount = 0;
                        while (bounceCount < tile.parameters.maxBounces && bounces != 0)
                        {
                            tile.parameters.scene.Raycast(rays, hits, 0.01f, tile.parameters.maxDepth, batchRayCount, bounces, ref hitMask, ref rayCount);
                            if (hitMask == 0)
                            {
                                break;
                            }

                            bounces = 0;
                            for (int i = 0; i < batchRayCount; i++)
                            {
                                if (BitHelper.GetBit(ref hitMask, i)) // Did ray hit?
                                {
                                    if (hits[i].material.Scatter(ref hits[i], out atten, ref rays[i], tile.parameters.scene, ref rndState))
                                    {
                                        BitHelper.SetBit(ref bounces, i);
                                    }

                                    localColor[i] *= atten;
                                }
                            }
                            bounceCount++;
                        }

                        for (int i = 0; i < batchRayCount; i++)
                        {
                            color += localColor[i];
                        }
                    }

                    color *= tile.runtimeParams.invSamplesPerPixel;

                    // Write backbuffer
                    int idx = (y * (tile.parameters.width * 3)) + (x * 3);
                    backbuffer[idx]     = color.X;
                    backbuffer[idx + 1] = color.Y;
                    backbuffer[idx + 2] = color.Z;
                }
            }
        }