2009-02-13 10 views
7

Recientemente me encontré con this raytracer in LINQ. ¿Me pregunto si alguien puede superar eso?¿Cuál es la declaración LINQ más impresionante que ha encontrado?

var pixelsQuery = 
from y in Enumerable.Range(0, screenHeight) 
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)) }; 

foreach (var row in pixelsQuery) 
    foreach (var pixel in row) 
     setPixel(pixel.X, pixel.Y, pixel.Color.ToDrawingColor()); 

Respuesta

6

Dudo que haya algo en la parte superior del raytracer. Soy muy aficionado a my Mandelbrot expression sin embargo:

from row in Enumerable.Range(0, ImageHeight) 
from col in Enumerable.Range(0, ImageWidth) 
// Work out the initial complex value from the row and column 
let c = new Complex((col * SampleWidth)/ImageWidth + OffsetX, 
        (row * SampleHeight)/ImageHeight + OffsetY) 
// Work out the number of iterations 
select Generate(c, x => x * x + c).TakeWhile(x => x.SquareLength < 4) 
            .Take(MaxIterations) 
            .Count() into count 
// Map that to an appropriate byte value 
select (byte)(count == MaxIterations ? 0 : (count % 255) + 1); 
2

me llaman loco, pero yo soy un gran fan de la legibilidad - por lo que tienden a tener simplemente una secuencia de expresiones individual de aspecto inocente que luego combino. Por supuesto, depende de cómo definas LINQ: si te refieres a sintaxis de consulta en C#, entonces no tiendo a ir por la borda ... pero si te refieres a meta-programación (es decir código C# que crea una expresión LINQ) , tengo algunos buenos ejemplos:

5

Mads Torgersen demonstrates cómo escribir una expresión lambda recursivo auto-contenido en LINQ para calcular (por ejemplo) un factorial:

i => new Func<Func<int,int>,Func<int,int>>(fac => x => x == 0 ? 1 : x * fac(x 
- 1))(new SelfApplicable<Func<Func<Func<int,int>,Func<int,int>>,Func<int,int> 
>>(y => f => x => f(y(y)(f))(x))(y => f => x => f(y(y)(f))(x))(fac => x => x 
== 0 ? 1 : x * fac(x - 1)))(i) 

Mads Notas:

que aun no puede encontrar la manera de romper la línea de modo que se acerca legible, por lo que no tienen.

+0

Fascinante (la entrada del blog, es decir, la lambda en sí misma es agonizante) ... –

Cuestiones relacionadas