Created
July 24, 2013 10:12
-
-
Save apriori/6069394 to your computer and use it in GitHub Desktop.
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
{-# LANGUAGE FlexibleContexts #-} | |
import Graphics.Rendering.OpenGL.GL.Tensor | |
import Data.Array.Accelerate as A | |
import qualified Data.Array.Repa as R | |
import qualified Data.Array.Accelerate.CUDA as I | |
import Data.List hiding (intersect) | |
import Foreign.C.Types | |
import Foreign.Ptr | |
import Data.Int | |
import Data.Word | |
import qualified Graphics.UI.GLUT as G | |
import Graphics.Rendering.OpenGL.GL.CoordTrans | |
width = 640 | |
height = 480 | |
fov = 45.0 | |
maxdepth = 2 | |
type VectorF = Vertex3 Float | |
type VectorI = Vertex3 Int | |
type Vec a = (a, a, a) | |
type VecF = Vec Float | |
infixl 6 -. | |
infixl 6 +. | |
infixl 7 *. | |
(-.), (+.), (*.) :: (Elt a, IsNum a) => Exp (Vec a) -> Exp (Vec a) -> Exp (Vec a) | |
(-.) = vzipWith (-) | |
(+.) = vzipWith (+) | |
(*.) = vzipWith (*) | |
infixl 6 --. | |
infixl 6 ++. | |
infix 7 //. | |
infixl 7 **. | |
(--.), (++.), (**.) :: (Elt a, IsNum a) => Exp (Vec a) -> Exp a -> Exp (Vec a) | |
(--.) v f = vmap (flip (-) f) v | |
(++.) v f = vmap (f+) v | |
(**.) v f = vmap (f*) v | |
(//.) :: (Elt a, IsNum a, IsFloating a) => Exp (Vec a) -> Exp a -> Exp (Vec a) | |
(//.) v f = vmap (flip (/) f) v | |
cfalse :: Exp Bool | |
cfalse = constant False | |
ctrue :: Exp Bool | |
ctrue = constant True | |
vmap :: (Elt a, Elt b) => (Exp a -> Exp b) -> Exp (Vec a) -> Exp (Vec b) | |
vmap f v = let (x1,y1,z1) = unlift v | |
in | |
lift (f x1, f y1, f z1) | |
vzipWith :: (Elt a, Elt b, Elt c) => (Exp a -> Exp b -> Exp c) -> Exp (Vec a) -> Exp (Vec b) -> Exp (Vec c) | |
vzipWith f v1 v2 | |
= let (x1,y1,z1) = unlift v1 | |
(x2,y2,z2) = unlift v2 | |
in | |
lift (f x1 x2, f y1 y2, f z1 z2) | |
dot :: (Elt a, IsNum a) => Exp (Vec a) -> Exp (Vec a) -> Exp a | |
dot a b = let | |
(x1, y1, z1) = unlift a | |
(x2, y2, z2) = unlift b | |
in | |
x1 * x2 + y1 * y2 + z1 * z2 | |
mag :: (Elt a, IsNum a, A.IsFloating a) => A.Exp (Vec a) -> A.Exp a | |
mag l = sqrt $ dot l l | |
normalized :: (Elt a, A.IsNum a, IsFloating a) => A.Exp (Vec a) -> (A.Exp (Vec a)) | |
normalized l = l //. (mag l) | |
type Ray = (VecF, --start | |
VecF) --dir | |
start :: Exp Ray -> Exp VecF | |
start r = A.fst r | |
dir :: Exp Ray -> Exp VecF | |
dir r = A.snd r | |
type Sphere = (VecF, --center | |
Float, --radius | |
VecF, --scolor | |
Float, --reflection | |
Float) --transparency | |
center :: Exp Sphere -> Exp VecF | |
center s = let (c, _, _, _, _) = unlift s :: (Exp VecF, Exp Float, Exp VecF, Exp Float, Exp Float) | |
in c | |
radius :: Exp Sphere -> Exp Float | |
radius s = let (_, r, _, _, _) = unlift s :: (Exp VecF, Exp Float, Exp VecF, Exp Float, Exp Float) | |
in lift r | |
scolor :: Exp Sphere -> Exp VecF | |
scolor s = let (_, _, c, _, _) = unlift s :: (Exp VecF, Exp Float, Exp VecF, Exp Float, Exp Float) | |
in lift c | |
reflection :: Exp Sphere -> Exp Float | |
reflection s = let (_, _, _, r, _) = unlift s :: (Exp VecF, Exp Float, Exp VecF, Exp Float, Exp Float) | |
in lift r | |
transparency :: Exp Sphere -> Exp Float | |
transparency s = let (_, _, _, _, t) = unlift s :: (Exp VecF, Exp Float, Exp VecF, Exp Float, Exp Float) | |
in lift t | |
type Light = (VecF, --position | |
VecF) --color | |
position :: Exp Light -> Exp VecF | |
position l = A.fst l | |
color :: Exp Light -> Exp VecF | |
color l = A.snd l | |
type Scene = (Vector Sphere, Vector Light) | |
objects :: Scene -> Vector Sphere | |
objects (spheres, lights) = spheres | |
lights :: Scene -> Vector Light | |
lights (spheres, lights) = lights | |
intersect :: Exp Sphere -> Exp Ray -> Exp Bool | |
intersect se re = | |
let | |
rs = start re | |
cs = center se | |
sr = radius se | |
dr = dir re | |
v = cs -. rs | |
a = dot v dr | |
b2 = dot v v - a * a | |
r2 = sr * sr | |
in | |
(a <* 0 ||* b2 >* r2) ? (constant False, constant True) | |
normalizeSphereSurface :: Exp Sphere -> Exp VecF -> Exp VecF | |
normalizeSphereSurface s v = normalized (v -. (center s)) | |
intersectDist :: Exp Ray -> Exp Sphere -> Exp (Bool, Sphere, Float) | |
intersectDist r s = | |
let | |
v = (center s) -. (start r) | |
a = dot v (dir r) | |
b2 = dot v v - a * a | |
r2 = (radius s) * (radius s) | |
c = sqrt(r2 - b2) | |
near = a - c | |
far = a + c | |
distance = (near <* 0) ? (far, near) | |
(x, y, z) = unlift v :: (Exp Float, Exp Float, Exp Float) | |
in | |
(a <* 0 ||* b2 >* r2) ? ( | |
lift $ (constant False, s, constant (-1.0)), | |
lift $ (constant True, s, distance) | |
) | |
predComp :: Exp (Bool, Sphere, Float) -> Exp (Bool, Sphere, Float) -> Exp (Bool, Sphere, Float) | |
predComp a b = (b1 ==* cfalse &&* b2 ==* cfalse) ? (lift (b1, s1, d1), | |
(b1 ==* cfalse &&* b2 ==* ctrue) ? (lift (b2, s2, d2), | |
(b1 ==* ctrue &&* b2 ==* cfalse) ? (lift (b1, s1, d1), | |
(b1 ==* ctrue &&* b2 ==* ctrue &&* d1 A.<* d2) ? (lift (b1, s1, d1), lift (b2, s2, d2))))) | |
where | |
(b1, s1, d1) = A.unlift a :: (Exp Bool, Exp Sphere, Exp Float) | |
(b2, s2, d2) = A.unlift b :: (Exp Bool, Exp Sphere, Exp Float) | |
minInterSect :: Scene -> Exp Ray -> Acc (Scalar (Bool, Sphere, Float)) | |
minInterSect s r = | |
let | |
objs = objects s | |
usedObjs = use objs | |
interSects = A.map (intersectDist r) usedObjs | |
dummySphere = ((0.0, 0, 0), | |
0.0, | |
(0.0, 0.0, 0.0), | |
0.0, | |
0.0) | |
dummyTuple = constant (False, dummySphere, -1.0) | |
in | |
--A.foldAll predComp dummyTuple interSects | |
unit dummyTuple | |
isblocked :: (Shape shl) => Array shl Sphere -> Exp Ray -> Acc (Scalar Bool) | |
isblocked a r = let | |
intersecttest a b = intersect b a | |
intersects = A.map (intersecttest r) (use a) | |
in | |
A.or intersects | |
colorforlight :: Scene -> Exp Sphere -> Exp VecF -> Exp VecF -> Exp Light -> Exp VecF | |
colorforlight s sph pip norm l = | |
let | |
lightpos = position l | |
lightdirection = normalized (lightpos -. pip) | |
r = lift $ (pip, lightdirection) | |
blocked = the $ isblocked (objects s) r | |
clr = ((color l) **. (A.max 0.0 (dot norm lightdirection))) | |
*. (scolor sph) **. (1.0 - reflection sph) | |
in | |
blocked ? (constant (0.0, 0.0, 0.0), clr) | |
combinedcolor :: Scene -> Exp Sphere -> Exp VecF -> Exp VecF -> Acc (Scalar VecF) | |
combinedcolor s sph pip norm = A.foldAll (+.) (constant (0.0, 0.0, 0.0)) (A.map (colorforlight s sph pip norm) (use $ lights s)) | |
trace :: Exp Ray -> Scene -> Int -> Exp VecF | |
trace r s d = let | |
(hasIntersect, sp, di) = unlift $ (minInterSect s r) A.!! 0 :: (Exp Bool, Exp Sphere, Exp Float) | |
in | |
(hasIntersect) ? | |
( | |
let | |
pointofhit = (dir r) **. (lift di) +. start r | |
normal_unrefl = normalizeSphereSurface (lift sp) pointofhit | |
dotnormalray_unrefl = dot normal_unrefl (dir r) | |
isinside = (dotnormalray_unrefl >* 0) ? (ctrue, cfalse) | |
dotnormalray = (dotnormalray_unrefl >* 0) ? (-dotnormalray_unrefl, dotnormalray_unrefl) | |
normal = (dotnormalray_unrefl >* 0) ? (normal_unrefl **. (-1.0), normal_unrefl) | |
reflectionratio = reflection (lift sp) | |
transparencyratio = transparency (lift sp) | |
facing = A.max 0.0 (-dotnormalray) | |
fresneleffect = reflectionratio + (1.0 - reflectionratio) * ((1.0 -facing) ^^ 5) | |
colorsperlight = A.map (colorforlight s (lift sp) pointofhit (normal **. 1.0)) (use $ lights s) | |
accumulatedcolor = I.run $ A.foldAll (+.) (constant (0.0, 0.0, 0.0)) colorsperlight | |
--clr = combinedcolor s (lift sp) pointofhit (normal **. 1.0) | |
in | |
--reflection | |
--if (d < maxdepth) then | |
-- let reflexclr = if (reflectionratio > 0) then | |
-- let reflectiondirection = (dir r) -. (normal *. 2.0 *. dotnormalray) in | |
-- (trace (Ray pointofhit reflectiondirection) s (d + 1)) *. fresneleffect | |
-- else | |
-- fromListStatic [0.0, 0.0, 0.0] | |
-- in | |
--let refractclr = if transparencyratio > 0.0 then | |
-- let ce = (dot (dir r) normal) * (-1.0) in | |
-- let iorconst = 1.5 in | |
-- let ior = if isinside then 1.0 / iorconst else iorconst in | |
-- let eta = 1.0 / ior in | |
-- let gf = (dir r) +. (normal *.ce) *. eta in | |
-- let sin_t1_2 = 1.0 - ce * ce in | |
-- let sin_t2_2 = sin_t1_2 * (eta * eta) in | |
-- if sin_t2_2 < 1.0 then | |
-- let gc = normal *. (sqrt 1 - sin_t2_2) in | |
-- let refraction_direction = gf -. gc in | |
-- let refraction = trace (Ray pointofhit refraction_direction) s (d + 1) in | |
-- refraction *. (1.0 - fresneleffect) *. (transparency sp) | |
-- else | |
-- fromListStatic [0.0, 0.0, 0.0] | |
-- else | |
-- fromListStatic [0.0, 0.0, 0.0] | |
-- in | |
-- let scaleMax = (fromIntegral (maxdepth - d - 1)) in | |
-- let scaleMin = fromIntegral (maxdepth - 1) in | |
-- let scale = scaleMax / scaleMin in | |
--clr +. (reflexclr *. scale) | |
-- clr +. reflexclr | |
--else | |
-- fromListStatic [0.0, 0.0, 0.0] | |
-- clr | |
--lift (fresneleffect, fresneleffect, fresneleffect), | |
accumulatedcolor, | |
constant (0.0, 0.0, 0.0) | |
) | |
updatePixel :: (Int, Int) -> VecF -> IO () | |
updatePixel p@(x, y) c@(r, g, b) = do | |
G.renderPrimitive G.Points $ do | |
G.color $ G.Color3 (CFloat r) (CFloat g) (CFloat b) | |
G.vertex $ Vertex3 (CFloat (Prelude.fromIntegral x)) (CFloat (Prelude.fromIntegral y)) 0 | |
calcPixel :: Scene -> Exp VecF -> Exp (Int, Int) -> Exp ((Int, Int), VecF) | |
calcPixel s eye idx = let | |
(x, y) = unlift idx :: (Exp Int, Exp Int) | |
h = constant $ (tan (fov / 360.0 * 2.0 * pi / 2.0)) * 2.0 | |
ww = A.fromIntegral $ constant width | |
hh = A.fromIntegral $ constant height | |
w = h * ww / hh | |
rx = ((A.fromIntegral x) - ww/2.0) /ww * w | |
ry = (hh / 2.0 - (A.fromIntegral y)) / hh * h | |
dir = normalized $ lift (rx, ry, constant (-1.0)) | |
in | |
lift (idx, trace (lift (eye, dir)) s 0) :: Exp ((Int, Int), VecF) | |
updateAllPixels :: Array DIM2 ((Int, Int), VecF) -> Int -> Int -> IO () | |
updateAllPixels p i j | |
| i >= width = updateAllPixels p 0 (j+1) | |
| j >= height = return () | |
| otherwise = | |
do | |
let (idx, color) = p `indexArray` (Z :. i :. j) | |
updatePixel idx color | |
--putStrLn $ show $ (x, y) | |
--putStrLn $ show $ (r, g, b) | |
updateAllPixels p (i+1) (j) | |
render :: Scene -> IO () | |
render s = do | |
let | |
eye = constant (0.0, 0.0, 0.0) | |
indices = A.fromList (A.Z A.:. width A.:. height) [ (x, y) | x <- [0..width-1], y <- [0..height-1]] :: A.Array A.DIM2 (Int, Int) | |
pixels = I.run $ A.map (calcPixel s eye) (use indices) | |
putStrLn "calculation done" | |
updateAllPixels pixels 0 0 | |
--main :: IO () | |
--main = do | |
-- let | |
-- r = ((0.0, 0.0, -20.0), (0.0, 0.0, 1.0)) :: Ray | |
-- s = ((0.0, 0.0, 0.0), 5.0, (1.0, 0.0, 0.0), 1.0, 0.2) :: Sphere | |
-- scene = Scene (fromList (Z :. 4) [ | |
-- ((0.0, -10002.0, -20.0), | |
-- 10000.0, | |
-- (0.8, 0.8, 0.8), | |
-- 0.0, | |
-- 0.0), | |
-- ((0.0, 2.0, -20.0), | |
-- 4.0, | |
-- (0.8, 0.5, 0.5), | |
-- 0.5, | |
-- 0.0), | |
-- ((5.0, 0.0, -15.0), | |
-- 2.0, | |
-- (0.3, 0.8, 0.8), | |
-- 0.2, | |
-- 0.0), | |
-- ((-5.0, 0.0, -15.0), | |
-- 2.0, | |
-- (0.3, 0.5, 0.8), | |
-- 0.2, | |
-- 0.0), | |
-- ((-2.0, -1.0, -10.0), | |
-- 1.0, | |
-- (0.1, 0.1, 0.1), | |
-- 0.1, | |
-- 0.8) | |
-- ]) | |
-- (fromList (Z :. 1) [ | |
-- ((-10.0, 20.0, 30.0), | |
-- (2.0, 2.0, 2.0)) | |
-- ]) | |
-- (hasIntersect, sp, di) = (I.run (minInterSect scene (constant r))) `indexArray` Z | |
-- putStrLn $ show hasIntersect | |
-- putStrLn $ show sp | |
-- putStrLn $ show di | |
main :: IO () | |
main = do | |
(progname, _) <- G.getArgsAndInitialize | |
w <- G.createWindow "Haskell raytracer" | |
G.windowSize G.$= (G.Size (CInt (Prelude.fromIntegral width)) (CInt (Prelude.fromIntegral height))) | |
let scene = ( (fromList (Z :. 4) [ | |
((0.0, -10002.0, -20.0), | |
10000.0, | |
(0.8, 0.8, 0.8), | |
0.0, | |
0.0), | |
((0.0, 2.0, -20.0), | |
4.0, | |
(0.8, 0.5, 0.5), | |
0.5, | |
0.0), | |
((5.0, 0.0, -15.0), | |
2.0, | |
(0.3, 0.8, 0.8), | |
0.2, | |
0.0), | |
((-5.0, 0.0, -15.0), | |
2.0, | |
(0.3, 0.5, 0.8), | |
0.2, | |
0.0), | |
((-2.0, -1.0, -10.0), | |
1.0, | |
(0.1, 0.1, 0.1), | |
0.1, | |
0.8) | |
]), | |
(fromList (Z :. 1) [ | |
((-10.0, 20.0, 30.0), | |
(2.0, 2.0, 2.0)) | |
]) | |
) | |
G.reshapeCallback G.$= Just Main.reshape | |
G.displayCallback G.$= display scene | |
G.mainLoop | |
reshape :: Size -> IO () | |
reshape size@(Size w h) = do | |
G.viewport G.$= (Position 0 0, size) | |
G.matrixMode G.$= Projection | |
G.loadIdentity | |
ortho 0.0 (Prelude.fromIntegral w) 0.0 (Prelude.fromIntegral h) (-1.0) 1.0 | |
G.matrixMode G.$= Modelview 0 | |
display :: Scene -> IO () | |
display s = do | |
G.clear [G.ColorBuffer] | |
render s | |
G.swapBuffers | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment