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); }
public static Vector3 Trace(int depth, Scene scene, Ray ray, Vector3 backgroundColor) { if (depth == Game.settings.maxDepth) { Game.numPrimaryRays++; } float distance = 0.0f; int? indexOfNearest = null; if (Config.USE_BVH) { List <int> meshIndices = scene.bvh.Traverse(ray); if (meshIndices.Count > 0) { Game.numRayTests += meshIndices.Count; NearestIntersection(scene, meshIndices, ray, out distance, out indexOfNearest); if (indexOfNearest.HasValue) { indexOfNearest = meshIndices[indexOfNearest.Value]; } } } else { Game.numRayTests += scene.meshes.Count; NearestIntersection(scene.meshes, ray, out distance, out indexOfNearest); } if (indexOfNearest.HasValue) { Game.numRayIntersections++; int index = indexOfNearest.Value; Material material = scene.materials[index]; Mesh mesh = scene.meshes[index]; var intersection = ray.At(distance); var normal = mesh.Normal(intersection); Vector3 color = material.Color(mesh, ray, distance, intersection); var reflection = material.reflection; var refraction = material.refraction; var ior = material.ior; var diffuse = 1.0f - reflection - refraction; var result = Vector3.Zero; //Photon map if (diffuse > 0.0f) { result = diffuse * PhotonMapping.GatherPhotonEnergy(intersection, normal, index); } if (mesh.isSkyboxMesh) { return(material.Color(mesh, ray, distance, intersection)); } if (depth > 1) { bool outside = Vector3.Dot(ray.direction, normal) < 0.0f; Vector3 bias = Renderer.EPSILON * normal; switch (material.materialType) { case MaterialType.Diffuse: { result = color * result; break; } case MaterialType.Reflection: { Vector3 reflectionRayOrigin = outside ? intersection + bias : intersection - bias; Vector3 reflectionDirection = Renderer.Reflect(ray.direction, normal).Normalized(); Ray reflectionRay = new Ray(reflectionRayOrigin, reflectionDirection); Vector3 reflectionColor = Trace(depth - 1, scene, reflectionRay, backgroundColor); result += reflection * reflectionColor; result = color * result; break; } case MaterialType.Reflection_Refraction: { Vector3 refractionColor = new Vector3(0.0f); float kr = Renderer.Fresnel(ray.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(ray.direction, normal, ior).Normalized(); Ray refractionRay = new Ray(refractionRayOrigin, refractionDirection); refractionColor = Trace(depth - 1, scene, refractionRay, backgroundColor); } Vector3 reflectionDirection = Renderer.Reflect(ray.direction, normal).Normalized(); Vector3 reflectionRayOrigin = outside ? intersection + bias : intersection - bias; Ray reflectionRay = new Ray(reflectionRayOrigin, reflectionDirection); Vector3 reflectionColor = Trace(depth - 1, scene, reflectionRay, backgroundColor); result += (reflectionColor * kr + refractionColor * (1.0f - kr)) * reflection; result = color * result; break; } } } if (material.selected) { //Outline float outlineSize = 0.01f; switch (mesh.shape) { case Shape.Plane: { if (mesh.TextureCoords(intersection).X < outlineSize || mesh.TextureCoords(intersection).X > 1.0f - outlineSize || mesh.TextureCoords(intersection).Y < outlineSize || mesh.TextureCoords(intersection).Y > 1.0f - outlineSize) { result = Vector3.One; } break; } case Shape.Sphere: { float kr = Renderer.Fresnel(ray.direction, normal, 0.95f); result = Vector3.One * kr + result * (1.0f - kr); break; } } } return(result); } return(backgroundColor); }
private static void InitializePhotonMap() { PhotonMapping.InitializePhotonMap(settings); }