public static void DrawArea <T, M>(int id, int x0, int y0, int xf, int yf, Raytracer <DefaultRayPayload, T, M> raycaster, Texture2D texture, float4x4 viewMatrix, float4x4 projectionMatrix, Scene <T, M> scene, int step = 1) where T : struct where M : struct { for (int px = x0; px < xf; px += step) { for (int py = y0; py < yf; py += step) { //int progress = (px * yf + py); //if (progress % 100 == 0) //{ // Console.WriteLine($"{id}: " + progress * 100 / (xf * yf) + "% "); //} RayDescription ray = RayDescription.FromScreen(px + 0.5f, py + 0.5f, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); DefaultRayPayload coloring = new DefaultRayPayload(); raycaster.Trace(scene, ray, ref coloring); for (int i = 0; i < step; i++) { for (int j = 0; j < step; j++) { texture.Write(Math.Min(px + i, texture.Width - 1), Math.Min(py + j, texture.Height - 1), float4(coloring.Color, 1)); } } } } Console.WriteLine($"Done {id}"); }
static void SimpleRaycast(Texture2D texture) { Raytracer <RayPayload, float3> raycaster = new Raytracer <RayPayload, float3>(); // View and projection matrices float4x4 viewMatrix = Transforms.LookAtLH(float3(2, 1f, 4), float3(0, 0, 0), float3(0, 1, 0)); float4x4 projectionMatrix = Transforms.PerspectiveFovLH(pi_over_4, texture.Height / (float)texture.Width, 0.01f, 20); Scene <float3> scene = new Scene <float3>(); CreateScene(scene); raycaster.OnClosestHit += delegate(IRaycastContext context, float3 attribute, ref RayPayload payload) { payload.Color = attribute; }; for (float px = 0.5f; px < texture.Width; px++) { for (float py = 0.5f; py < texture.Height; py++) { RayDescription ray = RayDescription.FromScreen(px, py, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); RayPayload coloring = new RayPayload(); raycaster.Trace(scene, ray, ref coloring); texture.Write((int)px, (int)py, float4(coloring.Color, 1)); } } }
public static void Draw <T, M>(Texture2D texture, Raytracer <DefaultRayPayload, T, M> raytracer, Scene <T, M> scene, float4x4 viewMatrix, float4x4 projectionMatrix, int rendStep = 1, int gridXDiv = 8, int gridYDiv = 8) where T : struct where M : struct { var start = new Stopwatch(); start.Start(); var tasks = new List <Task>(); int id = 0, xStep = texture.Width / gridXDiv, yStep = texture.Height / gridYDiv; for (int i = 0; i *yStep < texture.Height; i++) { for (int j = 0; j *xStep < texture.Width; j++) { int threadId = id, x0 = j * xStep, y0 = i * yStep, maxX = Math.Min((j + 1) * xStep, texture.Width), maxY = Math.Min((i + 1) * yStep, texture.Height); tasks.Add(Task.Run(() => RenderUtils.DrawArea(threadId, x0, y0, maxX, maxY, raytracer, texture, viewMatrix, projectionMatrix, scene, rendStep))); id++; } } Task.WaitAll(tasks.ToArray()); start.Stop(); Console.WriteLine($"Elapsed {start.ElapsedMilliseconds} milliseconds"); }
static void LitRaycast(Texture2D texture) { // Scene Setup float3 CameraPosition = float3(3, 2f, 4); float3 LightPosition = float3(3, 5, -2); // View and projection matrices float4x4 viewMatrix = Transforms.LookAtLH(CameraPosition, float3(0, 1, 0), float3(0, 1, 0)); float4x4 projectionMatrix = Transforms.PerspectiveFovLH(pi_over_4, texture.Height / (float)texture.Width, 0.01f, 20); Scene <PositionNormal> scene = new Scene <PositionNormal>(); CreateScene(scene); // Raycaster to trace rays and check for shadow rays. Raytracer <ShadowRayPayload, PositionNormal> shadower = new Raytracer <ShadowRayPayload, PositionNormal>(); shadower.OnAnyHit += delegate(IRaycastContext context, PositionNormal attribute, ref ShadowRayPayload payload) { // If any object is found in ray-path to the light, the ray is shadowed. payload.Shadowed = true; // No neccessary to continue checking other objects return(HitResult.Stop); }; // Raycaster to trace rays and lit closest surfaces Raytracer <RayPayload, PositionNormal> raycaster = new Raytracer <RayPayload, PositionNormal>(); raycaster.OnClosestHit += delegate(IRaycastContext context, PositionNormal attribute, ref RayPayload payload) { // Move geometry attribute to world space attribute = attribute.Transform(context.FromGeometryToWorld); float3 V = normalize(CameraPosition - attribute.Position); float3 L = normalize(LightPosition - attribute.Position); float lambertFactor = max(0, dot(attribute.Normal, L)); // Check ray to light... ShadowRayPayload shadow = new ShadowRayPayload(); shadower.Trace(scene, RayDescription.FromTo( attribute.Position + attribute.Normal * 0.001f, // Move an epsilon away from the surface to avoid self-shadowing LightPosition), ref shadow); payload.Color = shadow.Shadowed ? float3(0, 0, 0) : float3(1, 1, 1) * lambertFactor; }; raycaster.OnMiss += delegate(IRaycastContext context, ref RayPayload payload) { payload.Color = float3(0, 0, 1); // Blue, as the sky. }; // Render all points of the screen for (int px = 0; px < texture.Width; px++) { for (int py = 0; py < texture.Height; py++) { RayDescription ray = RayDescription.FromScreen(px + 0.5f, py + 0.5f, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); RayPayload coloring = new RayPayload(); raycaster.Trace(scene, ray, ref coloring); texture.Write(px, py, float4(coloring.Color, 1)); } } }
static void Pathtracing(Texture2D texture, int pass) { // View and projection matrices float4x4 viewMatrix = Transforms.LookAtLH(CameraPosition, float3(0, 1, 0), float3(0, 1, 0)); float4x4 projectionMatrix = Transforms.PerspectiveFovLH(pi_over_4, texture.Height / (float)texture.Width, 0.01f, 20); Scene <PositionNormalCoordinate, Material> scene = new Scene <PositionNormalCoordinate, Material>(); //CreateMeshScene(scene); CreateRaycastScene(scene); // Raycaster to trace rays and lit closest surfaces Raytracer <PTRayPayload, PositionNormalCoordinate, Material> raycaster = new Raytracer <PTRayPayload, PositionNormalCoordinate, Material>(); raycaster.OnClosestHit += delegate(IRaycastContext context, PositionNormalCoordinate attribute, Material material, ref PTRayPayload payload) { // Move geometry attribute to world space attribute = attribute.Transform(context.FromGeometryToWorld); float3 V = -normalize(context.GlobalRay.Direction); attribute.Normal = normalize(attribute.Normal); if (material.BumpMap != null) { float3 T, B; createOrthoBasis(attribute.Normal, out T, out B); float3 tangentBump = material.BumpMap.Sample(material.TextureSampler, attribute.Coordinates).xyz * 2 - 1; float3 globalBump = tangentBump.x * T + tangentBump.y * B + tangentBump.z * attribute.Normal; attribute.Normal = globalBump;// normalize(attribute.Normal + globalBump * 5f); } ScatteredRay outgoing = material.Scatter(attribute, V); float lambertFactor = abs(dot(attribute.Normal, outgoing.Direction)); payload.Color += payload.Importance * material.Emissive; // Recursive calls for indirect light due to reflections and refractions if (payload.Bounces > 0) { float3 D = outgoing.Direction; // recursive direction to check float3 facedNormal = dot(D, attribute.Normal) > 0 ? attribute.Normal : -attribute.Normal; // normal respect to direction RayDescription ray = new RayDescription { Direction = D, Origin = attribute.Position + facedNormal * 0.001f, MinT = 0.0001f, MaxT = 10000 }; payload.Importance *= outgoing.Ratio * lambertFactor / outgoing.PDF; payload.Bounces--; raycaster.Trace(scene, ray, ref payload); } }; raycaster.OnMiss += delegate(IRaycastContext context, ref PTRayPayload payload) { payload.Color = float3(0, 0, 0); // Blue, as the sky. }; /// Render all points of the screen for (int px = 0; px < texture.Width; px++) { for (int py = 0; py < texture.Height; py++) { int progress = (px * texture.Height + py); if (progress % 10000 == 0) { Console.Write("\r" + progress * 100 / (float)(texture.Width * texture.Height) + "% "); } RayDescription ray = RayDescription.FromScreen(px + 0.5f, py + 0.5f, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); float4 accum = texture.Read(px, py) * pass; PTRayPayload coloring = new PTRayPayload(); coloring.Importance = float3(1, 1, 1); coloring.Bounces = 3; raycaster.Trace(scene, ray, ref coloring); texture.Write(px, py, float4((accum.xyz + coloring.Color) / (pass + 1), 1)); } } }
static void Raytracing(Texture2D texture) { // View and projection matrices float4x4 viewMatrix = Transforms.LookAtLH(CameraPosition, float3(0, 1, 0), float3(0, 1, 0)); float4x4 projectionMatrix = Transforms.PerspectiveFovLH(pi_over_4, texture.Height / (float)texture.Width, 0.01f, 20); Scene <PositionNormalCoordinate, Material> scene = new Scene <PositionNormalCoordinate, Material>(); //CreateMeshScene(scene); CreateRaycastScene(scene); // Raycaster to trace rays and check for shadow rays. Raytracer <ShadowRayPayload, PositionNormalCoordinate, Material> shadower = new Raytracer <ShadowRayPayload, PositionNormalCoordinate, Material>(); shadower.OnAnyHit += delegate(IRaycastContext context, PositionNormalCoordinate attribute, Material material, ref ShadowRayPayload payload) { if (any(material.Emissive)) { return(HitResult.Discard); // Discard light sources during shadow test. } // If any object is found in ray-path to the light, the ray is shadowed. payload.Shadowed = true; // No neccessary to continue checking other objects return(HitResult.Stop); }; // Raycaster to trace rays and lit closest surfaces Raytracer <MyRayPayload, PositionNormalCoordinate, Material> raycaster = new Raytracer <MyRayPayload, PositionNormalCoordinate, Material>(); raycaster.OnClosestHit += delegate(IRaycastContext context, PositionNormalCoordinate attribute, Material material, ref MyRayPayload payload) { // Move geometry attribute to world space attribute = attribute.Transform(context.FromGeometryToWorld); float3 V = -normalize(context.GlobalRay.Direction); float3 L = (LightPosition - attribute.Position); float d = length(L); L /= d; // normalize direction to light reusing distance to light attribute.Normal = normalize(attribute.Normal); if (material.BumpMap != null) { float3 T, B; createOrthoBasis(attribute.Normal, out T, out B); float3 tangentBump = material.BumpMap.Sample(material.TextureSampler, attribute.Coordinates).xyz * 2 - 1; float3 globalBump = tangentBump.x * T + tangentBump.y * B + tangentBump.z * attribute.Normal; //attribute.Normal = globalBump; attribute.Normal = normalize(attribute.Normal + globalBump); } float lambertFactor = max(0, dot(attribute.Normal, L)); // Check ray to light... ShadowRayPayload shadow = new ShadowRayPayload(); shadower.Trace(scene, RayDescription.FromDir(attribute.Position + attribute.Normal * 0.001f, // Move an epsilon away from the surface to avoid self-shadowing L), ref shadow); float3 Intensity = (shadow.Shadowed ? 0.2f : 1.0f) * LightIntensity / (d * d); payload.Color = material.Emissive + material.EvalBRDF(attribute, V, L) * Intensity * lambertFactor; // direct light computation // Recursive calls for indirect light due to reflections and refractions if (payload.Bounces > 0) { foreach (var impulse in material.GetBRDFImpulses(attribute, V)) { float3 D = impulse.Direction; // recursive direction to check float3 facedNormal = dot(D, attribute.Normal) > 0 ? attribute.Normal : -attribute.Normal; // normal respect to direction RayDescription ray = new RayDescription { Direction = D, Origin = attribute.Position + facedNormal * 0.001f, MinT = 0.0001f, MaxT = 10000 }; MyRayPayload newPayload = new MyRayPayload { Bounces = payload.Bounces - 1 }; raycaster.Trace(scene, ray, ref newPayload); payload.Color += newPayload.Color * impulse.Ratio; } } }; raycaster.OnMiss += delegate(IRaycastContext context, ref MyRayPayload payload) { payload.Color = float3(0, 0, 0); // Blue, as the sky. }; /// Render all points of the screen for (int px = 0; px < texture.Width; px++) { for (int py = 0; py < texture.Height; py++) { int progress = (px * texture.Height + py); if (progress % 1000 == 0) { Console.Write("\r" + progress * 100 / (float)(texture.Width * texture.Height) + "% "); } RayDescription ray = RayDescription.FromScreen(px + 0.5f, py + 0.5f, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); MyRayPayload coloring = new MyRayPayload(); coloring.Bounces = 3; raycaster.Trace(scene, ray, ref coloring); texture.Write(px, py, float4(coloring.Color, 1)); } } }
static void RaycastingMeshTexture(Texture2D texture, Material mat) { // Scene Setup float3 CameraPosition = float3(3, 2f, 4); float3 LightPosition = float3(3, 5, -2); float3 LightIntensity = float3(1, 1, 1) * 100; // View and projection matrices float4x4 viewMatrix = Transforms.LookAtLH(CameraPosition, float3(0, 1, 0), float3(0, 1, 0)); float4x4 projectionMatrix = Transforms.PerspectiveFovLH(pi_over_4, texture.Height / (float)texture.Width, 0.01f, 20); Scene <PositionNormalCoordinate, Material> scene = new Scene <PositionNormalCoordinate, Material>(); CreateMeshScene(scene); //CreateRaycastScene(scene, mat); // Raycaster to trace rays and check for shadow rays. Raytracer <ShadowRayPayload, PositionNormalCoordinate, Material> shadower = new Raytracer <ShadowRayPayload, PositionNormalCoordinate, Material>(); shadower.OnAnyHit += delegate(IRaycastContext context, PositionNormalCoordinate attribute, Material material, ref ShadowRayPayload payload) { // If any object is found in ray-path to the light, the ray is shadowed. payload.Shadowed = true; // No neccessary to continue checking other objects return(HitResult.Stop); }; // Raycaster to trace rays and lit closest surfaces Raytracer <MyRayPayload, PositionNormalCoordinate, Material> raycaster = new Raytracer <MyRayPayload, PositionNormalCoordinate, Material>(); raycaster.OnClosestHit += delegate(IRaycastContext context, PositionNormalCoordinate attribute, Material material, ref MyRayPayload payload) { // Move geometry attribute to world space attribute = attribute.Transform(context.FromGeometryToWorld); float3 V = normalize(CameraPosition - attribute.Position); float3 L = (LightPosition - attribute.Position); float d = length(L); L /= d; // normalize direction to light reusing distance to light attribute.Normal = normalize(attribute.Normal); float lambertFactor = max(0, dot(attribute.Normal, L)); // Check ray to light... ShadowRayPayload shadow = new ShadowRayPayload(); shadower.Trace(scene, RayDescription.FromDir(attribute.Position + attribute.Normal * 0.001f, // Move an epsilon away from the surface to avoid self-shadowing L), ref shadow); float3 Intensity = (shadow.Shadowed ? 0.2f : 1.0f) * LightIntensity / (d * d); payload.Color = material.EvalBRDF(attribute, V, L) * Intensity * lambertFactor; }; raycaster.OnMiss += delegate(IRaycastContext context, ref MyRayPayload payload) { payload.Color = float3(0, 0, 0); // Blue, as the sky. }; /// Render all points of the screen for (int px = 0; px < texture.Width; px++) { for (int py = 0; py < texture.Height; py++) { int progress = (px * texture.Height + py); if (progress % 1000 == 0) { Console.Write("\r" + progress * 100 / (float)(texture.Width * texture.Height) + "% "); } RayDescription ray = RayDescription.FromScreen(px + 0.5f, py + 0.5f, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); MyRayPayload coloring = new MyRayPayload(); raycaster.Trace(scene, ray, ref coloring); texture.Write(px, py, float4(coloring.Color, 1)); } } }
public static void RaytracePassDrawArea <T>(int id, int x0, int y0, int xf, int yf, Raytracer <MyRTRayPayload, T, MyMaterial <T> > raycaster, Texture2D texture, float4x4 viewMatrix, float4x4 projectionMatrix, Scene <T, MyMaterial <T> > scene, int step = 1) where T : struct, IVertex <T>, INormalVertex <T>, ICoordinatesVertex <T>, IColorable, ITransformable <T> { for (int px = x0; px < xf; px += step) { for (int py = y0; py < yf; py += step) { RayDescription ray = RayDescription.FromScreen(px + 0.5f, py + 0.5f, texture.Width, texture.Height, inverse(viewMatrix), inverse(projectionMatrix), 0, 1000); MyRTRayPayload coloring = new MyRTRayPayload(); coloring.Bounces = 3; raycaster.Trace(scene, ray, ref coloring); for (int i = 0; i < step; i++) { for (int j = 0; j < step; j++) { texture.Write(Math.Min(px + i, texture.Width - 1), Math.Min(py + j, texture.Height - 1), float4(coloring.Color, 1)); } } } } Console.WriteLine($"Done {id}"); }
public static void RayTrace <T>(Texture2D texture, Scene <T, MyMaterial <T> > scene, Raytracer <MyRTRayPayload, T, MyMaterial <T> > raycaster, float4x4 viewMatrix, float4x4 projectionMatrix, int rendStep = 1, int gridXDiv = 8, int gridYDiv = 8) where T : struct, IVertex <T>, INormalVertex <T>, ICoordinatesVertex <T>, IColorable, ITransformable <T> { var start = new Stopwatch(); start.Start(); var tasks = new List <Task>(); int id = 0, xStep = texture.Width / gridXDiv, yStep = texture.Height / gridYDiv; for (int i = 0; i *yStep < texture.Height; i++) { for (int j = 0; j *xStep < texture.Width; j++) { int threadId = id, x0 = j * xStep, y0 = i * yStep, maxX = Math.Min((j + 1) * xStep, texture.Width), maxY = Math.Min((i + 1) * yStep, texture.Height); tasks.Add(Task.Run(() => RenderUtils.RaytracePassDrawArea(threadId, x0, y0, maxX, maxY, raycaster, texture, viewMatrix, projectionMatrix, scene, rendStep))); id++; } } Task.WaitAll(tasks.ToArray()); start.Stop(); Console.WriteLine($"Elapsed {start.ElapsedMilliseconds} milliseconds"); }
public static void PathTrace <T>(Texture2D texture, Scene <T, MyMaterial <T> > scene, Raytracer <MyPTRayPayload, T, MyMaterial <T> > raycaster, float4x4 viewMatrix, float4x4 projectionMatrix, int maxPass, int rendStep = 1, int gridXDiv = 8, int gridYDiv = 8, int initPass = 0) where T : struct, IVertex <T>, INormalVertex <T>, ICoordinatesVertex <T>, IColorable, ITransformable <T> { var pathTimer = new Stopwatch(); var passTimer = new Stopwatch(); pathTimer.Start(); int id = 0, xStep = texture.Width / gridXDiv, yStep = texture.Height / gridYDiv; int pass = initPass; while (pass < maxPass) { var tasks = new List <Task>(); passTimer.Restart(); for (int i = 0; i *yStep < texture.Height; i++) { for (int j = 0; j *xStep < texture.Width; j++) { int threadId = id, x0 = j * xStep, y0 = i * yStep, maxX = Math.Min((j + 1) * xStep, texture.Width), maxY = Math.Min((i + 1) * yStep, texture.Height); tasks.Add(Task.Run(() => RenderUtils.PathtracePassDrawArea(threadId, x0, y0, maxX, maxY, raycaster, texture, viewMatrix, projectionMatrix, scene, pass, rendStep))); id++; } } Task.WaitAll(tasks.ToArray()); texture.Save("test.rbm"); texture.SaveToBmp("test.bmp"); Console.WriteLine($"Pass {pass} completed in {passTimer.ElapsedMilliseconds / 1000} seconds. {DateTime.Now}"); pass++; } pathTimer.Stop(); Console.WriteLine($"Elapsed {pathTimer.ElapsedMilliseconds / 1000} seconds. {DateTime.Now}"); }