예제 #1
0
파일: Game.cs 프로젝트: trymtrim/RayTracer
        private void HandleObjectSelection(Vector2 position)
        {
            float scale            = (float)Math.Tan(MathHelper.DegreesToRadians(_camera.fov * 0.5f));
            float imageAspectRatio = (float)settings.width / settings.height;

            float x = (2.0f * (position.X + 0.5f) / settings.width - 1.0f) * imageAspectRatio * scale;
            float y = (1.0f - 2.0f * (position.Y + 0.5f) / settings.height) * scale;

            RayTracer.NearestIntersection(settings.scene.meshes, new Ray(_camera.position, new Vector3(x, -y, 1.0f)), out float distance, out int?indexOfNearest);

            if (indexOfNearest.HasValue)
            {
                SelectObject(indexOfNearest.Value);
            }
            else
            {
                DeselectObject();
            }
        }
예제 #2
0
        private static void TracePhoton(int depth, Scene scene, Ray photonRay, bool causticTracing = false)
        {
            RayTracer.NearestIntersection(scene.meshes, photonRay, out float distance, out int?indexOfNearest);

            if (!indexOfNearest.HasValue)
            {
                return;
            }

            Vector3  intersection = photonRay.At(distance);
            Vector3  normal       = scene.meshes[indexOfNearest.Value].Normal(intersection);
            int      index        = indexOfNearest.Value;
            Material material     = scene.materials[index];

            _photon.L        = photonRay.direction;      //Incident direction
            _photon.position = intersection;             //World space position of the photon hit

            //Initialize photon
            if (depth == Config.MAX_PHOTON_DEPTH && !_shadowPhoton)
            {
                _caustic = false;

                _photon.power = Vector3.One;
            }
            else if (_shadowPhoton)             //Shadow photon (indirect illumination)
            {
                if (material.materialType == MaterialType.Diffuse)
                {
                    _photon.power = new Vector3(-Config.SHADOW_STRENGTH);

                    //TODO: This might not work with diffuse spheres right now as the shadow photon will stop inside the sphere (?)
                    _globalPhotonMap[index].Add(new[] { _photon.position.X, _photon.position.Y, _photon.position.Z }, _photon);                     //Store photon
                }
                else
                {
                    photonRay.origin = intersection + (photonRay.direction * Renderer.EPSILON);
                    TracePhoton(0, scene, photonRay);
                }

                _shadowPhoton = false;
                return;
            }

            if (depth == 0)
            {
                return;
            }

            switch (material.materialType)
            {
            case MaterialType.Diffuse:
            {
                if (_caustic)
                {
                    _causticPhotonMap[index].Add(new[] { _photon.position.X, _photon.position.Y, _photon.position.Z }, _photon);                                     //Store photon
                    _caustic = false;
                }
                else if (causticTracing)
                {
                    _caustic = false;
                    return;
                }
                else
                {
                    _photon.power *= 1.0f / (float)Math.Sqrt(Config.MAX_PHOTON_DEPTH - depth + 1.0f);

                    //TODO: This might not work with diffuse spheres right now as the shadow photon will stop inside the sphere (?)
                    _globalPhotonMap[index].Add(new[] { _photon.position.X, _photon.position.Y, _photon.position.Z }, _photon);                                     //Store photon

                    //TODO: Randomly absorb or bounce (Russian roulette)?

                    //Bounce the photon
                    Vector3 newNormal = normal;
                    if (Vector3.Dot(normal, photonRay.direction) > 0.0f)
                    {
                        newNormal = -normal;
                    }

                    var direction = MathHelper.RandomOnHemisphereWithStaticSeed(newNormal);
                    Ray newRay    = new Ray(intersection + direction * Renderer.EPSILON, direction);
                    TracePhoton(depth - 1, scene, newRay);
                }

                break;
            }

            case MaterialType.Reflection:
            {
                if (causticTracing)
                {
                    _caustic = true;
                }
                else
                {
                    //Shadow photon ray (currently only doing it on reflection and refraction objects, since the scene only consists of those)
                    _shadowPhoton = true;

                    Vector3 shadowRayOrigin = intersection + (photonRay.direction * Renderer.EPSILON);
                    Ray     shadowRay       = new Ray(shadowRayOrigin, photonRay.direction);
                    TracePhoton(0, scene, shadowRay);

                    _shadowPhoton = false;
                }

                bool    outside = Vector3.Dot(photonRay.direction, normal) < 0.0f;
                Vector3 bias    = Renderer.EPSILON * normal;

                Vector3 reflectionRayOrigin = outside ? intersection + bias : intersection - bias;
                Vector3 reflectionDirection = Renderer.Reflect(photonRay.direction, normal).Normalized();
                Ray     reflectionRay       = new Ray(reflectionRayOrigin, reflectionDirection);

                TracePhoton(depth - 1, scene, reflectionRay, causticTracing);

                break;
            }

            case MaterialType.Reflection_Refraction:
            {
                if (causticTracing)
                {
                    _caustic = true;
                }
                else
                {
                    //Shadow photon ray (currently only doing it on reflection and refraction objects, since the scene only consists of those)
                    _shadowPhoton = true;

                    Vector3 shadowRayOrigin = intersection + (photonRay.direction * Renderer.EPSILON);
                    Ray     shadowRay       = new Ray(shadowRayOrigin, photonRay.direction);
                    TracePhoton(0, scene, shadowRay);

                    _shadowPhoton = false;
                }

                var     ior     = material.ior;
                bool    outside = Vector3.Dot(photonRay.direction, normal) < 0.0f;
                Vector3 bias    = Renderer.EPSILON * normal;

                float kr = Renderer.Fresnel(photonRay.direction, normal, ior);

                //Compute refraction if it is not a case of total internal reflection
                if (kr < 1.0f)
                {
                    Vector3 refractionRayOrigin = outside ? intersection - bias : intersection + bias;
                    Vector3 refractionDirection = Renderer.Refract(photonRay.direction, normal, ior).Normalized();
                    Ray     refractionRay       = new Ray(refractionRayOrigin, refractionDirection);

                    TracePhoton(depth - 1, scene, refractionRay, causticTracing);
                }
                else
                {
                    Vector3 reflectionRayOrigin = outside ? intersection + bias : intersection - bias;
                    Vector3 reflectionDirection = Renderer.Reflect(photonRay.direction, normal).Normalized();
                    Ray     reflectionRay       = new Ray(reflectionRayOrigin, reflectionDirection);

                    TracePhoton(depth - 1, scene, reflectionRay, causticTracing);
                }
                break;
            }
            }
        }