Wiki

Clone wiki

PolyVox / Computing the exact endpoint of a raycast


Last tested version of PolyVox: Unknown


lets assume you have a

PolyVox::Vector3DFloat position;

as a starting position (e.g. the eye of your player, not an integer voxel coordinate, but an actual float position inside a voxel)

and a

PolyVox::Vector3DFloat direction

for direction and raylength(if you have just a direction vector, normalize it and multiply by your desired raycasting distance)

You then perform your raycast:

PolyVox::RaycastResult result;
PolyVox::Raycast<YourVolumeType, YourVoxelType> raycaster(pVolumePointer, position, direction, result);
raycaster.execute();

We now construct 3 planes on the sides of the voxel that are far from the ray-start-position and intersect our ray with all 3 planes. The intersection point with the plane that is hit first is our hit Position.

PolyVox::Vector3DFloat signOfDir({
            (direction.getX() < 0)?(-1.0f):((direction.getX() > 0)?(1.0f):(0)),
            (direction.getY() < 0)?(-1.0f):((direction.getY() > 0)?(1.0f):(0)),
            (direction.getZ() < 0)?(-1.0f):((direction.getZ() > 0)?(1.0f):(0))
            });
        // schoolbook line-plane-intersection formula
        // n1*(p1 + r*u1) + n2*(p2 + r*u2) + n3*(p3 + r*u3) = b
        // for a plane parallel to the yz plane, n3 and n2 are zero and b is the x coordinate, n1 needs to be 1 then, as [n1, n2, n3] is a normal
        // the plane x coordinate  is the hit position + 0.5 units in the x-direction of the ray
        // position.getX() + r*direction.getX() = result.previousPosition.getX() + signOfDir.getX()*0.5
        // solved for r
        // r = (result.previousPosition.getX() + signOfDir.getX()*0.5 - position.getX())/direction.getX();
        // PolyVox vectors allow this to be done in one line for all 3 planes
        PolyVox::Vector3DFloat r = (PolyVox::Vector3DFloat(result.previousPosition) + signOfDir*float(0.5) - position)/direction;
        PolyVox::Vector3DFloat hitPos, hitNormal;
        // the shortest ray is our hit position.
        if(r.getX() < r.getY() && r.getX() < r.getZ()) {
            m_hitPos = position + direction*r.getX();
            m_hitNormal = {-signOfDir.getX(), 0, 0};
        } else if(r.getY() < r.getZ()) {
            m_hitPos = position + direction*r.getY();
            m_hitNormal = {0, -signOfDir.getY(), 0};
        } else {
            m_hitPos = position + direction*r.getZ();
            m_hitNormal = {0, 0, -signOfDir.getZ()};
        }

Updated