|
@@ -0,0 +1,465 @@
|
|
|
|
|
+// Copyright 2016 The G3N Authors. All rights reserved.
|
|
|
|
|
+// Use of this source code is governed by a BSD-style
|
|
|
|
|
+// license that can be found in the LICENSE file.
|
|
|
|
|
+
|
|
|
|
|
+package collision
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "github.com/g3n/engine/camera"
|
|
|
|
|
+ "github.com/g3n/engine/core"
|
|
|
|
|
+ "github.com/g3n/engine/gls"
|
|
|
|
|
+ "github.com/g3n/engine/graphic"
|
|
|
|
|
+ "github.com/g3n/engine/material"
|
|
|
|
|
+ "github.com/g3n/engine/math32"
|
|
|
|
|
+ "sort"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// Raycaster represents an empty object that can cast rays and check for ray intersections.
|
|
|
|
|
+type Raycaster struct {
|
|
|
|
|
+ // The distance from the ray origin to the intersected points
|
|
|
|
|
+ // must be greater than the value of this field to be considered.
|
|
|
|
|
+ // The defaul value is 0.0
|
|
|
|
|
+ Near float32
|
|
|
|
|
+ // The distance from the ray origin to the intersected points
|
|
|
|
|
+ // must be less than the value of this field to be considered.
|
|
|
|
|
+ // The defaul value is +Infinity.
|
|
|
|
|
+ Far float32
|
|
|
|
|
+ // Minimum distance in world coordinates between the ray and
|
|
|
|
|
+ // a line segment when checking intersects with lines.
|
|
|
|
|
+ // The default value is 0.1
|
|
|
|
|
+ LinePrecision float32
|
|
|
|
|
+ // Minimum distance in world coordinates between the ray and
|
|
|
|
|
+ // a point when checking intersects with points.
|
|
|
|
|
+ // The default value is 0.1
|
|
|
|
|
+ PointPrecision float32
|
|
|
|
|
+ // This field must be set with the camera view matrix used
|
|
|
|
|
+ // when checking for sprite intersections.
|
|
|
|
|
+ // It is set automatically when using camera.SetRaycaster
|
|
|
|
|
+ ViewMatrix math32.Matrix4
|
|
|
|
|
+ // Embedded ray
|
|
|
|
|
+ math32.Ray
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Intersect describes the intersection between a ray and an object
|
|
|
|
|
+type Intersect struct {
|
|
|
|
|
+ // Distance between the origin of the ray and the intersect
|
|
|
|
|
+ Distance float32
|
|
|
|
|
+ // Point of intersection in world coordinates
|
|
|
|
|
+ Point math32.Vector3
|
|
|
|
|
+ // Intersected node
|
|
|
|
|
+ Object core.INode
|
|
|
|
|
+ // If the geometry has indices, this field is the
|
|
|
|
|
+ // index in the Indices buffer of the vertex intersected
|
|
|
|
|
+ // or the first vertex of the intersected face.
|
|
|
|
|
+ // If the geometry doesn't have indices, this field is the
|
|
|
|
|
+ // index in the positions buffer of the vertex intersected
|
|
|
|
|
+ // or the first vertex of the insersected face.
|
|
|
|
|
+ Index uint32
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// NewRaycaster creates and returns a pointer to a new raycaster object
|
|
|
|
|
+// with the specified origin and direction.
|
|
|
|
|
+func NewRaycaster(origin, direction *math32.Vector3) *Raycaster {
|
|
|
|
|
+
|
|
|
|
|
+ rc := new(Raycaster)
|
|
|
|
|
+ rc.Ray.Set(origin, direction)
|
|
|
|
|
+ rc.Near = 0
|
|
|
|
|
+ rc.Far = math32.Inf(1)
|
|
|
|
|
+ rc.LinePrecision = 0.1
|
|
|
|
|
+ rc.PointPrecision = 0.1
|
|
|
|
|
+ return rc
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IntersectObject checks intersections between this raycaster and
|
|
|
|
|
+// and the specified node. If recursive is true, it also checks
|
|
|
|
|
+// the intersection with the node's children.
|
|
|
|
|
+// Intersections are returned sorted by distance, closest first.
|
|
|
|
|
+func (rc *Raycaster) IntersectObject(inode core.INode, recursive bool) []Intersect {
|
|
|
|
|
+
|
|
|
|
|
+ intersects := []Intersect{}
|
|
|
|
|
+ rc.intersectObject(inode, &intersects, recursive)
|
|
|
|
|
+ sort.Slice(intersects, func(i, j int) bool {
|
|
|
|
|
+ return intersects[i].Distance < intersects[j].Distance
|
|
|
|
|
+ })
|
|
|
|
|
+ return intersects
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IntersectObjects checks intersections between this raycaster and
|
|
|
|
|
+// the specified array of scene nodes. If recursive is true, it also checks
|
|
|
|
|
+// the intersection with each nodes' children.
|
|
|
|
|
+// Intersections are returned sorted by distance, closest first.
|
|
|
|
|
+func (rc *Raycaster) IntersectObjects(inodes []core.INode, recursive bool) []Intersect {
|
|
|
|
|
+
|
|
|
|
|
+ intersects := []Intersect{}
|
|
|
|
|
+ for _, inode := range inodes {
|
|
|
|
|
+ rc.intersectObject(inode, &intersects, recursive)
|
|
|
|
|
+ }
|
|
|
|
|
+ sort.Slice(intersects, func(i, j int) bool {
|
|
|
|
|
+ return intersects[i].Distance < intersects[j].Distance
|
|
|
|
|
+ })
|
|
|
|
|
+ return intersects
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (rc *Raycaster) intersectObject(inode core.INode, intersects *[]Intersect, recursive bool) {
|
|
|
|
|
+
|
|
|
|
|
+ node := inode.GetNode()
|
|
|
|
|
+ if !node.Visible() {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch in := inode.(type) {
|
|
|
|
|
+ case *graphic.Sprite:
|
|
|
|
|
+ rc.RaycastSprite(in, intersects)
|
|
|
|
|
+ case *graphic.Points:
|
|
|
|
|
+ rc.RaycastPoints(in, intersects)
|
|
|
|
|
+ case *graphic.Mesh:
|
|
|
|
|
+ rc.RaycastMesh(in, intersects)
|
|
|
|
|
+ case *graphic.Lines:
|
|
|
|
|
+ rc.RaycastLines(in, intersects)
|
|
|
|
|
+ case *graphic.LineStrip:
|
|
|
|
|
+ rc.RaycastLineStrip(in, intersects)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if recursive {
|
|
|
|
|
+ for _, child := range node.Children() {
|
|
|
|
|
+ rc.intersectObject(child, intersects, true)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// SetRaycaster sets the specified raycaster with this camera position in world coordinates
|
|
|
|
|
+// pointing to the direction defined by the specified coordinates unprojected using this camera.
|
|
|
|
|
+func (rc *Raycaster) SetFromCamera(cam *camera.Camera, sx, sy float32) error { // TODO maybe use ICamera
|
|
|
|
|
+
|
|
|
|
|
+ var origin, direction math32.Vector3
|
|
|
|
|
+ matrixWorld := cam.MatrixWorld()
|
|
|
|
|
+ origin.SetFromMatrixPosition(&matrixWorld)
|
|
|
|
|
+ direction.Set(sx, sy, 0.5)
|
|
|
|
|
+
|
|
|
|
|
+ unproj := cam.Unproject(&direction) // unproj = direction after this point TODO improve clarity
|
|
|
|
|
+ unproj.Sub(&origin).Normalize()
|
|
|
|
|
+ rc.Set(&origin, &direction)
|
|
|
|
|
+ cam.ViewMatrix(&rc.ViewMatrix) // Update the view matrix of the raycaster
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// RaycastSprite checks intersections between the raycaster and the specified sprite
|
|
|
|
|
+// and if any found appends it to the specified intersects array.
|
|
|
|
|
+func (rc *Raycaster) RaycastSprite(s *graphic.Sprite, intersects *[]Intersect) {
|
|
|
|
|
+
|
|
|
|
|
+ // Copy and convert ray to camera coordinates
|
|
|
|
|
+ var ray math32.Ray
|
|
|
|
|
+ ray.Copy(&rc.Ray).ApplyMatrix4(&rc.ViewMatrix)
|
|
|
|
|
+
|
|
|
|
|
+ // Calculates ViewMatrix * MatrixWorld
|
|
|
|
|
+ var mv math32.Matrix4
|
|
|
|
|
+ matrixWorld := s.MatrixWorld()
|
|
|
|
|
+ mv.MultiplyMatrices(&rc.ViewMatrix, &matrixWorld)
|
|
|
|
|
+
|
|
|
|
|
+ // Decompose transformation matrix in its components
|
|
|
|
|
+ var position math32.Vector3
|
|
|
|
|
+ var quaternion math32.Quaternion
|
|
|
|
|
+ var scale math32.Vector3
|
|
|
|
|
+ mv.Decompose(&position, &quaternion, &scale)
|
|
|
|
|
+
|
|
|
|
|
+ // Remove any rotation in X and Y axis and
|
|
|
|
|
+ // compose new transformation matrix
|
|
|
|
|
+ rotation := s.Rotation()
|
|
|
|
|
+ rotation.X = 0
|
|
|
|
|
+ rotation.Y = 0
|
|
|
|
|
+ quaternion.SetFromEuler(&rotation)
|
|
|
|
|
+ mv.Compose(&position, &quaternion, &scale)
|
|
|
|
|
+
|
|
|
|
|
+ // Get buffer with vertices and uvs
|
|
|
|
|
+ geom := s.GetGeometry()
|
|
|
|
|
+ vboPos := geom.VBO(gls.VertexPosition)
|
|
|
|
|
+ if vboPos == nil {
|
|
|
|
|
+ panic("sprite.Raycast(): VertexPosition VBO not found")
|
|
|
|
|
+ }
|
|
|
|
|
+ // Get vertex positions, transform to camera coordinates and
|
|
|
|
|
+ // checks intersection with ray
|
|
|
|
|
+ buffer := vboPos.Buffer()
|
|
|
|
|
+ indices := geom.Indices()
|
|
|
|
|
+ var v1 math32.Vector3
|
|
|
|
|
+ var v2 math32.Vector3
|
|
|
|
|
+ var v3 math32.Vector3
|
|
|
|
|
+ var point math32.Vector3
|
|
|
|
|
+ intersect := false
|
|
|
|
|
+ for i := 0; i < indices.Size(); i += 3 {
|
|
|
|
|
+ pos := indices[i]
|
|
|
|
|
+ buffer.GetVector3(int(pos*5), &v1)
|
|
|
|
|
+ v1.ApplyMatrix4(&mv)
|
|
|
|
|
+ pos = indices[i+1]
|
|
|
|
|
+ buffer.GetVector3(int(pos*5), &v2)
|
|
|
|
|
+ v2.ApplyMatrix4(&mv)
|
|
|
|
|
+ pos = indices[i+2]
|
|
|
|
|
+ buffer.GetVector3(int(pos*5), &v3)
|
|
|
|
|
+ v3.ApplyMatrix4(&mv)
|
|
|
|
|
+ if ray.IntersectTriangle(&v1, &v2, &v3, false, &point) {
|
|
|
|
|
+ intersect = true
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if !intersect {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ // Get distance from intersection point
|
|
|
|
|
+ origin := ray.Origin()
|
|
|
|
|
+ distance := origin.DistanceTo(&point)
|
|
|
|
|
+
|
|
|
|
|
+ // Checks if distance is between the bounds of the raycaster
|
|
|
|
|
+ if distance < rc.Near || distance > rc.Far {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Appends intersection to received parameter.
|
|
|
|
|
+ *intersects = append(*intersects, Intersect{
|
|
|
|
|
+ Distance: distance,
|
|
|
|
|
+ Point: point,
|
|
|
|
|
+ Object: s,
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// RaycastPoints
|
|
|
|
|
+func (rc *Raycaster) RaycastPoints(p *graphic.Points, intersects *[]Intersect) {
|
|
|
|
|
+
|
|
|
|
|
+ // Checks intersection with the bounding sphere transformed to world coordinates
|
|
|
|
|
+ geom := p.GetGeometry()
|
|
|
|
|
+ sphere := geom.BoundingSphere()
|
|
|
|
|
+ matrixWorld := p.MatrixWorld()
|
|
|
|
|
+ sphere.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ if !rc.IsIntersectionSphere(&sphere) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Copy ray and transforms to model coordinates
|
|
|
|
|
+ var inverseMatrix math32.Matrix4
|
|
|
|
|
+ var ray math32.Ray
|
|
|
|
|
+ inverseMatrix.GetInverse(&matrixWorld)
|
|
|
|
|
+ ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
|
|
|
|
|
+
|
|
|
|
|
+ // Checks intersection with all points
|
|
|
|
|
+ scale := p.Scale()
|
|
|
|
|
+ localThreshold := rc.PointPrecision / ((scale.X + scale.Y + scale.Z) / 3)
|
|
|
|
|
+ localThresholdSq := localThreshold * localThreshold
|
|
|
|
|
+
|
|
|
|
|
+ // internal function to check intersection with a point
|
|
|
|
|
+ testPoint := func(point *math32.Vector3, index int) {
|
|
|
|
|
+
|
|
|
|
|
+ // Get distance from ray to point and if greater than threshold,
|
|
|
|
|
+ // nothing to do.
|
|
|
|
|
+ rayPointDistanceSq := ray.DistanceSqToPoint(point)
|
|
|
|
|
+ if rayPointDistanceSq >= localThresholdSq {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ var intersectPoint math32.Vector3
|
|
|
|
|
+ ray.ClosestPointToPoint(point, &intersectPoint)
|
|
|
|
|
+ intersectPoint.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ origin := rc.Ray.Origin()
|
|
|
|
|
+ distance := origin.DistanceTo(&intersectPoint)
|
|
|
|
|
+ if distance < rc.Near || distance > rc.Far {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ // Appends intersection of raycaster with this point
|
|
|
|
|
+ *intersects = append(*intersects, Intersect{
|
|
|
|
|
+ Distance: distance,
|
|
|
|
|
+ Point: intersectPoint,
|
|
|
|
|
+ Index: uint32(index),
|
|
|
|
|
+ Object: p,
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ i := 0
|
|
|
|
|
+ geom.ReadVertices(func(vertex math32.Vector3) bool {
|
|
|
|
|
+ testPoint(&vertex, i)
|
|
|
|
|
+ i++
|
|
|
|
|
+ return false
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// RaycastMesh
|
|
|
|
|
+func (rc *Raycaster) RaycastMesh(m *graphic.Mesh, intersects *[]Intersect) {
|
|
|
|
|
+
|
|
|
|
|
+ // Transform this mesh geometry bounding sphere from model
|
|
|
|
|
+ // to world coordinates and checks intersection with raycaster
|
|
|
|
|
+ geom := m.GetGeometry()
|
|
|
|
|
+ sphere := geom.BoundingSphere()
|
|
|
|
|
+ matrixWorld := m.MatrixWorld()
|
|
|
|
|
+ sphere.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ if !rc.IsIntersectionSphere(&sphere) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Copy ray and transform to model coordinates
|
|
|
|
|
+ // This ray will will also be used to check intersects with
|
|
|
|
|
+ // the geometry, as is much less expensive to transform the
|
|
|
|
|
+ // ray to model coordinates than the geometry to world coordinates.
|
|
|
|
|
+ var inverseMatrix math32.Matrix4
|
|
|
|
|
+ inverseMatrix.GetInverse(&matrixWorld)
|
|
|
|
|
+ var ray math32.Ray
|
|
|
|
|
+ ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
|
|
|
|
|
+ bbox := geom.BoundingBox()
|
|
|
|
|
+ if !ray.IsIntersectionBox(&bbox) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Local function to check the intersection of the ray from the raycaster with
|
|
|
|
|
+ // the specified face defined by three poins.
|
|
|
|
|
+ checkIntersection := func(mat *material.Material, pA, pB, pC, point *math32.Vector3) *Intersect {
|
|
|
|
|
+
|
|
|
|
|
+ var intersect bool
|
|
|
|
|
+ switch mat.Side() {
|
|
|
|
|
+ case material.SideBack:
|
|
|
|
|
+ intersect = ray.IntersectTriangle(pC, pB, pA, true, point)
|
|
|
|
|
+ case material.SideFront:
|
|
|
|
|
+ intersect = ray.IntersectTriangle(pA, pB, pC, true, point)
|
|
|
|
|
+ case material.SideDouble:
|
|
|
|
|
+ intersect = ray.IntersectTriangle(pA, pB, pC, false, point)
|
|
|
|
|
+ }
|
|
|
|
|
+ if !intersect {
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Transform intersection point from model to world coordinates
|
|
|
|
|
+ var intersectionPointWorld = *point
|
|
|
|
|
+ intersectionPointWorld.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+
|
|
|
|
|
+ // Calculates the distance from the ray origin to intersection point
|
|
|
|
|
+ origin := rc.Ray.Origin()
|
|
|
|
|
+ distance := origin.DistanceTo(&intersectionPointWorld)
|
|
|
|
|
+
|
|
|
|
|
+ // Checks if distance is between the bounds of the raycaster
|
|
|
|
|
+ if distance < rc.Near || distance > rc.Far {
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return &Intersect{
|
|
|
|
|
+ Distance: distance,
|
|
|
|
|
+ Point: intersectionPointWorld,
|
|
|
|
|
+ Object: m,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ i := 0
|
|
|
|
|
+ geom.ReadFaces(func(vA, vB, vC math32.Vector3) bool {
|
|
|
|
|
+ // Checks intersection of the ray with this face
|
|
|
|
|
+ mat := m.GetMaterial(i).GetMaterial()
|
|
|
|
|
+ var point math32.Vector3
|
|
|
|
|
+ intersect := checkIntersection(mat, &vA, &vB, &vC, &point)
|
|
|
|
|
+ if intersect != nil {
|
|
|
|
|
+ intersect.Index = uint32(i)
|
|
|
|
|
+ *intersects = append(*intersects, *intersect)
|
|
|
|
|
+ }
|
|
|
|
|
+ i += 3
|
|
|
|
|
+ return false
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// RaycastLines
|
|
|
|
|
+func (rc *Raycaster) RaycastLines(l *graphic.Lines, intersects *[]Intersect) {
|
|
|
|
|
+
|
|
|
|
|
+ lineRaycast(l, rc, intersects, 2)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// RaycastLineStrip
|
|
|
|
|
+func (rc *Raycaster) RaycastLineStrip(l *graphic.LineStrip, intersects *[]Intersect) {
|
|
|
|
|
+
|
|
|
|
|
+ lineRaycast(l, rc, intersects, 1)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Internal function used by raycasting for Lines and LineStrip.
|
|
|
|
|
+func lineRaycast(igr graphic.IGraphic, rc *Raycaster, intersects *[]Intersect, step int) {
|
|
|
|
|
+
|
|
|
|
|
+ // Get the bounding sphere
|
|
|
|
|
+ gr := igr.GetGraphic()
|
|
|
|
|
+ geom := igr.GetGeometry()
|
|
|
|
|
+ sphere := geom.BoundingSphere()
|
|
|
|
|
+
|
|
|
|
|
+ // Transform bounding sphere from model to world coordinates and
|
|
|
|
|
+ // checks intersection with raycaster
|
|
|
|
|
+ matrixWorld := gr.MatrixWorld()
|
|
|
|
|
+ sphere.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ if !rc.IsIntersectionSphere(&sphere) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Copy ray and transform to model coordinates
|
|
|
|
|
+ // This ray will will also be used to check intersects with
|
|
|
|
|
+ // the geometry, as is much less expensive to transform the
|
|
|
|
|
+ // ray to model coordinates than the geometry to world coordinates.
|
|
|
|
|
+ var inverseMatrix math32.Matrix4
|
|
|
|
|
+ var ray math32.Ray
|
|
|
|
|
+ inverseMatrix.GetInverse(&matrixWorld)
|
|
|
|
|
+ ray.Copy(&rc.Ray).ApplyMatrix4(&inverseMatrix)
|
|
|
|
|
+
|
|
|
|
|
+ var vstart math32.Vector3
|
|
|
|
|
+ var vend math32.Vector3
|
|
|
|
|
+ var interSegment math32.Vector3
|
|
|
|
|
+ var interRay math32.Vector3
|
|
|
|
|
+
|
|
|
|
|
+ // Get geometry positions and indices buffers
|
|
|
|
|
+ vboPos := geom.VBO(gls.VertexPosition)
|
|
|
|
|
+ if vboPos == nil {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ positions := vboPos.Buffer()
|
|
|
|
|
+ indices := geom.Indices()
|
|
|
|
|
+ precisionSq := rc.LinePrecision * rc.LinePrecision
|
|
|
|
|
+
|
|
|
|
|
+ // Checks intersection with individual lines for indexed geometry
|
|
|
|
|
+ if indices.Size() > 0 {
|
|
|
|
|
+ for i := 0; i < indices.Size()-1; i += step {
|
|
|
|
|
+ // Calculates distance from ray to this line segment
|
|
|
|
|
+ a := indices[i]
|
|
|
|
|
+ b := indices[i+1]
|
|
|
|
|
+ positions.GetVector3(int(3*a), &vstart)
|
|
|
|
|
+ positions.GetVector3(int(3*b), &vend)
|
|
|
|
|
+ distSq := ray.DistanceSqToSegment(&vstart, &vend, &interRay, &interSegment)
|
|
|
|
|
+ if distSq > precisionSq {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ // Move back to world coordinates for distance calculation
|
|
|
|
|
+ interRay.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ origin := rc.Ray.Origin()
|
|
|
|
|
+ distance := origin.DistanceTo(&interRay)
|
|
|
|
|
+ if distance < rc.Near || distance > rc.Far {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ interSegment.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ *intersects = append(*intersects, Intersect{
|
|
|
|
|
+ Distance: distance,
|
|
|
|
|
+ Point: interSegment,
|
|
|
|
|
+ Index: uint32(i),
|
|
|
|
|
+ Object: igr,
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ // Checks intersection with individual lines for NON indexed geometry
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for i := 0; i < positions.Size()/3-1; i += step {
|
|
|
|
|
+ positions.GetVector3(int(3*i), &vstart)
|
|
|
|
|
+ positions.GetVector3(int(3*i+3), &vend)
|
|
|
|
|
+ distSq := ray.DistanceSqToSegment(&vstart, &vend, &interRay, &interSegment)
|
|
|
|
|
+ if distSq > precisionSq {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Move back to world coordinates for distance calculation
|
|
|
|
|
+ interRay.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ origin := rc.Ray.Origin()
|
|
|
|
|
+ distance := origin.DistanceTo(&interRay)
|
|
|
|
|
+ if distance < rc.Near || distance > rc.Far {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ interSegment.ApplyMatrix4(&matrixWorld)
|
|
|
|
|
+ *intersects = append(*intersects, Intersect{
|
|
|
|
|
+ Distance: distance,
|
|
|
|
|
+ Point: interSegment,
|
|
|
|
|
+ Index: uint32(i),
|
|
|
|
|
+ Object: igr,
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|