lines.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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 graphic
  5. import (
  6. "github.com/g3n/engine/core"
  7. "github.com/g3n/engine/geometry"
  8. "github.com/g3n/engine/gls"
  9. "github.com/g3n/engine/material"
  10. "github.com/g3n/engine/math32"
  11. )
  12. // Lines is a Graphic which is rendered as a collection of independent lines
  13. type Lines struct {
  14. Graphic // Embedded graphic object
  15. uniMVP gls.Uniform // Model view projection matrix uniform location cache
  16. }
  17. func (l *Lines) Init(igeom geometry.IGeometry, imat material.IMaterial) {
  18. l.Graphic.Init(igeom, gls.LINES)
  19. l.AddMaterial(l, imat, 0, 0)
  20. l.uniMVP.Init("MVP")
  21. }
  22. func NewLines(igeom geometry.IGeometry, imat material.IMaterial) *Lines {
  23. l := new(Lines)
  24. l.Init(igeom, imat)
  25. return l
  26. }
  27. // RenderSetup is called by the engine before drawing this geometry
  28. func (l *Lines) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  29. // Calculates model view projection matrix and updates uniform
  30. mw := l.MatrixWorld()
  31. var mvpm math32.Matrix4
  32. mvpm.MultiplyMatrices(&rinfo.ViewMatrix, &mw)
  33. mvpm.MultiplyMatrices(&rinfo.ProjMatrix, &mvpm)
  34. // Transfer mvpm uniform
  35. location := l.uniMVP.Location(gs)
  36. gs.UniformMatrix4fv(location, 1, false, &mvpm[0])
  37. }
  38. // Raycast satisfies the INode interface and checks the intersections
  39. // of this geometry with the specified raycaster
  40. func (l *Lines) Raycast(rc *core.Raycaster, intersects *[]core.Intersect) {
  41. lineRaycast(l, rc, intersects, 2)
  42. }
  43. // Internal function used by raycasting for Lines and LineStrip
  44. func lineRaycast(igr IGraphic, rc *core.Raycaster, intersects *[]core.Intersect, step int) {
  45. // Get the bounding sphere
  46. gr := igr.GetGraphic()
  47. geom := igr.GetGeometry()
  48. sphere := geom.BoundingSphere()
  49. // Transform bounding sphere from model to world coordinates and
  50. // checks intersection with raycaster
  51. matrixWorld := gr.MatrixWorld()
  52. sphere.ApplyMatrix4(&matrixWorld)
  53. if !rc.IsIntersectionSphere(&sphere) {
  54. return
  55. }
  56. // Copy ray and transform to model coordinates
  57. // This ray will will also be used to check intersects with
  58. // the geometry, as is much less expensive to transform the
  59. // ray to model coordinates than the geometry to world coordinates.
  60. var inverseMatrix math32.Matrix4
  61. var ray math32.Ray
  62. inverseMatrix.GetInverse(&matrixWorld, true)
  63. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  64. var vstart math32.Vector3
  65. var vend math32.Vector3
  66. var interSegment math32.Vector3
  67. var interRay math32.Vector3
  68. // Get geometry positions and indices buffers
  69. vboPos := geom.VBO("VertexPosition")
  70. if vboPos == nil {
  71. return
  72. }
  73. positions := vboPos.Buffer()
  74. indices := geom.Indices()
  75. precisionSq := rc.LinePrecision * rc.LinePrecision
  76. // Checks intersection with individual lines for indexed geometry
  77. if indices.Size() > 0 {
  78. for i := 0; i < indices.Size()-1; i += step {
  79. // Calculates distance from ray to this line segment
  80. a := indices[i]
  81. b := indices[i+1]
  82. positions.GetVector3(int(3*a), &vstart)
  83. positions.GetVector3(int(3*b), &vend)
  84. distSq := ray.DistanceSqToSegment(&vstart, &vend, &interRay, &interSegment)
  85. if distSq > precisionSq {
  86. continue
  87. }
  88. // Move back to world coordinates for distance calculation
  89. interRay.ApplyMatrix4(&matrixWorld)
  90. origin := rc.Ray.Origin()
  91. distance := origin.DistanceTo(&interRay)
  92. if distance < rc.Near || distance > rc.Far {
  93. continue
  94. }
  95. interSegment.ApplyMatrix4(&matrixWorld)
  96. *intersects = append(*intersects, core.Intersect{
  97. Distance: distance,
  98. Point: interSegment,
  99. Index: uint32(i),
  100. Object: igr,
  101. })
  102. }
  103. // Checks intersection with individual lines for NON indexed geometry
  104. } else {
  105. for i := 0; i < positions.Size()/3-1; i += step {
  106. positions.GetVector3(int(3*i), &vstart)
  107. positions.GetVector3(int(3*i+3), &vend)
  108. distSq := ray.DistanceSqToSegment(&vstart, &vend, &interRay, &interSegment)
  109. if distSq > precisionSq {
  110. continue
  111. }
  112. // Move back to world coordinates for distance calculation
  113. interRay.ApplyMatrix4(&matrixWorld)
  114. origin := rc.Ray.Origin()
  115. distance := origin.DistanceTo(&interRay)
  116. if distance < rc.Near || distance > rc.Far {
  117. continue
  118. }
  119. interSegment.ApplyMatrix4(&matrixWorld)
  120. *intersects = append(*intersects, core.Intersect{
  121. Distance: distance,
  122. Point: interSegment,
  123. Index: uint32(i),
  124. Object: igr,
  125. })
  126. }
  127. }
  128. }