Zylann / godot_voxel

Voxel module for Godot Engine
MIT License
2.71k stars 251 forks source link

most of times raycast3d dont detect collision with terrain and when detect collision most of times dont make hole in terrain #677

Closed se8820726 closed 3 months ago

se8820726 commented 3 months ago

this is main scene structure:

image

this is voxel terrain config:

image

my character throws projectiles to the terrain.

projectile code:


extends Node3D

@export var ray: RayCast3D
@onready var _terrain: VoxelTerrain = get_parent().get_node("VoxelTerrain")

var checkCollide:=true
var _radius := 50.0
var speed = 300.0

func _ready():
    top_level =true

func _process(delta):
    position+=transform.basis*Vector3(0,0,-speed)*delta

    if checkCollide and ray.is_colliding():

        checkCollide = false
        var pointed_pos := ray.get_collision_point()

        do_sphere(pointed_pos, _radius, false)
        await get_tree().create_timer(1.0).timeout

        queue_free()

func do_sphere(center: Vector3, radius: float, add: bool):
    var vt := _terrain.get_voxel_tool()
    if add:
        vt.mode = VoxelTool.MODE_ADD
    else:
        vt.mode = VoxelTool.MODE_REMOVE
    vt.set_sdf_scale(0.002)
    vt.do_sphere(center, radius)
    print(center)

func _on_timer_timeout():
    queue_free()

projectile scene tree:

image

and when collision detects make a hole in the terrain by calling function _dosphere

projectile have a raycast3d node and by it i will detect collision. but in most of times dont detect collision and didnt make hole in terrain. i think maybe its problem is by terrain collision generator also most of times after detect collision the function _dosphere will fire but dont make any hole in terrain

this is whole of project: godot voxel.zip

Zylann commented 3 months ago

vt.set_sdf_scale(0.002)

You should not need this. If you saw an example do that, it's likely out of date. It used to be needed in the past because SDF data was scaled in some situations to fit better into 16-bit fixed-point encoding, but it was inconsistent and confusing, so I made VoxelTool account for that automatic some time ago. Right now that scale create artefacts, remving that line fixes them.

func _process(delta): position+=transform.basisVector3(0,0,-speed)delta

I recommend you move your projectile in _physics_process, because collision detection is involved.

I tried your project and I think your projectile is simply too fast. You're running into a classic issue in collision detection, which is tunnelling. Refer to what I described somewhere in here: https://github.com/Zylann/godot_voxel/issues/676#issuecomment-2236392681 You have to lower the speed of your projectile, or make your raycast longer, at minimum it should have the the length it travels between two physics frames, otherwise it risks passing through mesh colliders. With a speed of 300, I would assume it would travel 5 meters per frame, and your current length is 2, so it will pass through very often (in fact even with 10 it has a hard time hitting anything. And that's not a VoxelTerrain issue, colliders are Godot's). Sometimes it will even hit a surface behind the wall you stand in front of.

Finally, your projectile has a VoxelViewer. For something that moves so fast, this is a very bad idea. While that indeed makes voxels load around them, it is a relatively expensive process, so there will be times where it might hit and dig a sphere, but not actually be able to remesh the area right away because of the overload it's produced by generating chunks at high speed. It's also quite slow to show the result because colliders are still built on the main thread. If you print the contents of VoxelEngine.get_stats() you will find that each projectile you fire causes thousands of tasks to go pending. VoxelViewers are meant to be attached to players and maybe some localized points of interest, not on super-fast moving or numerous things, they are expensive. Considering you're using VoxelTerrain, colliders will load for every chunk you can see. So if your projectile hits a chunk you can see, it doesn't need a VoxelViewer at all.

After removing the VoxelViewer, removed the SDF scaling, increased raycast length to 20: https://github.com/user-attachments/assets/d25b78b5-05c3-481b-8667-0a0e226245c0

se8820726 commented 3 months ago

thank you problem solved i removed the VoxelViewer, removed the SDF scaling, increased raycast length to 20