frustum.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 math32
  5. // Frustum represents a frustum
  6. type Frustum struct {
  7. planes []Plane
  8. }
  9. // NewFrustumFromMatrix creates and returns a Frustum based on the provided matrix
  10. func NewFrustumFromMatrix(m *Matrix4) *Frustum {
  11. f := new(Frustum)
  12. f.planes = make([]Plane, 6)
  13. f.SetFromMatrix(m)
  14. return f
  15. }
  16. // NewFrustum returns a pointer to a new Frustum object
  17. func NewFrustum(p0, p1, p2, p3, p4, p5 *Plane) *Frustum {
  18. f := new(Frustum)
  19. f.planes = make([]Plane, 6)
  20. f.Set(p0, p1, p2, p3, p4, p5)
  21. return f
  22. }
  23. // Set sets the frustum's planes
  24. func (f *Frustum) Set(p0, p1, p2, p3, p4, p5 *Plane) *Frustum {
  25. if p0 != nil {
  26. f.planes[0] = *p0
  27. }
  28. if p1 != nil {
  29. f.planes[1] = *p1
  30. }
  31. if p2 != nil {
  32. f.planes[2] = *p2
  33. }
  34. if p3 != nil {
  35. f.planes[3] = *p3
  36. }
  37. if p4 != nil {
  38. f.planes[4] = *p4
  39. }
  40. if p5 != nil {
  41. f.planes[5] = *p5
  42. }
  43. return f
  44. }
  45. // Copy modifies the receiver frustum to match the provided frustum
  46. func (f *Frustum) Copy(frustum *Frustum) *Frustum {
  47. for i := 0; i < 6; i++ {
  48. f.planes[i] = frustum.planes[i]
  49. }
  50. return f
  51. }
  52. // SetFromMatrix sets the frustum's planes based on the specified Matrix4
  53. func (f *Frustum) SetFromMatrix(m *Matrix4) *Frustum {
  54. planes := f.planes
  55. me0 := m[0]
  56. me1 := m[1]
  57. me2 := m[2]
  58. me3 := m[3]
  59. me4 := m[4]
  60. me5 := m[5]
  61. me6 := m[6]
  62. me7 := m[7]
  63. me8 := m[8]
  64. me9 := m[9]
  65. me10 := m[10]
  66. me11 := m[11]
  67. me12 := m[12]
  68. me13 := m[13]
  69. me14 := m[14]
  70. me15 := m[15]
  71. planes[0].SetComponents(me3-me0, me7-me4, me11-me8, me15-me12).Normalize()
  72. planes[1].SetComponents(me3+me0, me7+me4, me11+me8, me15+me12).Normalize()
  73. planes[2].SetComponents(me3+me1, me7+me5, me11+me9, me15+me13).Normalize()
  74. planes[3].SetComponents(me3-me1, me7-me5, me11-me9, me15-me13).Normalize()
  75. planes[4].SetComponents(me3-me2, me7-me6, me11-me10, me15-me14).Normalize()
  76. planes[5].SetComponents(me3+me2, me7+me6, me11+me10, me15+me14).Normalize()
  77. return f
  78. }
  79. /**
  80. SHOULD NOT DEPEND on core package (Move to core ?)
  81. func (this *Frustum) IntersectsObject(geometry *core.Geometry) bool {
  82. return false
  83. }
  84. */
  85. // IntersectsSphere determines whether the specified sphere is intersecting the frustum
  86. func (f *Frustum) IntersectsSphere(sphere *Sphere) bool {
  87. planes := f.planes
  88. negRadius := -sphere.Radius
  89. for i := 0; i < 6; i++ {
  90. distance := planes[i].DistanceToPoint(&sphere.Center)
  91. if distance < negRadius {
  92. return false
  93. }
  94. }
  95. return true
  96. }
  97. // IntersectsBox determines whether the specified box is intersecting the frustum
  98. func (f *Frustum) IntersectsBox(box *Box3) bool {
  99. var p1 Vector3
  100. var p2 Vector3
  101. for i := 0; i < 6; i++ {
  102. plane := &f.planes[i]
  103. if plane.normal.X > 0 {
  104. p1.X = box.Min.X
  105. } else {
  106. p1.X = box.Max.X
  107. }
  108. if plane.normal.X > 0 {
  109. p2.X = box.Max.X
  110. } else {
  111. p2.X = box.Min.X
  112. }
  113. if plane.normal.Y > 0 {
  114. p1.Y = box.Min.Y
  115. } else {
  116. p1.Y = box.Max.Y
  117. }
  118. if plane.normal.Y > 0 {
  119. p2.Y = box.Max.Y
  120. } else {
  121. p2.Y = box.Min.Y
  122. }
  123. if plane.normal.Z > 0 {
  124. p1.Z = box.Min.Z
  125. } else {
  126. p1.Z = box.Max.Z
  127. }
  128. if plane.normal.Z > 0 {
  129. p2.Z = box.Max.Z
  130. } else {
  131. p2.Z = box.Min.Z
  132. }
  133. d1 := plane.DistanceToPoint(&p1)
  134. d2 := plane.DistanceToPoint(&p2)
  135. // if both outside plane, no intersection
  136. if d1 < 0 && d2 < 0 {
  137. return false
  138. }
  139. }
  140. return true
  141. }
  142. // ContainsPoint determines whether the frustum contains the specified point
  143. func (f *Frustum) ContainsPoint(point *Vector3) bool {
  144. for i := 0; i < 6; i++ {
  145. if f.planes[i].DistanceToPoint(point) < 0 {
  146. return false
  147. }
  148. }
  149. return true
  150. }
  151. // Clone returns a pointer to a new Frustum object with the same planes as the original
  152. func (f *Frustum) Clone() *Frustum {
  153. return NewFrustum(nil, nil, nil, nil, nil, nil).Copy(f)
  154. }