camera.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. t := c.near * math32.Tan(math32.DegToRad(c.fov*0.5))
  196. ymax := t
  197. ymin := -t
  198. xmax := t
  199. xmin := -t
  200. switch c.axis {
  201. case Vertical:
  202. xmax *= c.aspect
  203. xmin *= c.aspect
  204. case Horizontal:
  205. ymax /= c.aspect
  206. ymin /= c.aspect
  207. }
  208. c.projMatrix.MakeFrustum(xmin, xmax, ymin, ymax, c.near, c.far)
  209. case Orthographic:
  210. s := c.size / 2
  211. var h, w float32
  212. switch c.axis {
  213. case Vertical:
  214. h = s
  215. w = s * c.aspect
  216. case Horizontal:
  217. h = s / c.aspect
  218. w = s
  219. }
  220. c.projMatrix.MakeOrthographic(-w, w, h, -h, c.near, c.far)
  221. }
  222. c.projChanged = false
  223. }
  224. *m = c.projMatrix
  225. }
  226. // Project transforms the specified position from world coordinates to this camera projected coordinates.
  227. func (c *Camera) Project(v *math32.Vector3) *math32.Vector3 {
  228. // Get camera view matrix
  229. var viewMat, projMat math32.Matrix4
  230. c.ViewMatrix(&viewMat)
  231. c.ProjMatrix(&projMat)
  232. // Apply projMat * viewMat to the provided vector
  233. v.ApplyProjection(projMat.Multiply(&viewMat))
  234. return v
  235. }
  236. // Unproject transforms the specified position from camera projected coordinates to world coordinates.
  237. func (c *Camera) Unproject(v *math32.Vector3) *math32.Vector3 {
  238. // Get inverted camera view matrix
  239. invViewMat := c.MatrixWorld()
  240. // Get inverted camera projection matrix
  241. var invProjMat math32.Matrix4
  242. c.ProjMatrix(&invProjMat)
  243. err := invProjMat.GetInverse(&invProjMat)
  244. if err != nil {
  245. panic("Camera.Unproject: Couldn't invert matrix")
  246. }
  247. // Apply invViewMat * invProjMat to the provided vector
  248. v.ApplyProjection(invViewMat.Multiply(&invProjMat))
  249. return v
  250. }