summaryrefslogtreecommitdiff
path: root/Matrix.hs
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-04-22 03:13:44 -0400
committerJoe Crayne <joe@jerkface.net>2019-04-22 03:36:23 -0400
commitac89ee199abfe893b03cdbb89a426cd0594e06c9 (patch)
treec3542c880eb610e9a2d5d863ec9ba518a32a0b02 /Matrix.hs
parent36bd8e7133eca5d4e04252c555ee0cc2cc78106e (diff)
objdemo: pass view matrix from haskell.
Diffstat (limited to 'Matrix.hs')
-rw-r--r--Matrix.hs230
1 files changed, 230 insertions, 0 deletions
diff --git a/Matrix.hs b/Matrix.hs
new file mode 100644
index 0000000..b47e223
--- /dev/null
+++ b/Matrix.hs
@@ -0,0 +1,230 @@
1{-# LANGUAGE BangPatterns, FlexibleContexts #-}
2module Matrix where
3
4import Numeric.LinearAlgebra
5import Foreign.Storable
6import Data.Vector.Generic as V (snoc,init)
7import Prelude hiding ((<>))
8
9rotMatrixX :: (Storable a, Floating a) => a -> Matrix a
10rotMatrixX a = (4><4)
11 [ 1 , 0 , 0 , 0
12 , 0 , c , -s , 0
13 , 0 , s , c , 0
14 , 0 , 0 , 0 , 1 ] where (c,s) = (cos a, sin a)
15
16
17rotMatrixY :: (Storable a, Floating a) => a -> Matrix a
18rotMatrixY a = (4><4)
19 [ c , 0 , s , 0
20 , 0 , 1 , 0 , 0
21 , -s , 0 , c , 0
22 , 0 , 0 , 0 , 1 ] where (c,s) = (cos a, sin a)
23
24rotMatrixZ :: (Storable a, Floating a) => a -> Matrix a
25rotMatrixZ a = (4><4)
26 [ c , -s , 0 , 0
27 , s , c , 0 , 0
28 , 0 , 0 , 1 , 0
29 , 0 , 0 , 0 , 1 ] where (c,s) = (cos a, sin a)
30
31
32-- | Equivalent to
33--
34-- > translateBefore3to4 v m = translation v <> homoMatrix m
35--
36-- where translation and homoMatrix are taken as the usual transformations into
37-- the 4-dimensional homogeneous coordinate space.
38translateBefore3to4 :: Numeric t =>
39 Vector t -- 3 vector (translation)
40 -> Matrix t -- 3><3 matrix (projection)
41 -> Matrix t -- 4><4 matrix (projection)
42translateBefore3to4 v p3 = fromRows $ rs ++ [u]
43 where
44 !u = snoc (v <# p3) 1
45 rs = map (`snoc` 0) $ toRows p3
46{-# SPECIALIZE translateBefore3to4 :: Vector R -> Matrix R -> Matrix R #-}
47
48{-
49lookat pos target up = translateBefore3to4 (negate pos) r
50 where
51 backward = normalize $ pos - target
52 rightward = normalize $ up `cross` backward
53 upward = backward `cross` rightward
54 r = fromColumns [rightward,upward,backward]
55
56 -- Rebind 'normalize' in order to support Float which has no Field
57 -- instance.
58 normalize :: (Linear t c, Fractional t, Normed (c t)) => c t -> c t
59 normalize v = scale (1 / realToFrac (norm_2 v)) v
60-}
61
62-- | Camera transformation matrix (4x4).
63lookat :: (Numeric t, Num (Vector t), Fractional t, Normed (Vector t)) =>
64 Vector t -- ^ Camera position 3-vector.
65 -> Vector t -- ^ Target position 3-vector.
66 -> Vector t -- ^ Upward direction 3-vector.
67 -> Matrix t
68lookat pos target up = fromRows
69 [ snoc rightward (- dot rightward pos)
70 , snoc upward (- dot upward pos)
71 , snoc backward (- dot backward pos)
72 , snoc (fromList[0,0,0]) 1
73 ]
74 where
75 backward = normalize $ pos - target
76 rightward = normalize $ up `cross` backward
77 upward = backward `cross` rightward
78
79 -- Rebind 'normalize' in order to support Float which has no Field
80 -- instance.
81 normalize :: (Linear t c, Fractional t, Normed (c t)) => c t -> c t
82 normalize v = scale (1 / realToFrac (norm_2 v)) v
83
84{-# SPECIALIZE lookat :: Vector R -> Vector R -> Vector R -> Matrix R #-}
85
86
87
88
89
90-- lookat pos target up <> rot t
91-- == lookat ((((pos - target) <# rot (-t))) + target)
92-- target
93--
94-- | Perspective transformation 4x4 matrix.
95perspective :: (Storable a, Floating a) =>
96 a -- ^ Near plane clipping distance (always positive).
97 -> a -- ^ Far plane clipping distance (always positive).
98 -> a -- ^ Field of view of the y axis, in radians.
99 -> a -- ^ Aspect ratio, i.e. screen's width\/height.
100 -> Matrix a
101perspective n f fovy aspect = (4><4)
102 [ (2*n/(r-l)) , 0 , 0 , 0
103 , 0 , (2*n/(t-b)) , 0 , 0
104 , (-(r+l)/(r-l)) , ((t+b)/(t-b)) , (-(f+n)/(f-n)) , (-1)
105 , 0 , 0 , (-2*f*n/(f-n)) , 0 ]
106 where
107 t = n*tan(fovy/2)
108 b = -t
109 r = aspect*t
110 l = -r
111
112
113
114-- | Build a look at view matrix
115{-
116lookat2
117 :: (Epsilon a, Floating a)
118 => V3 a -- ^ Eye
119 -> V3 a -- ^ Center
120 -> V3 a -- ^ Up
121 -> M44 a
122-}
123lookat2 :: (Normed (Vector a), Field a, Num (Vector a)) =>
124 Vector a -> Vector a -> Vector a -> Matrix a
125lookat2 eye center up = fromColumns
126 [ snoc xa xd
127 , snoc ya yd
128 , snoc (-za) zd
129 , fromList [ 0 , 0 , 0 , 1 ] ]
130 where za = normalize $ center - eye
131 xa = normalize $ cross za up
132 ya = cross xa za
133 xd = -dot xa eye
134 yd = -dot ya eye
135 zd = dot za eye
136
137{-
138
139-- | Build a look at view matrix
140lookAt
141 :: (Epsilon a, Floating a)
142 => V3 a -- ^ Eye
143 -> V3 a -- ^ Center
144 -> V3 a -- ^ Up
145 -> M44 a
146lookAt eye center up =
147 V4 (V4 (xa^._x) (xa^._y) (xa^._z) xd)
148 (V4 (ya^._x) (ya^._y) (ya^._z) yd)
149 (V4 (-za^._x) (-za^._y) (-za^._z) zd)
150 (V4 0 0 0 1)
151 where za = normalize $ center - eye
152 xa = normalize $ cross za up
153 ya = cross xa za
154 xd = -dot xa eye
155 yd = -dot ya eye
156 zd = dot za eye
157
158-- | Build a matrix for a symmetric perspective-view frustum
159perspective
160 :: Floating a
161 => a -- ^ FOV (y direction, in radians)
162 -> a -- ^ Aspect ratio
163 -> a -- ^ Near plane
164 -> a -- ^ Far plane
165 -> M44 a
166perspective fovy aspect near far =
167 V4 (V4 x 0 0 0)
168 (V4 0 y 0 0)
169 (V4 0 0 z w)
170 (V4 0 0 (-1) 0)
171 where tanHalfFovy = tan $ fovy / 2
172 x = 1 / (aspect * tanHalfFovy)
173 y = 1 / tanHalfFovy
174 fpn = far + near
175 fmn = far - near
176 oon = 0.5/near
177 oof = 0.5/far
178 -- z = 1 / (near/fpn - far/fpn) -- would be better by .5 bits
179 z = -fpn/fmn
180 w = 1/(oof-oon) -- 13 bits error reduced to 0.17
181 -- w = -(2 * far * near) / fmn
182
183
184-- | Perspective transformation matrix in row major order.
185perspective :: Float -- ^ Near plane clipping distance (always positive).
186 -> Float -- ^ Far plane clipping distance (always positive).
187 -> Float -- ^ Field of view of the y axis, in radians.
188 -> Float -- ^ Aspect ratio, i.e. screen's width\/height.
189 -> Mat4
190perspective n f fovy aspect = transpose $
191 Mat4 (Vec4 (2*n/(r-l)) 0 (-(r+l)/(r-l)) 0)
192 (Vec4 0 (2*n/(t-b)) ((t+b)/(t-b)) 0)
193 (Vec4 0 0 (-(f+n)/(f-n)) (-2*f*n/(f-n)))
194 (Vec4 0 0 (-1) 0)
195 where
196 t = n*tan(fovy/2)
197 b = -t
198 r = aspect*t
199 l = -r
200
201-}
202
203lookAtRotate :: (Normed (Vector t), Num (Vector t), Numeric t,
204 Floating t) =>
205 Vector t -> Vector t -> Vector t -> t -> Matrix t
206lookAtRotate pos target up t = lookat pos target up <> m
207 where
208 m = rotMatrixX t {- <> rotMatrixZ t -}
209
210rotateLookAt :: (Normed (Vector t), Floating t, Num (Vector t),
211 Numeric t) =>
212 Vector t -> Vector t -> Vector t -> t -> Matrix t
213rotateLookAt pos target up t = lookat pos' target up'
214 where
215 m = rotMatrixX (-t)
216 pos' = V.init $ (m #> snoc pos 0)
217 up' = V.init (m #> snoc up 0)
218
219
220{-
221void UniformMatrix{234}{fd}v( int location, sizei count, boolean transpose, const float *value );
222void UniformMatrix{2x3,3x2,2x4,4x2,3x4,4x3}{fd}v( int location, sizei count, boolean transpose, const float *value );
223
224The UniformMatrix{234}fv and UniformMatrix{234}dv commands will load count 2 ×
2252, 3 × 3, or 4 × 4 matrices (corresponding to 2, 3, or 4 in the command name)
226of single- or double-precision floating-point values, respectively, into a
227uniform defined as a matrix or an array of matrices. If transpose is FALSE ,
228the matrix is specified in column major order, otherwise in row major order.
229
230-}