world view ray casting
This commit is contained in:
parent
3595c32ae5
commit
c2a69d7cd0
@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"edgaru089.ml/go/gl01/internal/igwrap"
|
||||||
"edgaru089.ml/go/gl01/internal/igwrap/backend"
|
"edgaru089.ml/go/gl01/internal/igwrap/backend"
|
||||||
"edgaru089.ml/go/gl01/internal/io"
|
"edgaru089.ml/go/gl01/internal/io"
|
||||||
"edgaru089.ml/go/gl01/internal/render"
|
"edgaru089.ml/go/gl01/internal/render"
|
||||||
@ -249,6 +250,10 @@ func (g *Game) Update(win *glfw.Window, delta time.Duration) {
|
|||||||
imgui.ShowDemoWindow(nil)
|
imgui.ShowDemoWindow(nil)
|
||||||
g.imgui()
|
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()
|
io.Diagnostics.Times.GUI = clock.Restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,3 +35,54 @@ var DirectionVecd = [6]Vec3d{
|
|||||||
ZPlus: {0, 0, 1},
|
ZPlus: {0, 0, 1},
|
||||||
ZMinus: {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
|
||||||
|
}
|
||||||
|
@ -23,7 +23,8 @@ type BlockAppearance struct {
|
|||||||
NotSolid bool // Is block not solid, i.e., has no hitbox at all? (this makes the zero value reasonable)
|
NotSolid bool // Is block not solid, i.e., has no hitbox at all? (this makes the zero value reasonable)
|
||||||
Light int // The light level it emits, 0 is none
|
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
|
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)
|
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,
|
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
if len(app.Lookbox) == 0 {
|
||||||
|
app.Lookbox = app.Hitbox
|
||||||
|
}
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +150,9 @@ func GetBlockAppearance(position itype.Vec3i, id, aux int, data itype.Dataset, w
|
|||||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
if len(app.Lookbox) == 0 {
|
||||||
|
app.Lookbox = app.Hitbox
|
||||||
|
}
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +179,16 @@ func (b Block) Appearance(position itype.Vec3i) BlockAppearance {
|
|||||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
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
|
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