Volume raycast example

I was playing around with volume raycast and decided to write an example. The code creates a volume area max X max X max size. It creates 4 random volume cubes (green) in that area. From the raycast origin 0,0,0 (red cube in closest corner) it scans 3 areas looking for a cube. The first area is the imaginary wall to the right. The second is to the left. The third is the ceiling. When the raycast hits a cube, it prints out its location for that area. If a cube happens to appear on the boundary between the walls or wall and ceiling it will print in both areas. When printing, it can show multiple hits. Depending on how close a cube is to the origin, it can be hit multiple times during a scan area.

If you have questions about what I’m doing, just ask. It was confusing how raycast was working when I started writing this, but it makes sense to me now.


viewer.mode=STANDARD

function setup() 
    assert(OrbitViewer, "Please include Cameras as a dependency")
    
    scene=craft.scene()
    craft.scene.main=scene  -- elimates draw function
        
    v=scene.camera:add(OrbitViewer,vec3(10,0,0),300,0,800)
    v.rx=10
    v.ry=45
    
    scene.voxels.blocks:addAssetPack("Blocks") 
    
    scene.voxels:resize(vec3(16,1,16))          
    scene.voxels.coordinates=vec3(40,0,40) 
    
    max=100
    
    -- create volume area, max x max x max
    volume=scene:entity():add(craft.volume,max,max,max)
    print("volume size  "..max.."x"..max.."x"..max)
    
    -- draw voxel floor  max x max
    scene.voxels:fill(BLOCK_NAME,"Solid",COLOR,color(228, 175, 103))
    scene.voxels:box(0,0,0,max,0,max)
    
    -- set origin value
    origin=vec3(0,0,0)
    
    -- draw 4 random volume cubes
    print("4 random volume cubes =====")
    for x=1,4 do    
        c=vec3(math.random(max-1),math.random(max-1),math.random(max-1))
        volume:set(c.x,c.y,c.z,COLOR,color(0, 255, 196),BLOCK_NAME,"Solid")
        print(c.x.." "..c.y.." "..c.z)
    end
    print("============")
    
    -- do a raycast range on 3 areas
    print("scan right wall ======")
    for x=0,max do   -- right wall
        for y=0,max do
            maxDist=math.sqrt(x^2+y^2+max^2)-1
            doRaycast(origin,vec3(x,y,max),maxDist)
        end
    end
    
    print("scan left wall ======")
    for y=0,max do   -- left wall
        for z=0,max do
            maxDist=math.sqrt(max^2+y^2+z^2)-1
            doRaycast(origin,vec3(max,y,z),maxDist)
        end
    end
    
    print("scan ceiling ======")
    for x=0,max do   -- ceiling        
        for z=0,max do
            maxDist=math.sqrt(x^2+max^2+z^2)-1
            doRaycast(origin,vec3(x,max,z),maxDist)
        end
    end
    
    -- draw the origin box
    scene.voxels:fill(BLOCK_NAME,"Solid",COLOR,color(255, 19, 0))
    scene.voxels:block(origin)
end

function doRaycast(origin,dir,dist)
    volume:raycast(origin,dir,dist, 
    function(coord, id, face)
        if coord and id ~= 0 then
            print(coord)
            return true
        end
    end)
end

@dave1707 - interesting, always seemed to hit the cube in the corner which is odd. Also the length of the beam, I’m assuming is max, restricts you to hits depending on the starting point and angle. Putting in 200 for max took ages and 500 threw out an error.

I assume the green cubes are where the beam ended without hitting a plane and the red where it does.

@Bri_G The red cube in the corner is the origin or starting point of each raycast. The 4 green cubes are the random cubes that the raycast is supposed to find. I print their 4 values when they’re created. When the raycast sweeps out an area, it will print the x,y,z position of the cube it finds. The length of the raycast is maxDist. If raycast hits the wall of the volume area, it registers a hit at that position which would be a false hit. The maxDist stops the raycast just short of hitting the wall. That distance changes as it sweeps each position of the imaginary wall. Raycast doesn’t use angles but goes in an x,y,z direction. So I send a raycast out to each x,y,z position of an imaginary wall and if it hits one of the random cubes, it prints the x,y,z cube position. Those should match the 4 x,y,z values printed at the start.

I tried a size of 200 and it took about 20 seconds. I tried a size of 500 and got a bad_alloc error message.

I’m probably not explaining what’s happening very well, so if you have more questions just ask.