camera.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package camera contains virtual cameras and associated controls.
  5. package camera
  6. import (
  7. "github.com/g3n/engine/core"
  8. "github.com/g3n/engine/math32"
  9. "github.com/g3n/engine/util/logger"
  10. )
  11. // Package logger
  12. var log = logger.New("CAMERA", logger.Default)
  13. // Axis represents a camera axis.
  14. type Axis int
  15. // The two possible camera axes.
  16. const (
  17. Vertical = Axis(iota)
  18. Horizontal
  19. )
  20. // Projection represents a camera projection.
  21. type Projection int
  22. // The possible camera projections.
  23. const (
  24. Perspective = Projection(iota)
  25. Orthographic
  26. )
  27. // ICamera is the interface for all cameras.
  28. type ICamera interface {
  29. ViewMatrix(m *math32.Matrix4)
  30. ProjMatrix(m *math32.Matrix4)
  31. }
  32. // Camera represents a virtual camera, which specifies how to project a 3D scene onto an image.
  33. type Camera struct {
  34. core.Node // Embedded Node
  35. aspect float32 // Aspect ratio (width/height)
  36. near float32 // Near plane depth
  37. far float32 // Far plane depth
  38. axis Axis // The reference axis
  39. proj Projection // Projection method
  40. fov float32 // Perspective field-of-view along reference axis
  41. size float32 // Orthographic size along reference axis
  42. projChanged bool // Flag indicating that the projection matrix needs to be recalculated
  43. projMatrix math32.Matrix4 // Last calculated projection matrix
  44. }
  45. // New creates and returns a new perspective camera with the specified aspect ratio and default parameters.
  46. func New(aspect float32) *Camera {
  47. return NewPerspective(aspect, 0.3, 1000, 60, Vertical)
  48. }
  49. // NewPerspective creates and returns a new perspective camera with the specified parameters.
  50. func NewPerspective(aspect, near, far, fov float32, axis Axis) *Camera {
  51. c := new(Camera)
  52. c.Node.Init(c)
  53. c.SetDirection(0, 0, -1)
  54. c.aspect = aspect
  55. c.near = near
  56. c.far = far
  57. c.axis = axis
  58. c.proj = Perspective
  59. c.fov = fov
  60. c.size = 8
  61. c.projChanged = true
  62. return c
  63. }
  64. // NewOrthographic creates and returns a new orthographic camera with the specified parameters.
  65. func NewOrthographic(aspect, near, far, size float32, axis Axis) *Camera {
  66. c := new(Camera)
  67. c.Node.Init(c)
  68. c.SetDirection(0, 0, -1)
  69. c.aspect = aspect
  70. c.near = near
  71. c.far = far
  72. c.axis = axis
  73. c.proj = Orthographic
  74. c.fov = 60
  75. c.size = size
  76. c.projChanged = true
  77. return c
  78. }
  79. // Aspect returns the camera aspect ratio.
  80. func (c *Camera) Aspect() float32 {
  81. return c.aspect
  82. }
  83. // SetAspect sets the camera aspect ratio.
  84. func (c *Camera) SetAspect(aspect float32) {
  85. if aspect == c.aspect {
  86. return
  87. }
  88. c.aspect = aspect
  89. c.projChanged = true
  90. }
  91. // Near returns the camera near plane Z coordinate.
  92. func (c *Camera) Near() float32 {
  93. return c.near
  94. }
  95. // SetNear sets the camera near plane Z coordinate.
  96. func (c *Camera) SetNear(near float32) {
  97. if near == c.near {
  98. return
  99. }
  100. c.near = near
  101. c.projChanged = true
  102. }
  103. // Far returns the camera far plane Z coordinate.
  104. func (c *Camera) Far() float32 {
  105. return c.far
  106. }
  107. // SetFar sets the camera far plane Z coordinate.
  108. func (c *Camera) SetFar(far float32) {
  109. if far == c.far {
  110. return
  111. }
  112. c.far = far
  113. c.projChanged = true
  114. }
  115. // Axis returns the reference axis associated with the camera size/fov.
  116. func (c *Camera) Axis() Axis {
  117. return c.axis
  118. }
  119. // SetAxis sets the reference axis associated with the camera size/fov.
  120. func (c *Camera) SetAxis(axis Axis) {
  121. if axis == c.axis {
  122. return
  123. }
  124. c.axis = axis
  125. c.projChanged = true
  126. }
  127. // Projection returns the projection method used by the camera.
  128. func (c *Camera) Projection() Projection {
  129. return c.proj
  130. }
  131. // SetProjection sets the projection method used by the camera.
  132. func (c *Camera) SetProjection(proj Projection) {
  133. if proj == c.proj {
  134. return
  135. }
  136. c.proj = proj
  137. c.projChanged = true
  138. }
  139. // Fov returns the perspective field-of-view in degrees along the reference axis.
  140. func (c *Camera) Fov() float32 {
  141. return c.fov
  142. }
  143. // SetFov sets the perspective field-of-view in degrees along the reference axis.
  144. func (c *Camera) SetFov(fov float32) {
  145. if fov == c.fov {
  146. return
  147. }
  148. c.fov = fov
  149. if c.proj == Perspective {
  150. c.projChanged = true
  151. }
  152. }
  153. // UpdateFov updates the field-of-view such that the frustum matches
  154. // the orthographic size at the depth specified by targetDist.
  155. func (c *Camera) UpdateFov(targetDist float32) {
  156. c.fov = 2 * math32.Atan(c.size/(2*targetDist)) * 180 / math32.Pi
  157. if c.proj == Perspective {
  158. c.projChanged = true
  159. }
  160. }
  161. // Size returns the orthographic view size along the camera's reference axis.
  162. func (c *Camera) Size() float32 {
  163. return c.size
  164. }
  165. // SetSize sets the orthographic view size along the camera's reference axis.
  166. func (c *Camera) SetSize(size float32) {
  167. if size == c.size {
  168. return
  169. }
  170. c.size = size
  171. if c.proj == Orthographic {
  172. c.projChanged = true
  173. }
  174. }
  175. // UpdateSize updates the orthographic size to match the current
  176. // field-of-view frustum at the depth specified by targetDist.
  177. func (c *Camera) UpdateSize(targetDist float32) {
  178. c.size = 2 * targetDist * math32.Tan(math32.Pi/180*c.fov/2)
  179. if c.proj == Orthographic {
  180. c.projChanged = true
  181. }
  182. }
  183. // ViewMatrix returns the view matrix of the camera.
  184. func (c *Camera) ViewMatrix(m *math32.Matrix4) {
  185. c.UpdateMatrixWorld()
  186. matrixWorld := c.MatrixWorld()
  187. err := m.GetInverse(&matrixWorld)
  188. if err != nil {
  189. panic("Camera.ViewMatrix: Couldn't invert matrix")
  190. }
  191. }
  192. // ProjMatrix returns the projection matrix of the camera.
  193. func (c *Camera) ProjMatrix(m *math32.Matrix4) {
  194. if c.projChanged {
  195. switch c.proj {
  196. case Perspective:
  197. t := c.near * math32.Tan(math32.DegToRad(c.fov*0.5))
  198. ymax := t
  199. ymin := -t
  200. xmax := t
  201. xmin := -t
  202. switch c.axis {
  203. case Vertical:
  204. xmax *= c.aspect
  205. xmin *= c.aspect
  206. case Horizontal:
  207. ymax /= c.aspect
  208. ymin /= c.aspect
  209. }
  210. c.projMatrix.MakeFrustum(xmin, xmax, ymin, ymax, c.near, c.far)
  211. case Orthographic:
  212. s := c.size / 2
  213. var h, w float32
  214. switch c.axis {
  215. case Vertical:
  216. h = s
  217. w = s * c.aspect
  218. case Horizontal:
  219. h = s / c.aspect
  220. w = s
  221. }
  222. c.projMatrix.MakeOrthographic(-w, w, h, -h, c.near, c.far)
  223. }
  224. c.projChanged = false
  225. }
  226. *m = c.projMatrix
  227. }
  228. // Project transforms the specified position from world coordinates to this camera projected coordinates.
  229. func (c *Camera) Project(v *math32.Vector3) *math32.Vector3 {
  230. // Get camera view matrix
  231. var viewMat, projMat math32.Matrix4
  232. c.ViewMatrix(&viewMat)
  233. c.ProjMatrix(&projMat)
  234. // Apply projMat * viewMat to the provided vector
  235. v.ApplyProjection(projMat.Multiply(&viewMat))
  236. return v
  237. }
  238. // Unproject transforms the specified position from camera projected coordinates to world coordinates.
  239. func (c *Camera) Unproject(v *math32.Vector3) *math32.Vector3 {
  240. // Get inverted camera view matrix
  241. invViewMat := c.MatrixWorld()
  242. // Get inverted camera projection matrix
  243. var invProjMat math32.Matrix4
  244. c.ProjMatrix(&invProjMat)
  245. err := invProjMat.GetInverse(&invProjMat)
  246. if err != nil {
  247. panic("Camera.Unproject: Couldn't invert matrix")
  248. }
  249. // Apply invViewMat * invProjMat to the provided vector
  250. v.ApplyProjection(invViewMat.Multiply(&invProjMat))
  251. return v
  252. }