github.com/df-mc/dragonfly@v0.9.13/server/block/cube/trace/bbox.go (about) 1 package trace 2 3 import ( 4 "github.com/df-mc/dragonfly/server/block/cube" 5 "github.com/go-gl/mathgl/mgl64" 6 "math" 7 ) 8 9 // BBoxResult is the result of a basic ray trace collision with a bounding box. 10 type BBoxResult struct { 11 bb cube.BBox 12 pos mgl64.Vec3 13 face cube.Face 14 } 15 16 // BBox ... 17 func (r BBoxResult) BBox() cube.BBox { 18 return r.bb 19 } 20 21 // Position ... 22 func (r BBoxResult) Position() mgl64.Vec3 { 23 return r.pos 24 } 25 26 // Face ... 27 func (r BBoxResult) Face() cube.Face { 28 return r.face 29 } 30 31 // BBoxIntercept performs a ray trace and calculates the point on the BBox's edge nearest to the start position that the ray trace 32 // collided with. 33 // BBoxIntercept returns a BBoxResult with the colliding vector closest to the start position, if no colliding point was found, 34 // a zero BBoxResult is returned and ok is false. 35 func BBoxIntercept(bb cube.BBox, start, end mgl64.Vec3) (result BBoxResult, ok bool) { 36 min, max := bb.Min(), bb.Max() 37 v1 := vec3OnLineWithX(start, end, min[0]) 38 v2 := vec3OnLineWithX(start, end, max[0]) 39 v3 := vec3OnLineWithY(start, end, min[1]) 40 v4 := vec3OnLineWithY(start, end, max[1]) 41 v5 := vec3OnLineWithZ(start, end, min[2]) 42 v6 := vec3OnLineWithZ(start, end, max[2]) 43 44 if v1 != nil && !bb.Vec3WithinYZ(*v1) { 45 v1 = nil 46 } 47 if v2 != nil && !bb.Vec3WithinYZ(*v2) { 48 v2 = nil 49 } 50 if v3 != nil && !bb.Vec3WithinXZ(*v3) { 51 v3 = nil 52 } 53 if v4 != nil && !bb.Vec3WithinXZ(*v4) { 54 v4 = nil 55 } 56 if v5 != nil && !bb.Vec3WithinXY(*v5) { 57 v5 = nil 58 } 59 if v6 != nil && !bb.Vec3WithinXY(*v6) { 60 v6 = nil 61 } 62 63 var ( 64 vec *mgl64.Vec3 65 dist = math.MaxFloat64 66 ) 67 68 for _, v := range [...]*mgl64.Vec3{v1, v2, v3, v4, v5, v6} { 69 if v == nil { 70 continue 71 } 72 73 if d := start.Sub(*v).LenSqr(); d < dist { 74 vec = v 75 dist = d 76 } 77 } 78 79 if vec == nil { 80 return 81 } 82 83 var f cube.Face 84 switch vec { 85 case v1: 86 f = cube.FaceWest 87 case v2: 88 f = cube.FaceEast 89 case v3: 90 f = cube.FaceDown 91 case v4: 92 f = cube.FaceUp 93 case v5: 94 f = cube.FaceNorth 95 case v6: 96 f = cube.FaceSouth 97 } 98 99 return BBoxResult{bb: bb, pos: *vec, face: f}, true 100 } 101 102 // vec3OnLineWithX returns an mgl64.Vec3 on the line between mgl64.Vec3 a and b with an X value passed. If no such vec3 103 // could be found, the bool returned is false. 104 func vec3OnLineWithX(a, b mgl64.Vec3, x float64) *mgl64.Vec3 { 105 if mgl64.FloatEqual(b[0], a[0]) { 106 return nil 107 } 108 109 f := (x - a[0]) / (b[0] - a[0]) 110 if f < 0 || f > 1 { 111 return nil 112 } 113 114 return &mgl64.Vec3{x, a[1] + (b[1]-a[1])*f, a[2] + (b[2]-a[2])*f} 115 } 116 117 // vec3OnLineWithY returns an mgl64.Vec3 on the line between mgl64.Vec3 a and b with a Y value passed. If no such vec3 118 // could be found, the bool returned is false. 119 func vec3OnLineWithY(a, b mgl64.Vec3, y float64) *mgl64.Vec3 { 120 if mgl64.FloatEqual(a[1], b[1]) { 121 return nil 122 } 123 124 f := (y - a[1]) / (b[1] - a[1]) 125 if f < 0 || f > 1 { 126 return nil 127 } 128 129 return &mgl64.Vec3{a[0] + (b[0]-a[0])*f, y, a[2] + (b[2]-a[2])*f} 130 } 131 132 // vec3OnLineWithZ returns an mgl64.Vec3 on the line between mgl64.Vec3 a and b with a Z value passed. If no such vec3 133 // could be found, the bool returned is false. 134 func vec3OnLineWithZ(a, b mgl64.Vec3, z float64) *mgl64.Vec3 { 135 if mgl64.FloatEqual(a[2], b[2]) { 136 return nil 137 } 138 139 f := (z - a[2]) / (b[2] - a[2]) 140 if f < 0 || f > 1 { 141 return nil 142 } 143 144 return &mgl64.Vec3{a[0] + (b[0]-a[0])*f, a[1] + (b[1]-a[1])*f, z} 145 }