How to interpolate raycasts between frames

[SOLUTION AT BOTTOM]

in my vr game, i added lightsabers. the collision detection uses raycasts to find an object to slice, or they will once I fix this. the lightsaber can move very fast, since the user can swing their hand. i could manually slow it down, but that would be immersion breaking.

when the user swings the saber very fast, like a flick of the wrist, it may completely miss an object like so:

but i have in mind to interpolate between the last and current positions. this SHOULD work, i dont know why, but it just interpolates position and rotation. im testing it with a trail render for a burnout since its going to have that anyways. this is what it should look like:

but it still looks choppy and there does not appear to be any interpolation. all google searches give me results for fast small things like bullets, not fast thin broad objects like a line. any help would be apreciated!

code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Saber : MonoBehaviour
{
    public TrailRenderer burnout;
    public byte steps = 5;
    Vector3 lastPosition = Vector3.zero;
    Quaternion lastRotation = Quaternion.identity;
    // Update is called once per frame
    void Update()
    {
        Vector3 position = transform.position;
        Quaternion rotation = transform.rotation;
        RaycastHit burnoutPoint;
        for (int i = 0; i < steps; i++)
        {
            Vector3 currentPosition = Vector3.Lerp(lastPosition, position, i / steps);
            Quaternion currentRotation = Quaternion.Lerp(lastRotation, rotation, i / steps);
           
            if (Physics.Raycast(currentPosition, currentRotation * Vector3.up, out burnoutPoint, 1.05f))
            {
                burnout.transform.position = burnoutPoint.point - (currentRotation * Vector3.up / 50);
                burnout.AddPosition(burnoutPoint.point - (currentRotation * Vector3.up / 50));
            }
            burnout.emitting = Physics.Raycast(currentPosition, currentRotation * Vector3.up, 1.05f);
        }
        lastPosition = transform.position;
        lastRotation = transform.rotation;
    }
}

-------EDIT BEFORE UPLOAD!-------
if anyone else has this issue, remember to explicitly convert the iterator to a float or double!

Correct example: |
V
Vector3 currentPosition = Vector3.Lerp(lastPosition, position, (float)i / steps);

Incorrect example, causes integer division, rounding to 1 or 0

Vector3 currentPosition = Vector3.Lerp(lastPosition, position, i / steps);

1 Like

You could have written the solution into a seperate post. That generally makes it easier for others to spot the solution ^^.

Though you are right, your issue is most likely the way you calculate the “t” value of the lerps. By doing i / steps where “i” and “steps” are both integers, you’re doing an integer division. The result of an integer division is again an integer. So the result will always be 0 since “steps” is always larger than “i”. Since a float value is required and wanted, at least one of the operands has to be a float. Then the result will be a float as well.

Finally I want to add, if the position and rotation change is purely controlled by the user, you may even use the distance / difference between the current and last position to determine the number of steps you want to apply. This would reduce the overhead if the last position is equal (or almost equal) to the current. If there’s a huge difference you would just crank up the number of steps. Of course when you calculate such a steps value dynamically, you want to clamp the value to reasonable values. A good indicator would be the distance the tip of your sword moves. Say you want to detect objects around the size of 0.1. You could do

var currentTip = rotation * Vector3.forward + position;
var lastTip = lastRotation * Vector3.forward + lastPosition;
var dist = Vector3.Distance(currentTip, lastTip);
steps = Mathf.Clamp(Mathf.CeilToInt(dist / 0.1f), 2, 30);

This assumes that your sword goes along the forward direction (if not, change Vector3.forward to whatever) and also limits the steps to a minumum of 2 and a maximum of 30.

i just implemented something like the spedometer which as you said, jumped my fps from 92 to 120(quest 2 max fps)