world view ray casting
This commit is contained in:
parent
3595c32ae5
commit
c2a69d7cd0
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"edgaru089.ml/go/gl01/internal/igwrap"
|
||||
"edgaru089.ml/go/gl01/internal/igwrap/backend"
|
||||
"edgaru089.ml/go/gl01/internal/io"
|
||||
"edgaru089.ml/go/gl01/internal/render"
|
||||
@ -249,6 +250,10 @@ func (g *Game) Update(win *glfw.Window, delta time.Duration) {
|
||||
imgui.ShowDemoWindow(nil)
|
||||
g.imgui()
|
||||
|
||||
if ok, bc, face, _, _ := g.world.CastViewRay(io.ViewPos, io.ViewDir.Normalize(), 10); ok {
|
||||
igwrap.TextBackground("Looking At: (%d %d %d) facing %s", bc[0], bc[1], bc[2], itype.DirectionName[face])
|
||||
}
|
||||
|
||||
io.Diagnostics.Times.GUI = clock.Restart()
|
||||
}
|
||||
|
||||
|
@ -35,3 +35,54 @@ var DirectionVecd = [6]Vec3d{
|
||||
ZPlus: {0, 0, 1},
|
||||
ZMinus: {0, 0, -1},
|
||||
}
|
||||
var DirectionName = [6]string{
|
||||
"X+",
|
||||
"X-",
|
||||
"Y+",
|
||||
"Y-",
|
||||
"Z+",
|
||||
"Z-",
|
||||
}
|
||||
|
||||
func (d Direction) Opposite() Direction {
|
||||
switch d {
|
||||
case XPlus:
|
||||
return XMinus
|
||||
case XMinus:
|
||||
return XPlus
|
||||
case YPlus:
|
||||
return YMinus
|
||||
case YMinus:
|
||||
return YPlus
|
||||
case ZPlus:
|
||||
return ZMinus
|
||||
case ZMinus:
|
||||
return ZPlus
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// DirectionIs returns X/Y/Z for 0/1/2, and +/- for #pos/neg.
|
||||
func DirectionIs(index int, positive bool) Direction {
|
||||
switch index {
|
||||
case 0:
|
||||
if positive {
|
||||
return XPlus
|
||||
} else {
|
||||
return XMinus
|
||||
}
|
||||
case 1:
|
||||
if positive {
|
||||
return YPlus
|
||||
} else {
|
||||
return YMinus
|
||||
}
|
||||
case 2:
|
||||
if positive {
|
||||
return ZPlus
|
||||
} else {
|
||||
return ZMinus
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
@ -155,3 +155,51 @@ func (box1 Boxd) Intersect(box2 Boxd) (ok bool, intersect Boxd) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func between(val, min, max float64) bool {
|
||||
return min <= val && val <= max
|
||||
}
|
||||
|
||||
// IntersectRay computes if a Box intersects with a ray.
|
||||
// #dir must be normalized, otherwise it's garbage-in garbage-out.
|
||||
func (box Boxd) IntersectRay(start, dir Vec3d, length float64) (ok bool, hitface Direction, where Vec3d, dist float64) {
|
||||
// https://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms
|
||||
if box.Contains(start) {
|
||||
return true, XPlus, start, 0
|
||||
}
|
||||
|
||||
min, max := box.MinPoint(), box.MaxPoint()
|
||||
|
||||
var t Vec3d
|
||||
for i := 0; i < 3; i++ {
|
||||
if dir[i] > 0 {
|
||||
t[i] = (min[i] - start[i]) / dir[i]
|
||||
} else {
|
||||
t[i] = (max[i] - start[i]) / dir[i]
|
||||
}
|
||||
}
|
||||
|
||||
maxi := 0
|
||||
for i, ti := range t {
|
||||
if ti > t[maxi] {
|
||||
maxi = i
|
||||
}
|
||||
}
|
||||
|
||||
if between(t[maxi], 0, length) {
|
||||
pt := start.Add(dir.Multiply(t[maxi]))
|
||||
|
||||
o1 := (maxi + 1) % 3
|
||||
o2 := (maxi + 1) % 3
|
||||
|
||||
if between(pt[o1], min[o1], max[o1]) && between(pt[o2], min[o2], max[o2]) {
|
||||
ok = true
|
||||
hitface = DirectionIs(maxi, dir[maxi] < 0)
|
||||
where = pt
|
||||
dist = t[maxi]
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ type BlockAppearance struct {
|
||||
Light int // The light level it emits, 0 is none
|
||||
|
||||
Hitbox []itype.Boxd // Hitbox, in block-local coordinates; empty slice means a default hitbox of 1x1x1
|
||||
Lookbox []itype.Boxd // Selection hitbox, hit only by the view ray; empty means Hitbox[]
|
||||
|
||||
RenderType BlockRenderType // Rendering type, defaults to OneTexture (zero value)
|
||||
|
||||
@ -130,6 +131,9 @@ func GetBlockAppearance(position itype.Vec3i, id, aux int, data itype.Dataset, w
|
||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||
}}
|
||||
}
|
||||
if len(app.Lookbox) == 0 {
|
||||
app.Lookbox = app.Hitbox
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
@ -146,6 +150,9 @@ func GetBlockAppearance(position itype.Vec3i, id, aux int, data itype.Dataset, w
|
||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||
}}
|
||||
}
|
||||
if len(app.Lookbox) == 0 {
|
||||
app.Lookbox = app.Hitbox
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
@ -172,6 +179,16 @@ func (b Block) Appearance(position itype.Vec3i) BlockAppearance {
|
||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||
}}
|
||||
}
|
||||
if len(app.Lookbox) == 0 {
|
||||
if len(app.Hitbox) == 0 {
|
||||
app.Lookbox = []itype.Boxd{{
|
||||
OffX: 0, OffY: 0, OffZ: 0,
|
||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||
}}
|
||||
} else {
|
||||
app.Lookbox = app.Hitbox
|
||||
}
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
|
48
internal/world/viewray.go
Normal file
48
internal/world/viewray.go
Normal file
@ -0,0 +1,48 @@
|
||||
package world
|
||||
|
||||
import "edgaru089.ml/go/gl01/internal/util/itype"
|
||||
|
||||
// CastViewRay
|
||||
func (w *World) CastViewRay(from, dir itype.Vec3d, maxlen float64) (ok bool, blockcoord itype.Vec3i, face itype.Direction, where itype.Vec3d, dist float64) {
|
||||
|
||||
bfrom := from.Floor()
|
||||
bfromdir := itype.Direction(-1)
|
||||
for bfrom.ToFloat64().Addv(0.5, 0.5, 0.5).Add(from.Negative()).Length() < maxlen {
|
||||
for todir := itype.Direction(0); todir < 6; todir++ {
|
||||
if todir == bfromdir {
|
||||
continue
|
||||
}
|
||||
|
||||
bto := bfrom.Add(itype.DirectionVeci[todir])
|
||||
block := w.Block(bto)
|
||||
|
||||
if block.Id != 0 {
|
||||
outbox := itype.Boxd{
|
||||
OffX: float64(bto[0]),
|
||||
OffY: float64(bto[1]),
|
||||
OffZ: float64(bto[2]),
|
||||
SizeX: 1,
|
||||
SizeY: 1,
|
||||
SizeZ: 1,
|
||||
}
|
||||
var outface itype.Direction
|
||||
if ok, outface, _, _ = outbox.IntersectRay(from, dir, maxlen); ok {
|
||||
app := block.Appearance(bto)
|
||||
for _, lb := range app.Lookbox {
|
||||
if ok, face, where, dist = lb.IntersectRay(from, dir, maxlen); ok {
|
||||
blockcoord = bto
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bfromdir = outface.Opposite()
|
||||
bfrom = bto
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok = false
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user