I'm working on an obstacle avoidance system in unity, and my thought is to cast a sphere along the velocity; if it hits, draw a ring of spheres around that one and repeat until max ring count or a clear path is found.

2D example

2D circle packing

To accomplish this, I'm currently rotating the vector up and then rotating again using the velocity as the axis of rotation, and casting a sphere along the new vector.

working example

enter image description here

This works fine (although I'm not sure how performant it is) until the initial direction is not one of the cardinal directions.

what's happening when things go wrong

enter image description here

My understanding is that after the following line, rotatedVector would be a vector of equal magnitude to ray, but pointing in a new direction that could be described as having rotated about the velocityDirection a number of degrees equal to the magnitude of velocityDirection.

var rotatedVector = Quaternion.Euler(velocityDirection) * ray;

But that only seems to be happening when the velocityDirection is aligned with +- World.up, forward, or right.

Any ideas as to what's happening or how I can accomplish this goal?

Code to DrawGizmos

public int NumRings = 3;
private void OnDrawGizmosSelected()
    Vector3 velocityDirection = transform.forward * MaxSpeed;
    NumRings = Mathf.Clamp(NumRings, 0, 6);

    Gizmos.color = Color.cyan;
    for (int i = 0; i < NumRings; i++) {
        Vector3 rotationAxis = Vector3.Cross(velocityDirection, velocityDirection + Vector3.up).normalized * Mathf.Atan(i*2/ MaxSpeed) * Mathf.Rad2Deg;
        Vector3 probe;
        if (rotationAxis.magnitude > 0) {
            probe = Quaternion.Euler(rotationAxis) * velocityDirection;
        } else {
            probe = velocityDirection;

        int numProbes = i == 0 ? 1 : 6*i;
        rotationAxis = velocityDirection.normalized;
        for (int j = 0; j < numProbes; j++) {
            var test = Quaternion.Euler(rotationAxis * 360 / numProbes * j) * probe;
            Gizmos.DrawLine(transform.position, transform.position + test);
            Gizmos.DrawWireSphere(transform.position + test, 1f);
  • \$\begingroup\$ It looks like you want AngleAxis, not Euler. \$\endgroup\$
    – DMGregory
    Sep 20 at 17:25
  • \$\begingroup\$ @DMGregory That was it! thank you so much! If you'd like to add this as an answer I'd be happy to mark it as correct. If anyone else is interested I changed the line var test to {var test = Quaternion.AngleAxis(360 / numProbes * j, rotationAxis) * probe;} which solved the problem. \$\endgroup\$
    – aLaxCoder
    Sep 20 at 18:52
  • \$\begingroup\$ If you've solved your problem, please post your solution as an Answer below. You might also want to edit your question to ask "How do I rotate one vector around another" since your question seems to be about that and not about the collision avoidance part. \$\endgroup\$
    – DMGregory
    Sep 20 at 19:33

@DMGregory pointed out that the vector rotation function I was looking for was Quaternion.AngleAxis.

Changing var test to the below resulted in the desired behavior.

var test = Quaternion.AngleAxis(360 / numProbes * j, rotationAxis) * probe;

Thanks again @DMGregory


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.