示例#1
0
        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;
            }
            }
        }
示例#3
0
        public static void Render(RenderSettings settings, Camera camera)
        {
            if (settings.traceMethod == TraceMethod.PhotonTracing)
            {
                if (Config.RENDER_PHOTON_MAP)
                {
                    screen.UpdateSurface(PhotonMapping.PhotonMapRender(settings, camera));
                    return;
                }
            }

            Bitmap bitmap = new Bitmap(settings.width, settings.height);

            for (int j = 0; j < settings.height; ++j)
            {
                for (int i = 0; i < settings.width; ++i)
                {
                    Vector3 colorVector = settings.backgroundColor;

                    float vx = i / (float)settings.width;
                    float vy = j / (float)settings.height;

                    Ray ray = camera.RayThroughScreen(vx, vy);

                    switch (settings.traceMethod)
                    {
                    case TraceMethod.WhittedRayTracing:
                    {
                        colorVector = RayTracer.Trace(settings.maxDepth, settings.scene, ray, settings.backgroundColor);
                        break;
                    }

                    case TraceMethod.PathTracing:
                    {
                        int sampleCount = Config.PATH_TRACING_SAMPLES;

                        //TODO: Unsure if this should be here or if I should start random sampling loop from 0 instead of 1
                        colorVector = PathTracer.Trace(settings.maxDepth, settings.scene, ray, settings.backgroundColor);

                        for (int k = 1; k < sampleCount; k++)
                        {
                            var offsetXMin = -(0.5f / settings.width);
                            var offsetXMax = (0.5f / settings.width);
                            var offsetYMin = -(0.5f / settings.height);
                            var offsetYMax = (0.5f / settings.height);

                            var x = vx + MathHelper.RandomRange(offsetXMin, offsetXMax);
                            var y = vy + MathHelper.RandomRange(offsetYMin, offsetYMax);

                            ray = camera.RayThroughScreen(x, y);

                            colorVector += PathTracer.Trace(settings.maxDepth, settings.scene, ray, settings.backgroundColor);
                        }

                        colorVector /= sampleCount;
                        break;
                    }

                    case TraceMethod.PhotonTracing:
                    {
                        colorVector = PhotonTracer.Trace(settings.maxDepth, settings.scene, ray, settings.backgroundColor);
                        break;
                    }
                    }

                    if (settings.showUI)
                    {
                        //Render UI
                        Vector3?uiColor = RenderUI(settings, i, j);

                        if (uiColor.HasValue)
                        {
                            colorVector += uiColor.Value;
                        }
                    }

                    float red   = MathHelper.Clamp(colorVector.X, 0.0f, 1.0f);
                    float green = MathHelper.Clamp(colorVector.Y, 0.0f, 1.0f);
                    float blue  = MathHelper.Clamp(colorVector.Z, 0.0f, 1.0f);

                    Color color = Color.FromArgb(255, (int)(red * 255), (int)(green * 255), (int)(blue * 255));
                    bitmap.SetPixel(i, j, color);
                }
            }

            screen.UpdateSurface(bitmap);
        }