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(); } }
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; } } }