Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace Tracer
- module Camera =
- open System
- open Point
- open Vector
- open Interfaces
- open System.Drawing
- open System.Windows.Forms
- open sampling
- open System.Threading;
- open System.Collections.Concurrent
- open System.Threading.Tasks
- open System.Drawing.Imaging
- open Microsoft.FSharp.NativeInterop
- type point = Point.Point
- type vector = Vector.Vector
- type sampler = ISampler
- //credits to
- type LockContext(bitmap : Bitmap) =
- let data = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat)
- let getPixelAddress x y =
- match data.PixelFormat with
- | PixelFormat.Format32bppArgb -> NativePtr.add<byte> (NativePtr.ofNativeInt (data.Scan0)) ((y * (data.Stride)) + (x*4))
- | _ -> failwith "PixelFormat not supported"
- let setPixel x y (color : Color) =
- let address = getPixelAddress x y
- match data.PixelFormat with
- | PixelFormat.Format32bppArgb -> NativePtr.set address 3 color.A
- NativePtr.set address 2 color.R
- NativePtr.set address 1 color.G
- NativePtr.write address color.B
- | _ -> failwith "PixelFormat not supported"
- member this.SetPixeL(x,y, color : Color) = setPixel x y color
- let rec getClosestHit (hits:(float * vector * IMaterial * point) option list) (index:int) (bestIndex:int) (leastT:float) =
- match hits with
- | hit :: rest -> if hit.IsSome
- then let (t, _, _, _) = hit.Value
- if t < leastT
- then getClosestHit rest (index + 1) index t
- else getClosestHit rest (index + 1) bestIndex leastT
- else getClosestHit rest (index + 1) bestIndex leastT
- | [] -> bestIndex
- let rec findHit (o:point) (dir:vector) (shapes:IShape list) (bestHit:(float * vector * IMaterial * point) option) (minDist:float) =
- match shapes with
- | s :: rest -> match s.hit o dir with
- | Some(t, n, mat, hp) -> if t < minDist
- then findHit o dir rest (Some(t, n, mat, hp)) t
- else findHit o dir rest bestHit minDist
- | None -> findHit o dir rest bestHit minDist
- | [] -> bestHit
- let traceRay (o:point) (dir:vector) (shapes:IShape list) =
- findHit o dir shapes None Double.PositiveInfinity
- type Scene(shapes, lights, ambientLight, maxDepth) =
- interface IScene with
- member this.shapes = shapes
- member this.lights = lights
- member this.ambientLight = ambientLight
- member this.maxDepth = maxDepth
- member this.traceRay o dir = traceRay o dir shapes
- let mkScene s l a m = new Scene(s, l, a, m) :> IScene
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // rendering //
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- let renderScene (scene:IScene) (camera:ICamera) : Bitmap =
- let threadBag = new ConcurrentBag<int*int*Color>()
- let resX = camera.getResX
- let resY = camera.getResY
- let bmp = new Bitmap(resX, resY)
- let stopWatch = System.Diagnostics.Stopwatch.StartNew()
- let mutable progress = 0
- let context = new LockContext(bmp)
- Parallel.For(0,resY-1, fun j ->
- do
- for i in [0 .. resX-1]
- do
- let mutable accum = Colour.mkColour 0.0 0.0 0.0
- for ii in [1 .. camera.vpSampler.length]
- do
- let (dir,position) = camera.calcDir i j
- let hit = traceRay position dir scene.shapes
- if hit.IsSome
- then
- let t, n, mat, p = hit.Value
- accum <- accum + (mat.shade p dir n scene 0)
- context.SetPixeL(i,j, Colour.toColor (accum/(float camera.vpSampler.length)))) |> ignore
- bmp
- let renderToFile (scene:IScene) (camera:ICamera) (path:string) =
- (renderScene scene camera).Save(path)
- let renderToScreen (scene:IScene) (camera:ICamera) : unit =
- let bmp = renderScene scene camera
- let result = new Form(MaximizeBox = true, Text = "Rendered Image")
- let graphics = result.CreateGraphics()
- graphics.DrawImage(bmp, 0, 0)
- do Application.Run result
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // types and inheritance //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- type PinholeCamera(position, lookat, up, zoom, vpWidth, vpHeight, pixelWidth, pixelHeight, vpSampler) = //Parametre
- let position = position
- let lookat = lookat
- let up = up
- let zoom = zoom
- let vpWidth = vpWidth
- let vpHeight = vpHeight
- let resX = pixelWidth
- let resY = pixelHeight
- let vpSampler = vpSampler
- member this.w = normalize (Point.distance lookat position)
- member this.v = normalize (crossProduct up this.w)
- member this.u = crossProduct this.w this.v
- member this.calcPxPy i j (x,y) =
- ((vpWidth / float resX) * (float i - (float resX / 2.0) + x)), ((vpHeight / float resY) * (float j - (float resY / 2.0) + y))
- interface ICamera with
- member this.vpSampler = vpSampler
- member this.getResX = resX
- member this.getResY = resY
- member this.calcDir i j =
- let (x,y,_) = (vpSampler: ISampler).getNext Thread.CurrentThread.ManagedThreadId
- let (px,py) = this.calcPxPy i j (x,y)
- Vector.normalize (Vector.substract (Vector.add ((Vector.multScalar px this.v),(Vector.multScalar py this.u)),(Vector.multScalar zoom this.w))), position // had a weird issue with not being able to reach infix operators
- type ThinLensCamera(position,lookat,up,zoom,vpWidth,vpHeight,pixelWidth,pixelHeight,lensRadius,fpDistance,vpSampler,lenseSampler) =
- inherit PinholeCamera(position, lookat, up, zoom, vpWidth, vpHeight, pixelWidth, pixelHeight, vpSampler)
- let lensRadius = lensRadius
- let fpDistance = fpDistance
- let lenseSampler = lenseSampler
- interface ICamera with
- override this.calcDir i j =
- let (x,y,_) = (vpSampler: ISampler).getNext Thread.CurrentThread.ManagedThreadId
- let (qx,qy) = this.calcPxPy i j (x,y)
- let (px,py) = (fpDistance*qx/zoom,fpDistance*qy/zoom)
- let (sx, sy,_) = (lenseSampler : ISampler).getNext Thread.CurrentThread.ManagedThreadId
- let (lx,ly) = (lensRadius*sx,lensRadius*sy)
- (Vector.normalize (((px-lx)*this.u) + ((py-ly)*this.v) - (fpDistance*this.w))),(position + (lx*this.u) + (ly*this.v)) // should normalize vector
- let mkPinholeCamera position lookat up zoom vpWidth vpHeight pixelWidth pixelHeight vpSampler = new PinholeCamera(position,lookat,up,zoom,vpWidth,vpHeight,pixelWidth,pixelHeight,vpSampler) :> ICamera
- let mkThinLensCamera position lookat up zoom vpWidth vpHeight pixelWidth pixelHeight lensRadius fpDistance vpSampler (lensSampler:ISampler) = new ThinLensCamera(position,lookat,up,zoom,vpWidth,vpHeight,pixelWidth,pixelHeight,lensRadius,fpDistance,vpSampler,lensSampler) :> ICamera
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement