perspective.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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
  5. import (
  6. "github.com/g3n/engine/core"
  7. "github.com/g3n/engine/math32"
  8. )
  9. // Perspective represents a perspective camera
  10. type Perspective struct {
  11. Camera // Embedded camera
  12. fov float32 // field of view in degrees
  13. aspect float32 // aspect ratio (width/height)
  14. near float32 // near plane z coordinate
  15. far float32 // far plane z coordinate
  16. projChanged bool // camera projection parameters changed (needs to recalculates projection matrix)
  17. projMatrix math32.Matrix4 // last calculated projection matrix
  18. }
  19. // NewPerspective creates and returns a pointer to a new perspective camera with the
  20. // specified parameters.
  21. func NewPerspective(fov, aspect, near, far float32) *Perspective {
  22. cam := new(Perspective)
  23. cam.Camera.Initialize()
  24. cam.fov = fov
  25. cam.aspect = aspect
  26. cam.near = near
  27. cam.far = far
  28. cam.projChanged = true
  29. return cam
  30. }
  31. // SetFov sets the camera field of view in degrees
  32. func (cam *Perspective) SetFov(fov float32) {
  33. cam.fov = fov
  34. cam.projChanged = true
  35. }
  36. // SetAspect sets the camera aspect ratio (width/height)
  37. func (cam *Perspective) SetAspect(aspect float32) {
  38. cam.aspect = aspect
  39. cam.projChanged = true
  40. }
  41. // Fov returns the current camera FOV (field of view) in degrees
  42. func (cam *Perspective) Fov() float32 {
  43. return cam.fov
  44. }
  45. // Aspect returns the current camera aspect ratio
  46. func (cam Perspective) Aspect() float32 {
  47. return cam.aspect
  48. }
  49. // Near returns the current camera near plane Z coordinate
  50. func (cam *Perspective) Near() float32 {
  51. return cam.near
  52. }
  53. // Far returns the current camera far plane Z coordinate
  54. func (cam *Perspective) Far() float32 {
  55. return cam.far
  56. }
  57. // ProjMatrix satisfies the ICamera interface
  58. func (cam *Perspective) ProjMatrix(m *math32.Matrix4) {
  59. cam.updateProjMatrix()
  60. *m = cam.projMatrix
  61. }
  62. // Project transforms the specified position from world coordinates to this camera projected coordinates.
  63. func (cam *Perspective) Project(v *math32.Vector3) (*math32.Vector3, error) {
  64. cam.updateProjMatrix()
  65. var matrix math32.Matrix4
  66. matrixWorld := cam.MatrixWorld()
  67. err := matrix.GetInverse(&matrixWorld)
  68. if err != nil {
  69. return nil, err
  70. }
  71. matrix.MultiplyMatrices(&cam.projMatrix, &matrix)
  72. v.ApplyProjection(&matrix)
  73. return v, nil
  74. }
  75. // Unproject transforms the specified position from camera projected coordinates to world coordinates.
  76. func (cam *Perspective) Unproject(v *math32.Vector3) (*math32.Vector3, error) {
  77. // Get inverted camera view matrix
  78. var viewMatrix math32.Matrix4
  79. cam.ViewMatrix(&viewMatrix)
  80. var invertedViewMatrix math32.Matrix4
  81. err := invertedViewMatrix.GetInverse(&viewMatrix)
  82. if err != nil {
  83. return nil, err
  84. }
  85. // Get inverted camera projection matrix
  86. cam.updateProjMatrix()
  87. var invertedProjMatrix math32.Matrix4
  88. err = invertedProjMatrix.GetInverse(&cam.projMatrix)
  89. if err != nil {
  90. return nil, err
  91. }
  92. // Multiply invertedViewMatrix by invertedProjMatrix
  93. // to get transformation from camera projected coordinates to world coordinates
  94. // and project vector using this transformation
  95. var matrix math32.Matrix4
  96. matrix.MultiplyMatrices(&invertedViewMatrix, &invertedProjMatrix)
  97. v.ApplyProjection(&matrix)
  98. return v, nil
  99. }
  100. // SetRaycaster sets the specified raycaster with this camera position in world coordinates
  101. // pointing to the direction defined by the specified coordinates unprojected using this camera.
  102. func (cam *Perspective) SetRaycaster(rc *core.Raycaster, sx, sy float32) error {
  103. var origin, direction math32.Vector3
  104. matrixWorld := cam.MatrixWorld()
  105. origin.SetFromMatrixPosition(&matrixWorld)
  106. direction.Set(sx, sy, 0.5)
  107. unproj, err := cam.Unproject(&direction)
  108. if err != nil {
  109. return err
  110. }
  111. unproj.Sub(&origin).Normalize()
  112. rc.Set(&origin, &direction)
  113. // Updates the view matrix of the raycaster
  114. cam.ViewMatrix(&rc.ViewMatrix)
  115. return nil
  116. }
  117. // updateProjMatrix updates this camera projection matrix if necessary
  118. func (cam *Perspective) updateProjMatrix() {
  119. if cam.projChanged {
  120. cam.projMatrix.MakePerspective(cam.fov, cam.aspect, cam.near, cam.far)
  121. cam.projChanged = false
  122. }
  123. }