points.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. type Points struct {
  13. Graphic // Embedded graphic
  14. mvpm gls.UniformMatrix4f // Model view projection matrix uniform
  15. }
  16. // NewPoints creates and returns a graphic points object with the specified
  17. // geometry and material.
  18. func NewPoints(igeom geometry.IGeometry, imat material.IMaterial) *Points {
  19. p := new(Points)
  20. p.Graphic.Init(igeom, gls.POINTS)
  21. if imat != nil {
  22. p.AddMaterial(p, imat, 0, 0)
  23. }
  24. p.mvpm.Init("MVP")
  25. return p
  26. }
  27. // RenderSetup is called by the engine before rendering this graphic
  28. func (p *Points) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  29. // Calculates model view projection matrix and updates uniform
  30. mw := p.MatrixWorld()
  31. var mvpm math32.Matrix4
  32. mvpm.MultiplyMatrices(&rinfo.ViewMatrix, &mw)
  33. mvpm.MultiplyMatrices(&rinfo.ProjMatrix, &mvpm)
  34. p.mvpm.SetMatrix4(&mvpm)
  35. p.mvpm.Transfer(gs)
  36. }
  37. // Raycast satisfies the INode interface and checks the intersections
  38. // of this geometry with the specified raycaster
  39. func (p *Points) Raycast(rc *core.Raycaster, intersects *[]core.Intersect) {
  40. // Checks intersection with the bounding sphere transformed to world coordinates
  41. geom := p.GetGeometry()
  42. sphere := geom.BoundingSphere()
  43. matrixWorld := p.MatrixWorld()
  44. sphere.ApplyMatrix4(&matrixWorld)
  45. if !rc.IsIntersectionSphere(&sphere) {
  46. return
  47. }
  48. // Copy ray and transforms to model coordinates
  49. var inverseMatrix math32.Matrix4
  50. var ray math32.Ray
  51. inverseMatrix.GetInverse(&matrixWorld, true)
  52. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  53. // Checks intersection with all points
  54. scale := p.Scale()
  55. localThreshold := rc.PointPrecision / ((scale.X + scale.Y + scale.Z) / 3)
  56. localThresholdSq := localThreshold * localThreshold
  57. // internal function to check intersection with a point
  58. testPoint := func(point *math32.Vector3, index int) {
  59. // Get distance from ray to point and if greater than threshold,
  60. // nothing to do.
  61. rayPointDistanceSq := ray.DistanceSqToPoint(point)
  62. if rayPointDistanceSq >= localThresholdSq {
  63. return
  64. }
  65. var intersectPoint math32.Vector3
  66. ray.ClosestPointToPoint(point, &intersectPoint)
  67. intersectPoint.ApplyMatrix4(&matrixWorld)
  68. origin := rc.Ray.Origin()
  69. distance := origin.DistanceTo(&intersectPoint)
  70. if distance < rc.Near || distance > rc.Far {
  71. return
  72. }
  73. // Appends intersection of raycaster with this point
  74. *intersects = append(*intersects, core.Intersect{
  75. Distance: distance,
  76. Point: intersectPoint,
  77. Index: uint32(index),
  78. Object: p,
  79. })
  80. }
  81. // Get buffer with position vertices
  82. vbPos := geom.VBO("VertexPosition")
  83. if vbPos == nil {
  84. panic("points.Raycast(): VertexPosition VBO not found")
  85. }
  86. positions := vbPos.Buffer()
  87. var point math32.Vector3
  88. indices := geom.Indices()
  89. // Geometry has indexed vertices
  90. if indices.Size() > 0 {
  91. for i := 0; i < indices.Size(); i++ {
  92. a := indices[i]
  93. positions.GetVector3(int(a*3), &point)
  94. testPoint(&point, i)
  95. }
  96. } else {
  97. for i := 0; i < positions.Size()/3; i++ {
  98. positions.GetVector3(i*3, &point)
  99. testPoint(&point, i)
  100. }
  101. }
  102. }