Created
February 20, 2012 13:43
-
-
Save abrkn/1869253 to your computer and use it in GitHub Desktop.
Ray tracer?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal void RenderParallel(Scene scene, CancellationToken cancellationToken) | |
{ | |
int[] rgb = new int[screenWidth * screenHeight]; | |
var pixelsQuery = | |
from y in | |
Enumerable.Range(0, screenHeight).AsParallel() | |
.WithCancellation(cancellationToken) | |
let recenterY = -(y - (screenHeight / 2.0)) / (2.0 * screenHeight) | |
select from x in Enumerable.Range(0, screenWidth) | |
let recenterX = (x - (screenWidth / 2.0)) / (2.0 * screenWidth) | |
let point = | |
Vector.Norm(Vector.Plus(scene.Camera.Forward, | |
Vector.Plus(Vector.Times(recenterX, scene.Camera.Right), | |
Vector.Times(recenterY, scene.Camera.Up)))) | |
let ray = new Ray() { Start = scene.Camera.Pos, Dir = point } | |
let computeTraceRay = (Func<Func<TraceRayArgs, Color>, Func<TraceRayArgs, Color>>) | |
(f => traceRayArgs => | |
(from isect in | |
from thing in traceRayArgs.Scene.Things | |
select thing.Intersect(traceRayArgs.Ray) | |
where isect != null | |
orderby isect.Dist | |
let d = isect.Ray.Dir | |
let pos = Vector.Plus(Vector.Times(isect.Dist, isect.Ray.Dir), isect.Ray.Start) | |
let normal = isect.Thing.Normal(pos) | |
let reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal)) | |
let naturalColors = | |
from light in traceRayArgs.Scene.Lights | |
let ldis = Vector.Minus(light.Pos, pos) | |
let livec = Vector.Norm(ldis) | |
let testRay = new Ray() { Start = pos, Dir = livec } | |
let testIsects = from inter in | |
from thing in traceRayArgs.Scene.Things | |
select thing.Intersect(testRay) | |
where inter != null | |
orderby inter.Dist | |
select inter | |
let testIsect = testIsects.FirstOrDefault() | |
let neatIsect = testIsect == null ? 0 : testIsect.Dist | |
let isInShadow = !((neatIsect > Vector.Mag(ldis)) || (neatIsect == 0)) | |
where !isInShadow | |
let illum = Vector.Dot(livec, normal) | |
let lcolor = illum > 0 ? Color.Times(illum, light.Color) : Color.Make(0, 0, 0) | |
let specular = Vector.Dot(livec, Vector.Norm(reflectDir)) | |
let scolor = specular > 0 | |
? Color.Times(Math.Pow(specular, isect.Thing.Surface.Roughness), | |
light.Color) | |
: Color.Make(0, 0, 0) | |
select Color.Plus(Color.Times(isect.Thing.Surface.Diffuse(pos), lcolor), | |
Color.Times(isect.Thing.Surface.Specular(pos), scolor)) | |
let reflectPos = Vector.Plus(pos, Vector.Times(.001, reflectDir)) | |
let reflectColor = traceRayArgs.Depth >= MaxDepth | |
? Color.Make(.5, .5, .5) | |
: Color.Times(isect.Thing.Surface.Reflect(reflectPos), | |
f(new TraceRayArgs(new Ray() | |
{ | |
Start = reflectPos, | |
Dir = reflectDir | |
}, | |
traceRayArgs.Scene, | |
traceRayArgs.Depth + 1))) | |
select naturalColors.Aggregate(reflectColor, | |
(color, natColor) => Color.Plus(color, natColor)) | |
).DefaultIfEmpty(Color.Background).First()) | |
let traceRay = Y(computeTraceRay) | |
select new { X = x, Y = y, Color = traceRay(new TraceRayArgs(ray, scene, 0)) }; | |
int rowsProcessed = 0; | |
pixelsQuery.ForAll(row => | |
{ | |
foreach (var pixel in row) | |
{ | |
rgb[pixel.X + (pixel.Y * screenWidth)] = pixel.Color.ToInt32(); | |
} | |
int processed = Interlocked.Increment(ref rowsProcessed); | |
if (processed % rowsPerUpdate == 0 || | |
processed >= screenHeight) updateImageHandler(rgb); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment