[SOLVED] Rotate vector by random max degree

Whats the best way to rotate a vector randomly within a limited angle?

For example, imagine a FPS game where you aim at a certain direction, but when firing a bullet it will shoot at the general aim direction but with a random offset up to 15 degrees angle from the original direction.

Thanks!

The easiest and fail safe solution is to create a Matrix, like for example

Matrix rot = Matrix.CreateRotationZ( randomAngle) and then transform the vector with Vector3.Transform(rot);

However, you can also use some trigonometry and create normal vectors that you add to your base vector to skew it to the given direction. Remember to normalize and multiply with the original length afterwards.

Mathematically you could visualize the problem as cone which represents the spread of fire. A bullet can be thought of as travelling any ray that is contained inside the cone. Even this is pretty unrealistic but may make for fun mechanics.

Use the random class to get a floating point, multiply by 2 and subtract 1 to get a value from -1 to +1.
var rnd = random.Sample()*2-1;

then multiply this with the angle to get an angle from -15 to +15 and add that to your target vector.
var offsetAngle = rnd*15;

But will be unrealistic because the offset is distributed evenly between -15 to 15. To get a more bell-like distribution concentrated to the center, multiply rand with itself a few times.
rnd = rnd * rnd * rnd;
var offsetAngle = rnd*15;

If you choice to use an odd number of multiplications (ex: rnd = rnd * rnd;) you need to preserve the sign. (Math.Sign() maybe?)

Now, if you are going for that cone effect, you need one more random number to rotate the offset 360 degrees around.

    private static S.Random __Random = new S.Random();
    private static int __RandTick = S.Environment.TickCount;



    /// <summary>
    /// Get random POINT position from RADIUS range 
    /// </summary>
    /// <param name="radius">Radius size</param>
    /// <param name="length">Arch length 0 - 360</param>
    /// <param name="addToSeed">Add seed increment</param>
    /// <returns>Returns random position within radius</returns>
    public static Z3DC.DPoint RANDOM_P(float radius, float length, int addToSeed)
    {
        __RandTick = __RandTick + S.Environment.TickCount + addToSeed;
        __Random = null;   __Random = new S.Random(__RandTick);

        double m_Ang = __Random.NextDouble() * S.Math.PI * 2;

        return new Z3DC.DPoint
            (
                (float)S.Math.Cos(m_Ang) * radius,
                (float)S.Math.Sin(m_Ang) * radius + length
            );
    }

Thanks for the tips everybody, I actually wanted the ability to have different random on different axis, I though maybe there’s a simple way to do it. Anyway ended up doing something like this:

    /// <summary>
    /// Random vector direction.
    /// </summary>
    protected Vector3 RandDirection(Vector3 baseVector, Vector3 randDir)
    {
        float originalLen = baseVector.Length();
        Vector3 newVelocity = baseVector;
        newVelocity.X += (float)(Random.NextDouble() * randDir.X - Random.NextDouble() * randDir.X);
        newVelocity.Y += (float)(Random.NextDouble() * randDir.Y - Random.NextDouble() * randDir.Y);
        newVelocity.Z += (float)(Random.NextDouble() * randDir.Z - Random.NextDouble() * randDir.Z);
        newVelocity.Normalize();
        return newVelocity * originalLen;
    }

Which appears to be working pretty well for now… :slight_smile:

2 Likes