perspective.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 is 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. // Get camera view matrix
  65. var matrix math32.Matrix4
  66. matrixWorld := cam.MatrixWorld()
  67. err := matrix.GetInverse(&matrixWorld)
  68. if err != nil {
  69. return nil, err
  70. }
  71. // Update camera projection matrix
  72. cam.updateProjMatrix()
  73. // Multiply viewMatrix by projMatrix and apply the resulting projection matrix to the provided vector
  74. matrix.MultiplyMatrices(&cam.projMatrix, &matrix)
  75. v.ApplyProjection(&matrix)
  76. return v, nil
  77. }
  78. // Unproject transforms the specified position from camera projected coordinates to world coordinates.
  79. func (cam *Perspective) Unproject(v *math32.Vector3) (*math32.Vector3, error) {
  80. // Get inverted camera view matrix
  81. invertedViewMatrix := cam.MatrixWorld()
  82. // Get inverted camera projection matrix
  83. cam.updateProjMatrix()
  84. var invertedProjMatrix math32.Matrix4
  85. err := invertedProjMatrix.GetInverse(&cam.projMatrix)
  86. if err != nil {
  87. return nil, err
  88. }
  89. // Multiply invertedViewMatrix by invertedProjMatrix
  90. // to get transformation from camera projected coordinates to world coordinates
  91. // and project vector using this transformation
  92. var matrix math32.Matrix4
  93. matrix.MultiplyMatrices(&invertedViewMatrix, &invertedProjMatrix)
  94. v.ApplyProjection(&matrix)
  95. return v, nil
  96. }
  97. // SetRaycaster sets the specified raycaster with this camera position in world coordinates
  98. // pointing to the direction defined by the specified coordinates unprojected using this camera.
  99. func (cam *Perspective) SetRaycaster(rc *core.Raycaster, sx, sy float32) error {
  100. var origin, direction math32.Vector3
  101. matrixWorld := cam.MatrixWorld()
  102. origin.SetFromMatrixPosition(&matrixWorld)
  103. direction.Set(sx, sy, 0.5)
  104. unproj, err := cam.Unproject(&direction)
  105. if err != nil {
  106. return err
  107. }
  108. unproj.Sub(&origin).Normalize()
  109. rc.Set(&origin, &direction)
  110. // Updates the view matrix of the raycaster
  111. cam.ViewMatrix(&rc.ViewMatrix)
  112. return nil
  113. }
  114. // updateProjMatrix updates the projection matrix if necessary.
  115. func (cam *Perspective) updateProjMatrix() {
  116. if cam.projChanged {
  117. cam.projMatrix.MakePerspective(cam.fov, cam.aspect, cam.near, cam.far)
  118. cam.projChanged = false
  119. }
  120. }