javascriptmathvectorgame-engineraytracing

Ray bouncing: How to invert a velocity vector to represent a perfect bounce?


I'm working on a voxel raytracing system in JavaScript, which odd as it may sound is quite doable in a simple form. I'm trying to figure out how to make a virtual ray bounce and can't quite wrap my mind around the algorithm.

The concept is simple: Each ray is a virtual point with two properties, a position and a velocity, both stored as an x, y, z vector which is a dictionary. Each tick the velocity is added to the position, voxels at the new point are also searched at that point. The relevant part is something among the lines of:

for(let step = 0; step < dist_max; step++) {
    pos.x += vel.x;
    pos.y += vel.y;
    pos.z += vel.z;
    if(solid_at(pos)) {
        // A voxel was hit
    }
}

When a successful hit occurs, I need to do something to vel to reverse the direction of the ray and make it bounce like a rubber ball. Without making it lose or gain speed just change its direction. The surface can be considered to have no angle so no need to take any collider properties into account, it only needs to bounce as if it hits a flat plane facing right toward the ray... it would be useful if an amount between 0 and 1 can control how much the effect is applied so semi-transparent voxels may reflect / refract accordingly.

Clearly the secret isn't to multiply all of the velocity by -1 as that would only make it go backwards: I think I need to invert just one or two of its axes, or swap the velocity of one axis with that of another. But how do I know which should be flipped when the ray could be going in any direction and have any amount of velocity in either X and Y and Z both positive or negative?


Solution

  • In the end I solved this the simple way: Whenever a voxel is updated, the point checks its neighbors and stores new normals. Normals is a mere list of 6 boolean entries, representing if the space in that axis is empty for -X +X -Y +Y -Z +Z. The ray simply checks this dictionary and if a location is clear decides whether it can bounce in that direction or not. It can even flip the ray on multiple axes at once if it's a corner voxel.

    if vel_x > 0 and mat.normals[0]:
        vel_x *= -1
    elif vel_x < 0 and mat.normals[1]:
        vel_x *= -1
    if vel_y > 0 and mat.normals[2]:
        vel_y *= -1
    elif vel_y < 0 and mat.normals[3]:
        vel_y *= -1
    if vel_z > 0 and mat.normals[4]:
        vel_z *= -1
    elif vel_z < 0 and mat.normals[5]:
        vel_z *= -1