raycaster.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  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 collision
  5. import (
  6. "sort"
  7. "github.com/g3n/engine/camera"
  8. "github.com/g3n/engine/core"
  9. "github.com/g3n/engine/gls"
  10. "github.com/g3n/engine/graphic"
  11. "github.com/g3n/engine/material"
  12. "github.com/g3n/engine/math32"
  13. )
  14. // Raycaster represents an empty object that can cast rays and check for ray intersections.
  15. type Raycaster struct {
  16. // The distance from the ray origin to the intersected points
  17. // must be greater than the value of this field to be considered.
  18. // The defaul value is 0.0
  19. Near float32
  20. // The distance from the ray origin to the intersected points
  21. // must be less than the value of this field to be considered.
  22. // The defaul value is +Infinity.
  23. Far float32
  24. // Minimum distance in world coordinates between the ray and
  25. // a line segment when checking intersects with lines.
  26. // The default value is 0.1
  27. LinePrecision float32
  28. // Minimum distance in world coordinates between the ray and
  29. // a point when checking intersects with points.
  30. // The default value is 0.1
  31. PointPrecision float32
  32. // This field must be set with the camera view matrix used
  33. // when checking for sprite intersections.
  34. // It is set automatically when using camera.SetRaycaster
  35. ViewMatrix math32.Matrix4
  36. // Embedded ray
  37. math32.Ray
  38. }
  39. // Intersect describes the intersection between a ray and an object
  40. type Intersect struct {
  41. // Distance between the origin of the ray and the intersect
  42. Distance float32
  43. // Point of intersection in world coordinates
  44. Point math32.Vector3
  45. // Intersected node
  46. Object core.INode
  47. // If the geometry has indices, this field is the
  48. // index in the Indices buffer of the vertex intersected
  49. // or the first vertex of the intersected face.
  50. // If the geometry doesn't have indices, this field is the
  51. // index in the positions buffer of the vertex intersected
  52. // or the first vertex of the insersected face.
  53. Index uint32
  54. }
  55. // NewRaycaster creates and returns a pointer to a new raycaster object
  56. // with the specified origin and direction.
  57. func NewRaycaster(origin, direction *math32.Vector3) *Raycaster {
  58. rc := new(Raycaster)
  59. rc.Ray.Set(origin, direction)
  60. rc.Near = 0
  61. rc.Far = math32.Inf(1)
  62. rc.LinePrecision = 0.1
  63. rc.PointPrecision = 0.1
  64. return rc
  65. }
  66. // IntersectObject checks intersections between this raycaster and
  67. // and the specified node. If recursive is true, it also checks
  68. // the intersection with the node's children.
  69. // Intersections are returned sorted by distance, closest first.
  70. func (rc *Raycaster) IntersectObject(inode core.INode, recursive bool) []Intersect {
  71. intersects := []Intersect{}
  72. rc.intersectObject(inode, &intersects, recursive)
  73. sort.Slice(intersects, func(i, j int) bool {
  74. return intersects[i].Distance < intersects[j].Distance
  75. })
  76. return intersects
  77. }
  78. // IntersectObjects checks intersections between this raycaster and
  79. // the specified array of scene nodes. If recursive is true, it also checks
  80. // the intersection with each nodes' children.
  81. // Intersections are returned sorted by distance, closest first.
  82. func (rc *Raycaster) IntersectObjects(inodes []core.INode, recursive bool) []Intersect {
  83. intersects := []Intersect{}
  84. for _, inode := range inodes {
  85. rc.intersectObject(inode, &intersects, recursive)
  86. }
  87. sort.Slice(intersects, func(i, j int) bool {
  88. return intersects[i].Distance < intersects[j].Distance
  89. })
  90. return intersects
  91. }
  92. func (rc *Raycaster) intersectObject(inode core.INode, intersects *[]Intersect, recursive bool) {
  93. node := inode.GetNode()
  94. if !node.Visible() {
  95. return
  96. }
  97. switch in := inode.(type) {
  98. case *graphic.Sprite:
  99. rc.RaycastSprite(in, intersects)
  100. case *graphic.Points:
  101. rc.RaycastPoints(in, intersects)
  102. case *graphic.Mesh:
  103. rc.RaycastMesh(in, intersects)
  104. case *graphic.Lines:
  105. rc.RaycastLines(in, intersects)
  106. case *graphic.LineStrip:
  107. rc.RaycastLineStrip(in, intersects)
  108. }
  109. if recursive {
  110. for _, child := range node.Children() {
  111. rc.intersectObject(child, intersects, true)
  112. }
  113. }
  114. return
  115. }
  116. // SetRaycaster sets the specified raycaster with this camera position in world coordinates
  117. // pointing to the direction defined by the specified coordinates unprojected using this camera.
  118. func (rc *Raycaster) SetFromCamera(cam *camera.Camera, sx, sy float32) error { // TODO maybe use ICamera
  119. var origin, direction math32.Vector3
  120. matrixWorld := cam.MatrixWorld()
  121. origin.SetFromMatrixPosition(&matrixWorld)
  122. direction.Set(sx, sy, 0.5)
  123. unproj := cam.Unproject(&direction) // unproj = direction after this point TODO improve clarity
  124. unproj.Sub(&origin).Normalize()
  125. rc.Set(&origin, &direction)
  126. cam.ViewMatrix(&rc.ViewMatrix) // Update the view matrix of the raycaster
  127. return nil
  128. }
  129. // RaycastSprite checks intersections between the raycaster and the specified sprite
  130. // and if any found appends it to the specified intersects array.
  131. func (rc *Raycaster) RaycastSprite(s *graphic.Sprite, intersects *[]Intersect) {
  132. // Copy and convert ray to camera coordinates
  133. var ray math32.Ray
  134. ray.Copy(&rc.Ray).ApplyMatrix4(&rc.ViewMatrix)
  135. // Calculates ViewMatrix * MatrixWorld
  136. var mv math32.Matrix4
  137. matrixWorld := s.MatrixWorld()
  138. mv.MultiplyMatrices(&rc.ViewMatrix, &matrixWorld)
  139. // Decompose transformation matrix in its components
  140. var position math32.Vector3
  141. var quaternion math32.Quaternion
  142. var scale math32.Vector3
  143. mv.Decompose(&position, &quaternion, &scale)
  144. // Remove any rotation in X and Y axis and
  145. // compose new transformation matrix
  146. rotation := s.Rotation()
  147. rotation.X = 0
  148. rotation.Y = 0
  149. quaternion.SetFromEuler(&rotation)
  150. mv.Compose(&position, &quaternion, &scale)
  151. // Get buffer with vertices and uvs
  152. geom := s.GetGeometry()
  153. vboPos := geom.VBO(gls.VertexPosition)
  154. if vboPos == nil {
  155. panic("sprite.Raycast(): VertexPosition VBO not found")
  156. }
  157. // Get vertex positions, transform to camera coordinates and
  158. // checks intersection with ray
  159. buffer := vboPos.Buffer()
  160. indices := geom.Indices()
  161. var v1 math32.Vector3
  162. var v2 math32.Vector3
  163. var v3 math32.Vector3
  164. var point math32.Vector3
  165. intersect := false
  166. for i := 0; i < indices.Size(); i += 3 {
  167. pos := indices[i]
  168. buffer.GetVector3(int(pos*5), &v1)
  169. v1.ApplyMatrix4(&mv)
  170. pos = indices[i+1]
  171. buffer.GetVector3(int(pos*5), &v2)
  172. v2.ApplyMatrix4(&mv)
  173. pos = indices[i+2]
  174. buffer.GetVector3(int(pos*5), &v3)
  175. v3.ApplyMatrix4(&mv)
  176. if ray.IntersectTriangle(&v1, &v2, &v3, false, &point) {
  177. intersect = true
  178. break
  179. }
  180. }
  181. if !intersect {
  182. return
  183. }
  184. // Get distance from intersection point
  185. origin := ray.Origin()
  186. distance := origin.DistanceTo(&point)
  187. // Checks if distance is between the bounds of the raycaster
  188. if distance < rc.Near || distance > rc.Far {
  189. return
  190. }
  191. // Appends intersection to received parameter.
  192. *intersects = append(*intersects, Intersect{
  193. Distance: distance,
  194. Point: point,
  195. Object: s,
  196. })
  197. }
  198. // RaycastPoints
  199. func (rc *Raycaster) RaycastPoints(p *graphic.Points, intersects *[]Intersect) {
  200. // Checks intersection with the bounding sphere transformed to world coordinates
  201. geom := p.GetGeometry()
  202. sphere := geom.BoundingSphere()
  203. matrixWorld := p.MatrixWorld()
  204. sphere.ApplyMatrix4(&matrixWorld)
  205. if !rc.IsIntersectionSphere(&sphere) {
  206. return
  207. }
  208. // Copy ray and transforms to model coordinates
  209. var inverseMatrix math32.Matrix4
  210. var ray math32.Ray
  211. inverseMatrix.GetInverse(&matrixWorld)
  212. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  213. // Checks intersection with all points
  214. scale := p.Scale()
  215. localThreshold := rc.PointPrecision / ((scale.X + scale.Y + scale.Z) / 3)
  216. localThresholdSq := localThreshold * localThreshold
  217. // internal function to check intersection with a point
  218. testPoint := func(point *math32.Vector3, index int) {
  219. // Get distance from ray to point and if greater than threshold,
  220. // nothing to do.
  221. rayPointDistanceSq := ray.DistanceSqToPoint(point)
  222. if rayPointDistanceSq >= localThresholdSq {
  223. return
  224. }
  225. var intersectPoint math32.Vector3
  226. ray.ClosestPointToPoint(point, &intersectPoint)
  227. intersectPoint.ApplyMatrix4(&matrixWorld)
  228. origin := rc.Ray.Origin()
  229. distance := origin.DistanceTo(&intersectPoint)
  230. if distance < rc.Near || distance > rc.Far {
  231. return
  232. }
  233. // Appends intersection of raycaster with this point
  234. *intersects = append(*intersects, Intersect{
  235. Distance: distance,
  236. Point: intersectPoint,
  237. Index: uint32(index),
  238. Object: p,
  239. })
  240. }
  241. i := 0
  242. geom.ReadVertices(func(vertex math32.Vector3) bool {
  243. testPoint(&vertex, i)
  244. i++
  245. return false
  246. })
  247. }
  248. // RaycastMesh
  249. func (rc *Raycaster) RaycastMesh(m *graphic.Mesh, intersects *[]Intersect) {
  250. // Transform this mesh geometry bounding sphere from model
  251. // to world coordinates and checks intersection with raycaster
  252. geom := m.GetGeometry()
  253. sphere := geom.BoundingSphere()
  254. matrixWorld := m.MatrixWorld()
  255. sphere.ApplyMatrix4(&matrixWorld)
  256. if !rc.IsIntersectionSphere(&sphere) {
  257. return
  258. }
  259. // Copy ray and transform to model coordinates
  260. // This ray will will also be used to check intersects with
  261. // the geometry, as is much less expensive to transform the
  262. // ray to model coordinates than the geometry to world coordinates.
  263. var inverseMatrix math32.Matrix4
  264. inverseMatrix.GetInverse(&matrixWorld)
  265. var ray math32.Ray
  266. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  267. bbox := geom.BoundingBox()
  268. if !ray.IsIntersectionBox(&bbox) {
  269. return
  270. }
  271. // Local function to check the intersection of the ray from the raycaster with
  272. // the specified face defined by three poins.
  273. checkIntersection := func(mat *material.Material, pA, pB, pC, point *math32.Vector3) *Intersect {
  274. var intersect bool
  275. switch mat.Side() {
  276. case material.SideBack:
  277. intersect = ray.IntersectTriangle(pC, pB, pA, true, point)
  278. case material.SideFront:
  279. intersect = ray.IntersectTriangle(pA, pB, pC, true, point)
  280. case material.SideDouble:
  281. intersect = ray.IntersectTriangle(pA, pB, pC, false, point)
  282. }
  283. if !intersect {
  284. return nil
  285. }
  286. // Transform intersection point from model to world coordinates
  287. var intersectionPointWorld = *point
  288. intersectionPointWorld.ApplyMatrix4(&matrixWorld)
  289. // Calculates the distance from the ray origin to intersection point
  290. origin := rc.Ray.Origin()
  291. distance := origin.DistanceTo(&intersectionPointWorld)
  292. // Checks if distance is between the bounds of the raycaster
  293. if distance < rc.Near || distance > rc.Far {
  294. return nil
  295. }
  296. return &Intersect{
  297. Distance: distance,
  298. Point: intersectionPointWorld,
  299. Object: m,
  300. }
  301. }
  302. i := 0
  303. geom.ReadFaces(func(vA, vB, vC math32.Vector3) bool {
  304. // Checks intersection of the ray with this face
  305. mat := m.GetMaterial(i).GetMaterial()
  306. var point math32.Vector3
  307. intersect := checkIntersection(mat, &vA, &vB, &vC, &point)
  308. if intersect != nil {
  309. intersect.Index = uint32(i)
  310. *intersects = append(*intersects, *intersect)
  311. }
  312. i += 3
  313. return false
  314. })
  315. }
  316. // RaycastLines
  317. func (rc *Raycaster) RaycastLines(l *graphic.Lines, intersects *[]Intersect) {
  318. lineRaycast(l, rc, intersects, 2)
  319. }
  320. // RaycastLineStrip
  321. func (rc *Raycaster) RaycastLineStrip(l *graphic.LineStrip, intersects *[]Intersect) {
  322. lineRaycast(l, rc, intersects, 1)
  323. }
  324. // Internal function used by raycasting for Lines and LineStrip.
  325. func lineRaycast(igr graphic.IGraphic, rc *Raycaster, intersects *[]Intersect, step int) {
  326. // Get the bounding sphere
  327. gr := igr.GetGraphic()
  328. geom := igr.GetGeometry()
  329. sphere := geom.BoundingSphere()
  330. // Transform bounding sphere from model to world coordinates and
  331. // checks intersection with raycaster
  332. matrixWorld := gr.MatrixWorld()
  333. sphere.ApplyMatrix4(&matrixWorld)
  334. if !rc.IsIntersectionSphere(&sphere) {
  335. return
  336. }
  337. // Copy ray and transform to model coordinates
  338. // This ray will will also be used to check intersects with
  339. // the geometry, as is much less expensive to transform the
  340. // ray to model coordinates than the geometry to world coordinates.
  341. var inverseMatrix math32.Matrix4
  342. var ray math32.Ray
  343. inverseMatrix.GetInverse(&matrixWorld)
  344. ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
  345. var vstart math32.Vector3
  346. var vend math32.Vector3
  347. var interSegment math32.Vector3
  348. var interRay math32.Vector3
  349. // Get geometry positions and indices buffers
  350. vboPos := geom.VBO(gls.VertexPosition)
  351. if vboPos == nil {
  352. return
  353. }
  354. positions := vboPos.Buffer()
  355. indices := geom.Indices()
  356. precisionSq := rc.LinePrecision * rc.LinePrecision
  357. // Checks intersection with individual lines for indexed geometry
  358. if indices.Size() > 0 {
  359. for i := 0; i < indices.Size()-1; i += step {
  360. // Calculates distance from ray to this line segment
  361. a := indices[i]
  362. b := indices[i+1]
  363. positions.GetVector3(int(3*a), &vstart)
  364. positions.GetVector3(int(3*b), &vend)
  365. distSq := ray.DistanceSqToSegment(&vstart, &vend, &interRay, &interSegment)
  366. if distSq > precisionSq {
  367. continue
  368. }
  369. // Move back to world coordinates for distance calculation
  370. interRay.ApplyMatrix4(&matrixWorld)
  371. origin := rc.Ray.Origin()
  372. distance := origin.DistanceTo(&interRay)
  373. if distance < rc.Near || distance > rc.Far {
  374. continue
  375. }
  376. interSegment.ApplyMatrix4(&matrixWorld)
  377. *intersects = append(*intersects, Intersect{
  378. Distance: distance,
  379. Point: interSegment,
  380. Index: uint32(i),
  381. Object: igr,
  382. })
  383. }
  384. // Checks intersection with individual lines for NON indexed geometry
  385. } else {
  386. for i := 0; i < positions.Size()/3-1; i += step {
  387. positions.GetVector3(int(3*i), &vstart)
  388. positions.GetVector3(int(3*i+3), &vend)
  389. distSq := ray.DistanceSqToSegment(&vstart, &vend, &interRay, &interSegment)
  390. if distSq > precisionSq {
  391. continue
  392. }
  393. // Move back to world coordinates for distance calculation
  394. interRay.ApplyMatrix4(&matrixWorld)
  395. origin := rc.Ray.Origin()
  396. distance := origin.DistanceTo(&interRay)
  397. if distance < rc.Near || distance > rc.Far {
  398. continue
  399. }
  400. interSegment.ApplyMatrix4(&matrixWorld)
  401. *intersects = append(*intersects, Intersect{
  402. Distance: distance,
  403. Point: interSegment,
  404. Index: uint32(i),
  405. Object: igr,
  406. })
  407. }
  408. }
  409. }