Beispiel #1
0
    static float3 Trace(Ray r, int depth, ref int inoutRayCount, ref SpheresSoA spheres, NativeArray <Material> materials, ref uint randState, bool doMaterialE = true)
    {
        Hit rec = default(Hit);
        int id  = 0;

        ++inoutRayCount;
        if (HitWorld(r, kMinT, kMaxT, ref rec, ref id, ref spheres))
        {
            Ray    scattered;
            float3 attenuation;
            float3 lightE;
            var    mat  = materials[id];
            var    matE = mat.emissive;
            if (depth < kMaxDepth && Scatter(mat, r, rec, out attenuation, out scattered, out lightE, ref inoutRayCount, ref spheres, materials, ref randState))
            {
                #if DO_LIGHT_SAMPLING
                if (!doMaterialE)
                {
                    matE = new float3(0, 0, 0);
                }
                doMaterialE = (mat.type != Material.Type.Lambert);
                #endif
                return(matE + lightE + attenuation * Trace(scattered, depth + 1, ref inoutRayCount, ref spheres, materials, ref randState, doMaterialE));
            }
            else
            {
                return(matE);
            }
        }
        else
        {
            // sky
            float3 unitDir = r.dir;
            float  t       = 0.5f * (unitDir.y + 1.0f);
            return(((1.0f - t) * new float3(1.0f, 1.0f, 1.0f) + t * new float3(0.5f, 0.7f, 1.0f)) * 0.3f);
        }
    }
Beispiel #2
0
    static bool Scatter(Material mat, Ray r_in, Hit rec, out float3 attenuation, out Ray scattered, out float3 outLightE, ref int inoutRayCount, ref SpheresSoA spheres, NativeArray <Material> materials, ref uint randState)
    {
        outLightE = new float3(0, 0, 0);
        if (mat.type == Material.Type.Lambert)
        {
            // random point inside unit sphere that is tangent to the hit point
            float3 target = rec.pos + rec.normal + MathUtil.RandomUnitVector(ref randState);
            scattered   = new Ray(rec.pos, normalize(target - rec.pos));
            attenuation = mat.albedo;

            // sample lights
#if DO_LIGHT_SAMPLING
            for (int j = 0; j < spheres.emissiveCount; ++j)
            {
                int i = spheres.emissives[j];
                //@TODO if (&mat == &smat)
                //    continue; // skip self
                //var s = spheres[i];
                float3 scenter   = new float3(spheres.centerX[i], spheres.centerY[i], spheres.centerZ[i]);
                float  sqRradius = spheres.sqRadius[i];

                // create a random direction towards sphere
                // coord system for sampling: sw, su, sv
                float3 sw = normalize(scenter - rec.pos);
                float3 su = normalize(cross(abs(sw.x) > 0.01f ? new float3(0, 1, 0) : new float3(1, 0, 0), sw));
                float3 sv = cross(sw, su);
                // sample sphere by solid angle
                float  cosAMax = sqrt(max(0.0f, 1.0f - sqRradius / lengthSquared(rec.pos - scenter)));
                float  eps1 = RandomFloat01(ref randState), eps2 = RandomFloat01(ref randState);
                float  cosA = 1.0f - eps1 + eps1 * cosAMax;
                float  sinA = sqrt(1.0f - cosA * cosA);
                float  phi  = 2 * PI * eps2;
                float3 l    = su * cos(phi) * sinA + sv * sin(phi) * sinA + sw * cosA;
                l = normalize(l);

                // shoot shadow ray
                Hit lightHit = default(Hit);
                int hitID    = 0;
                ++inoutRayCount;
                if (HitWorld(new Ray(rec.pos, l), kMinT, kMaxT, ref lightHit, ref hitID, ref spheres) && hitID == i)
                {
                    float omega = 2 * PI * (1 - cosAMax);

                    float3 rdir = r_in.dir;
                    float3 nl   = dot(rec.normal, rdir) < 0 ? rec.normal : -rec.normal;
                    outLightE += (mat.albedo * materials[i].emissive) * (max(0.0f, dot(l, nl)) * omega / PI);
                }
            }
#endif
            return(true);
        }
        else if (mat.type == Material.Type.Metal)
        {
            float3 refl = reflect(r_in.dir, rec.normal);
            // reflected ray, and random inside of sphere based on roughness
            scattered   = new Ray(rec.pos, normalize(refl + mat.roughness * RandomInUnitSphere(ref randState)));
            attenuation = mat.albedo;
            return(dot(scattered.dir, rec.normal) > 0);
        }
        else if (mat.type == Material.Type.Dielectric)
        {
            float3 outwardN;
            float3 rdir = r_in.dir;
            float3 refl = reflect(rdir, rec.normal);
            float  nint;
            attenuation = new float3(1, 1, 1);
            float3 refr;
            float  reflProb;
            float  cosine;
            if (dot(rdir, rec.normal) > 0)
            {
                outwardN = -rec.normal;
                nint     = mat.ri;
                cosine   = mat.ri * dot(rdir, rec.normal);
            }
            else
            {
                outwardN = rec.normal;
                nint     = 1.0f / mat.ri;
                cosine   = -dot(rdir, rec.normal);
            }
            if (Refract(rdir, outwardN, nint, out refr))
            {
                reflProb = Schlick(cosine, mat.ri);
            }
            else
            {
                reflProb = 1;
            }
            if (RandomFloat01(ref randState) < reflProb)
            {
                scattered = new Ray(rec.pos, normalize(refl));
            }
            else
            {
                scattered = new Ray(rec.pos, normalize(refr));
            }
        }
        else
        {
            attenuation = new float3(1, 0, 1);
            scattered   = default(Ray);
            return(false);
        }
        return(true);
    }
Beispiel #3
0
 static bool HitWorld(Ray r, float tMin, float tMax, ref Hit outHit, ref int outID, ref SpheresSoA spheres)
 {
     outID = spheres.HitSpheres(ref r, tMin, tMax, ref outHit);
     return(outID != -1);
 }
Beispiel #4
0
 public Test()
 {
     s_SpheresSoA = new SpheresSoA(s_SpheresData.Length);
 }