/
Camera.hs
146 lines (117 loc) · 4.68 KB
/
Camera.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : Diagrams.ThreeD.Camera
-- Copyright : (c) 2013 diagrams-lib team (see LICENSE)
-- License : BSD-style (see LICENSE)
-- Maintainer : diagrams-discuss@googlegroups.com
--
-- Types to specify viewpoint for 3D rendering.
--
-----------------------------------------------------------------------------
module Diagrams.ThreeD.Camera
( Camera -- do not export constructor
-- These are safe to construct manually
, PerspectiveLens(..), OrthoLens(..)
, horizontalFieldOfView, verticalFieldOfView
, orthoWidth, orthoHeight
, camLoc, camForward, camUp, camRight, camLens
, facing_ZCamera, mm50Camera
, mm50, mm50Wide, mm50Narrow
, aspect, camAspect
)
where
import Control.Lens (makeLenses)
import Data.Monoid
import Data.Typeable
import Diagrams.Angle
import Diagrams.Core
import Diagrams.Direction
import Diagrams.ThreeD.Vector
import Linear.V3
-- Parameterize Camera on the lens type, so that Backends can express which
-- lenses they handle.
data Camera l n = Camera
{ camLoc :: Point V3 n
, forward :: V3 n
, up :: V3 n
, lens :: l n
}
deriving Typeable
type instance V (Camera l n) = V3
type instance N (Camera l n) = n
class Typeable l => CameraLens l where
-- | The natural aspect ratio of the projection.
aspect :: Floating n => l n -> n
-- | A perspective projection
data PerspectiveLens n = PerspectiveLens
{ _horizontalFieldOfView :: Angle n -- ^ Horizontal field of view.
, _verticalFieldOfView :: Angle n -- ^ Vertical field of view.
}
deriving Typeable
makeLenses ''PerspectiveLens
type instance V (PerspectiveLens n) = V3
type instance N (PerspectiveLens n) = n
instance CameraLens PerspectiveLens where
aspect (PerspectiveLens h v) = angleRatio h v
-- | An orthographic projection
data OrthoLens n = OrthoLens
{ _orthoWidth :: n -- ^ Width
, _orthoHeight :: n -- ^ Height
}
deriving Typeable
makeLenses ''OrthoLens
type instance V (OrthoLens n) = V3
type instance N (OrthoLens n) = n
instance CameraLens OrthoLens where
aspect (OrthoLens h v) = h / v
instance Num n => Transformable (Camera l n) where
transform t (Camera p f u l) =
Camera (transform t p)
(transform t f)
(transform t u)
l
instance Num n => Renderable (Camera l n) NullBackend where
render _ _ = mempty
-- | A camera at the origin facing along the negative Z axis, with its
-- up-axis coincident with the positive Y axis. The field of view is
-- chosen to match a 50mm camera on 35mm film. Note that Cameras take
-- up no space in the Diagram.
mm50Camera :: (Typeable n, Floating n, Ord n, Renderable (Camera PerspectiveLens n) b)
=> QDiagram b V3 n Any
mm50Camera = facing_ZCamera mm50
-- | 'facing_ZCamera l' is a camera at the origin facing along the
-- negative Z axis, with its up-axis coincident with the positive Y
-- axis, with the projection defined by l.
facing_ZCamera :: (Floating n, Ord n, Typeable n, CameraLens l, Renderable (Camera l n) b) =>
l n -> QDiagram b V3 n Any
facing_ZCamera l = mkQD (Prim $ Camera origin unit_Z unitY l)
mempty mempty mempty (Query . const . Any $ False)
{-# ANN facing_ZCamera ("HLint: ignore Use camelCase" :: String) #-}
mm50, mm50Wide, mm50Narrow :: Floating n => PerspectiveLens n
-- | mm50 has the field of view of a 50mm lens on standard 35mm film,
-- hence an aspect ratio of 3:2.
mm50 = PerspectiveLens (40.5 @@ deg) (27 @@ deg)
-- | mm50blWide has the same vertical field of view as mm50, but an
-- aspect ratio of 1.6, suitable for wide screen computer monitors.
mm50Wide = PerspectiveLens (43.2 @@ deg) (27 @@ deg)
-- | mm50Narrow has the same vertical field of view as mm50, but an
-- aspect ratio of 4:3, for VGA and similar computer resolutions.
mm50Narrow = PerspectiveLens (36 @@ deg) (27 @@ deg)
camForward :: Camera l n -> Direction V3 n
camForward = direction . forward
camUp :: Camera l n -> Direction V3 n
camUp = direction . up
camRight :: Fractional n => Camera l n -> Direction V3 n
camRight c = direction right where
right = cross (forward c) (up c)
camLens :: Camera l n -> l n
camLens = lens
camAspect :: (Floating n, CameraLens l) => Camera l n -> n
camAspect = aspect . camLens