perspective.go 4.1 KB

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