camera.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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.aspect = aspect
  54. c.near = near
  55. c.far = far
  56. c.axis = axis
  57. c.proj = Perspective
  58. c.fov = fov
  59. c.size = 8
  60. c.projChanged = true
  61. return c
  62. }
  63. // NewOrthographic creates and returns a new orthographic camera with the specified parameters.
  64. func NewOrthographic(aspect, near, far, size float32, axis Axis) *Camera {
  65. c := new(Camera)
  66. c.Node.Init(c)
  67. c.aspect = aspect
  68. c.near = near
  69. c.far = far
  70. c.axis = axis
  71. c.proj = Orthographic
  72. c.fov = 60
  73. c.size = size
  74. c.projChanged = true
  75. return c
  76. }
  77. // Aspect returns the camera aspect ratio.
  78. func (c *Camera) Aspect() float32 {
  79. return c.aspect
  80. }
  81. // SetAspect sets the camera aspect ratio.
  82. func (c *Camera) SetAspect(aspect float32) {
  83. if aspect == c.aspect {
  84. return
  85. }
  86. c.aspect = aspect
  87. c.projChanged = true
  88. }
  89. // Near returns the camera near plane Z coordinate.
  90. func (c *Camera) Near() float32 {
  91. return c.near
  92. }
  93. // SetNear sets the camera near plane Z coordinate.
  94. func (c *Camera) SetNear(near float32) {
  95. if near == c.near {
  96. return
  97. }
  98. c.near = near
  99. c.projChanged = true
  100. }
  101. // Far returns the camera far plane Z coordinate.
  102. func (c *Camera) Far() float32 {
  103. return c.far
  104. }
  105. // SetFar sets the camera far plane Z coordinate.
  106. func (c *Camera) SetFar(far float32) {
  107. if far == c.far {
  108. return
  109. }
  110. c.far = far
  111. c.projChanged = true
  112. }
  113. // Axis returns the reference axis associated with the camera size/fov.
  114. func (c *Camera) Axis() Axis {
  115. return c.axis
  116. }
  117. // SetAxis sets the reference axis associated with the camera size/fov.
  118. func (c *Camera) SetAxis(axis Axis) {
  119. if axis == c.axis {
  120. return
  121. }
  122. c.axis = axis
  123. c.projChanged = true
  124. }
  125. // Projection returns the projection method used by the camera.
  126. func (c *Camera) Projection() Projection {
  127. return c.proj
  128. }
  129. // SetProjection sets the projection method used by the camera.
  130. func (c *Camera) SetProjection(proj Projection) {
  131. if proj == c.proj {
  132. return
  133. }
  134. c.proj = proj
  135. c.projChanged = true
  136. }
  137. // Fov returns the perspective field-of-view in degrees along the reference axis.
  138. func (c *Camera) Fov() float32 {
  139. return c.fov
  140. }
  141. // SetFov sets the perspective field-of-view in degrees along the reference axis.
  142. func (c *Camera) SetFov(fov float32) {
  143. if fov == c.fov {
  144. return
  145. }
  146. c.fov = fov
  147. if c.proj == Perspective {
  148. c.projChanged = true
  149. }
  150. }
  151. // UpdateFov updates the field-of-view such that the frustum matches
  152. // the orthographic size at the depth specified by targetDist.
  153. func (c *Camera) UpdateFov(targetDist float32) {
  154. c.fov = 2 * math32.Atan(c.size/(2*targetDist)) * 180 / math32.Pi
  155. if c.proj == Perspective {
  156. c.projChanged = true
  157. }
  158. }
  159. // Size returns the orthographic view size along the camera's reference axis.
  160. func (c *Camera) Size() float32 {
  161. return c.size
  162. }
  163. // SetSize sets the orthographic view size along the camera's reference axis.
  164. func (c *Camera) SetSize(size float32) {
  165. if size == c.size {
  166. return
  167. }
  168. c.size = size
  169. if c.proj == Orthographic {
  170. c.projChanged = true
  171. }
  172. }
  173. // UpdateSize updates the orthographic size to match the current
  174. // field-of-view frustum at the depth specified by targetDist.
  175. func (c *Camera) UpdateSize(targetDist float32) {
  176. c.size = 2 * targetDist * math32.Tan(math32.Pi/180*c.fov/2)
  177. if c.proj == Orthographic {
  178. c.projChanged = true
  179. }
  180. }
  181. // ViewMatrix returns the view matrix of the camera.
  182. func (c *Camera) ViewMatrix(m *math32.Matrix4) {
  183. c.UpdateMatrixWorld()
  184. matrixWorld := c.MatrixWorld()
  185. err := m.GetInverse(&matrixWorld)
  186. if err != nil {
  187. panic("Camera.ViewMatrix: Couldn't invert matrix")
  188. }
  189. }
  190. // ProjMatrix returns the projection matrix of the camera.
  191. func (c *Camera) ProjMatrix(m *math32.Matrix4) {
  192. if c.projChanged {
  193. switch c.proj {
  194. case Perspective:
  195. fov := c.fov
  196. if c.axis == Horizontal {
  197. fov *= c.aspect
  198. }
  199. c.projMatrix.MakePerspective(fov, c.aspect, c.near, c.far)
  200. case Orthographic:
  201. s := c.size / 2
  202. var h, w float32
  203. switch c.axis {
  204. case Vertical:
  205. h = s
  206. w = s * c.aspect
  207. case Horizontal:
  208. h = s / c.aspect
  209. w = s
  210. }
  211. c.projMatrix.MakeOrthographic(-w, w, h, -h, c.near, c.far)
  212. }
  213. c.projChanged = false
  214. }
  215. *m = c.projMatrix
  216. }
  217. // Project transforms the specified position from world coordinates to this camera projected coordinates.
  218. func (c *Camera) Project(v *math32.Vector3) *math32.Vector3 {
  219. // Get camera view matrix
  220. var viewMat, projMat math32.Matrix4
  221. c.ViewMatrix(&viewMat)
  222. c.ProjMatrix(&projMat)
  223. // Apply projMat * viewMat to the provided vector
  224. v.ApplyProjection(projMat.Multiply(&viewMat))
  225. return v
  226. }
  227. // Unproject transforms the specified position from camera projected coordinates to world coordinates.
  228. func (c *Camera) Unproject(v *math32.Vector3) *math32.Vector3 {
  229. // Get inverted camera view matrix
  230. invViewMat := c.MatrixWorld()
  231. // Get inverted camera projection matrix
  232. var invProjMat math32.Matrix4
  233. c.ProjMatrix(&invProjMat)
  234. err := invProjMat.GetInverse(&invProjMat)
  235. if err != nil {
  236. panic("Camera.Unproject: Couldn't invert matrix")
  237. }
  238. // Apply invViewMat * invProjMat to the provided vector
  239. v.ApplyProjection(invViewMat.Multiply(&invProjMat))
  240. return v
  241. }