summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-06-03 19:16:56 -0400
committerJoe Crayne <joe@jerkface.net>2019-06-03 19:16:56 -0400
commitf13eedc6482098581c359518e5db1dc7ec572eaf (patch)
treed5bce3bf46c367adc902e13e3d0eb9dc2e44357b
parent5ef4e1f8f206bb6b1bfe94b421d8b72b912af477 (diff)
Factor Camera module out of MeshSketch.
-rw-r--r--Camera.hs79
-rw-r--r--MeshSketch.hs48
-rw-r--r--lambda-gtk.cabal2
3 files changed, 81 insertions, 48 deletions
diff --git a/Camera.hs b/Camera.hs
new file mode 100644
index 0000000..6bf4dd8
--- /dev/null
+++ b/Camera.hs
@@ -0,0 +1,79 @@
1module Camera where
2
3import qualified Data.Vector.Generic as G
4import Numeric.LinearAlgebra as Math hiding ((<>))
5
6import Matrix
7import LambdaCube.GL.HMatrix ()
8
9data Camera = Camera
10 { camHeightAngle :: Float
11 , camTarget :: Vector Float -- 3-vector
12 , camDirection :: Vector Float -- 3-vector
13 , camDistance :: Float
14 , camWidth :: Float
15 , camHeight :: Float
16 , camUp :: Vector Float -- 3-vector
17 , camWorldToScreen :: Maybe (Matrix Float) -- 4×4
18 , camScreenToWorld :: Maybe (Matrix Float) -- 4×4
19 }
20
21-- | Compute the height of a pixel at the given 3d point.
22pixelDelta :: Camera -> Vector Float -> Float
23pixelDelta cam x = realToFrac $ frustumHeight eyeToPoint / realToFrac (camHeight cam)
24 where
25 eyeToPoint = norm_2 (x - camPos cam)
26 frustumHeight d = 2 * d * tan (realToFrac $ camHeightAngle cam / 2)
27
28camPos :: Camera -> Vector Float
29camPos c = camTarget c - scale (camDistance c) (camDirection c)
30
31camWorldCoordinates :: Camera -> Double -> Double -> Maybe (Vector Float) -> Vector Float
32camWorldCoordinates cam h k mplane = case mplane of
33 -- Write on the plane.
34 Just plane -> let n̂ = G.init plane
35 c = plane!3
36 a = (c - dot p n̂) / dot d̂ n̂
37 in p + scale a d̂
38
39 -- Write on the camDistance sphere.
40 Nothing -> p + scale (camDistance cam) d̂
41 where
42 q0 = fromList [ 2 * realToFrac h/camWidth cam - 1
43 , 1 - 2 * realToFrac k/camHeight cam
44 , 1
45 , 1
46 ] :: Vector Float
47 pv = snd $ projectionView cam
48 q1 = pv #> q0
49 q2 = scale (1 /(q1!3)) $ G.init q1
50 p = camPos cam
51 d = q2 - p
52 d̂ = unit d
53
54projectionView :: Camera -> (Camera,Matrix Float)
55projectionView c
56 | Just m <- camScreenToWorld c = (c,m)
57 | Just w <- camWorldToScreen c = projectionView c{ camScreenToWorld = Just $ invFloat w }
58 | otherwise = projectionView $ fst $ viewProjection c
59
60viewProjection :: Camera -> (Camera,(Matrix Float,Vector Float))
61viewProjection c
62 | Just m <- camWorldToScreen c = (c,(m,pos))
63 | otherwise = (c { camWorldToScreen = Just m' }, (m',pos))
64 where
65 m' = proj <> cam
66 cam = lookat pos (camTarget c) (camUp c)
67 pos = camPos c
68 proj = perspective 0.1 100 (camHeightAngle c) (camWidth c / camHeight c)
69
70invFloat :: Matrix Float -> Matrix Float
71invFloat m = realToFracMatrix $ inv (realToFracMatrix m :: Matrix Double)
72
73realToFracMatrix :: (Real a, Fractional t, Element t, Element a) => Matrix a -> Matrix t
74realToFracMatrix m = fromLists $ map realToFrac <$> toLists m
75
76unit :: (Linear t c, Fractional t, Normed (c t)) => c t -> c t
77unit v = scale (1/realToFrac (norm_2 v)) v
78
79
diff --git a/MeshSketch.hs b/MeshSketch.hs
index c63420e..1019d72 100644
--- a/MeshSketch.hs
+++ b/MeshSketch.hs
@@ -67,6 +67,7 @@ import qualified VectorRing as Vector
67import RingBuffer 67import RingBuffer
68import MaskableStream (AttributeKey,(@<-)) 68import MaskableStream (AttributeKey,(@<-))
69import SmallRing 69import SmallRing
70import Camera
70 71
71 72
72prettyDebug :: GL.DebugMessage -> String 73prettyDebug :: GL.DebugMessage -> String
@@ -118,21 +119,6 @@ data State = State
118 , stAngle :: IORef Int 119 , stAngle :: IORef Int
119 } 120 }
120 121
121data Camera = Camera
122 { camHeightAngle :: Float
123 , camTarget :: Vector Float -- 3-vector
124 , camDirection :: Vector Float -- 3-vector
125 , camDistance :: Float
126 , camWidth :: Float
127 , camHeight :: Float
128 , camUp :: Vector Float -- 3-vector
129 , camWorldToScreen :: Maybe (Matrix Float) -- 4×4
130 , camScreenToWorld :: Maybe (Matrix Float) -- 4×4
131 }
132
133camPos :: Camera -> Vector Float
134camPos c = camTarget c - scale (camDistance c) (camDirection c)
135
136initCamera :: Camera 122initCamera :: Camera
137initCamera = Camera 123initCamera = Camera
138 { camHeightAngle = pi/6 124 { camHeightAngle = pi/6
@@ -147,16 +133,6 @@ initCamera = Camera
147 } 133 }
148 where d = realToFrac $ norm_2 $ fromList [2::Float,2,10] 134 where d = realToFrac $ norm_2 $ fromList [2::Float,2,10]
149 135
150viewProjection :: Camera -> (Camera,(Matrix Float,Vector Float))
151viewProjection c
152 | Just m <- camWorldToScreen c = (c,(m,pos))
153 | otherwise = (c { camWorldToScreen = Just m' }, (m',pos))
154 where
155 m' = proj <> cam
156 cam = lookat pos (camTarget c) (camUp c)
157 pos = camPos c
158 proj = perspective 0.1 100 (camHeightAngle c) (camWidth c / camHeight c)
159
160realToFracVector :: ( Real a 136realToFracVector :: ( Real a
161 , Fractional b 137 , Fractional b
162 , Storable a 138 , Storable a
@@ -164,18 +140,6 @@ realToFracVector :: ( Real a
164 ) => Vector a -> Vector b 140 ) => Vector a -> Vector b
165realToFracVector v = Math.fromList $ map realToFrac $ Math.toList v 141realToFracVector v = Math.fromList $ map realToFrac $ Math.toList v
166 142
167realToFracMatrix :: (Real a, Fractional t, Element t, Element a) => Matrix a -> Matrix t
168realToFracMatrix m = fromLists $ map realToFrac <$> toLists m
169
170invFloat :: Matrix Float -> Matrix Float
171invFloat m = realToFracMatrix $ inv (realToFracMatrix m :: Matrix Double)
172
173projectionView :: Camera -> (Camera,Matrix Float)
174projectionView c
175 | Just m <- camScreenToWorld c = (c,m)
176 | Just w <- camWorldToScreen c = projectionView c{ camScreenToWorld = Just $ invFloat w }
177 | otherwise = projectionView $ fst $ viewProjection c
178
179addOBJToObjectArray :: GLStorage -> String -> [(GPUMesh, Maybe Text)] -> Map Text (ObjMaterial,TextureData) -> IO [LC.Object] 143addOBJToObjectArray :: GLStorage -> String -> [(GPUMesh, Maybe Text)] -> Map Text (ObjMaterial,TextureData) -> IO [LC.Object]
180addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \(mesh,mat) -> do 144addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \(mesh,mat) -> do
181 obj <- LC.addMeshToObjectArray storage slotName ["diffuseTexture","diffuseColor"] mesh 145 obj <- LC.addMeshToObjectArray storage slotName ["diffuseTexture","diffuseColor"] mesh
@@ -468,16 +432,6 @@ onResize glarea realized w h = do
468 } 432 }
469 LC.setScreenSize (stStorage realized) wd ht 433 LC.setScreenSize (stStorage realized) wd ht
470 434
471unit :: (Linear t c, Fractional t, Normed (c t)) => c t -> c t
472unit v = scale (1/realToFrac (norm_2 v)) v
473
474-- | Compute the height of a pixel at the given 3d point.
475pixelDelta :: Camera -> Vector Float -> Float
476pixelDelta cam x = realToFrac $ frustumHeight eyeToPoint / realToFrac (camHeight cam)
477 where
478 eyeToPoint = norm_2 (x - camPos cam)
479 frustumHeight d = 2 * d * tan (realToFrac $ camHeightAngle cam / 2)
480
481-- This computes a point in world coordinates on the view screen if 435-- This computes a point in world coordinates on the view screen if
482-- we assume the camera is located at the origin. 436-- we assume the camera is located at the origin.
483computeDirection :: Camera -> Double -> Double -> Vector Float 437computeDirection :: Camera -> Double -> Double -> Vector Float
diff --git a/lambda-gtk.cabal b/lambda-gtk.cabal
index e7e6859..a0c9fc3 100644
--- a/lambda-gtk.cabal
+++ b/lambda-gtk.cabal
@@ -50,7 +50,7 @@ executable meshsketch
50 other-modules: InfinitePlane LambdaCubeWidget GLWidget LambdaCube.Gtk TimeKeeper 50 other-modules: InfinitePlane LambdaCubeWidget GLWidget LambdaCube.Gtk TimeKeeper
51 LoadMesh MtlParser Matrix LambdaCube.GL.HMatrix 51 LoadMesh MtlParser Matrix LambdaCube.GL.HMatrix
52 Animator MeshSketch CubeMap AttributeData GPURing MaskableStream 52 Animator MeshSketch CubeMap AttributeData GPURing MaskableStream
53 RingBuffer SmallRing VectorRing 53 RingBuffer SmallRing VectorRing Camera
54 extensions: NondecreasingIndentation 54 extensions: NondecreasingIndentation
55 other-extensions: OverloadedLabels, OverloadedLists, OverloadedStrings 55 other-extensions: OverloadedLabels, OverloadedLists, OverloadedStrings
56 build-depends: base, containers >=0.5 && <0.6, bytestring >=0.10 && <0.11, 56 build-depends: base, containers >=0.5 && <0.6, bytestring >=0.10 && <0.11,