Bullet bounce: Mirroring a vector across a normal

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
fennec
Posts: 55
Joined: Fri Oct 10, 2008 7:23 am

Bullet bounce: Mirroring a vector across a normal

Post by fennec »

I'm trying to make a bullet bounce off terrain. I can imagine what needs to be done, but cannot quite figure out the math.

On impact, the bullet's movement is described by a vector for it's X,Y and Z velocity. The terrain triangle it hits is described by a vector, that I normalize. Somehow I need to multiply or add or do some kind of magic to these things to get the bullet's resulting bounced vector.

Image

I imagine I could solve for the XYZ rotations of the bullet and terrain and figure it out that way, but I'm hoping there's a simple way to do it with the vectors themselves.

Any help greatly appreciated.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Code: Select all

// Include the Irrlicht header
#include "irrlicht.h"
#include <assert.h>

#pragma comment(lib, "Irrlicht.lib")

// Irrlicht Namespaces
using namespace irr;
using namespace core;

vector3df reflectVectorFromSurface(const vector3df & incident,
                                   const vector3df & surfaceNormal)
{
    vector3df reflection(incident);

    const f32 dot = vector3df(reflection).normalize().dotProduct(vector3df(surfaceNormal).normalize());

    // I'm assuming that the surface is double sided, and that rays coming from inside it
    // are reflected internally.  If you want to make it single sided, perform this check.
    //if(dot > 0.f)
    //    return incident;

    // Otherwise, we have to reject parallel vectors or we get NaN results.
    if(equals(dot, 1.f))
        return incident;

    // Pretend that it's being emitted from the surface.
    reflection.invert();

    quaternion MrQuaternion;

    // Calculate the quaternion that will rotate the (inverted) incident to match the normal.
    (void)MrQuaternion.rotationFromTo(reflection, surfaceNormal);

    // Make it a matrix
    matrix4 rotationMatrix;
    MrQuaternion.getMatrix(rotationMatrix);

    // And apply it twice to the inverted incident vector.
    rotationMatrix.rotateVect(reflection);
    rotationMatrix.rotateVect(reflection);

    return reflection;
}

void testReflection(const vector3df & incident,
                    const vector3df & surfaceNormal,
                    const vector3df & expectedReflection)
{
    vector3df reflection = reflectVectorFromSurface(incident, surfaceNormal);
    (void)printf("Result %f %f %f\n", reflection.X, reflection.Y, reflection.Z);
    assert(reflection == expectedReflection);
}

int main()
{
    testReflection(vector3df(5, 0, 0), vector3df(-1, 0, 1), vector3df(0, 0, 5));

    // This is coming from inside the surface.  We'll reflect it, but it could
    // also be emitted; see the comments in reflectVectorFromSurface()
    testReflection(vector3df(-5, 0, 0), vector3df(-1, 0, 1), vector3df(0, 0, -5));

    // This is coming in orthogonally, so should be reflected directly back.
    testReflection(vector3df(5, 0, -5), vector3df(-1, 0, 1), vector3df(-5, 0, 5));

    // This is perpendicular, so should be emitted unchanged.
    testReflection(vector3df(5, 0, 0), vector3df(1, 0, 0), vector3df(5, 0, 0));
} 
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
fennec
Posts: 55
Joined: Fri Oct 10, 2008 7:23 am

Post by fennec »

I can't thank you enough, it works perfect. You should be paid for this support :) (but don't look at me, I'm poor)

Normalizing the normal garbles the result sometimes (flips it down into the ground), so I don't.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

fennec wrote:I can't thank you enough, it works perfect. You should be paid for this support :) (but don't look at me, I'm poor)
Great, I'm happy that this was useful. It's always a pleasure to answer such a clearly defined question.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
fennec
Posts: 55
Joined: Fri Oct 10, 2008 7:23 am

Post by fennec »

Really? You will be hearing more from me then Image

And the result: http://members.shaw.ca/evilgryphon1/bounce.avi
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

nice one fennec, your game seems to be coming along pretty well!
Image Image Image
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Remember our friend the dot product? For vectors A and B, A.dotProduct(B) gives us the length of the projection of A on B. We can use this to provide a much simpler calculation to get the same result...

Code: Select all

core::vector3df reflect(const core::vector3df& v, const core::vector3df& n)
{
    // n is assumed to be normalized
    // v should not be normalized
    // v should not be perpendicular to n
    return v - (2 * v.dotProduct(n)) * n;
}

core::vector3df reflect_s(const core::vector3df& v, core::vector3df n)
{
    // n is assumed to not be normalized
    // v should not be normalized
    // v should not be perpendicular to n
    n.normalize();
    return reflect(v, n);
}
Travis
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Much obliged, sir. The one time that I don't add a disclaimer that Vitek or hybrid will do the same thing in 2 lines of code... ;)

I was thinking that in this case that the ricochet would look more realistic if it came off at a random angle. One way of doing that - Vitek will probably do the same thing in 2 line of code - would be to rotate around the normal by a psuedo-random angle that's weighted towards 180 degrees. This will produce a partial cone of scatters, which might look all right as the basis of a random scatter. Reducing the velocity (I suggest applying a random reducing scale to Y) should also add some realism.

Code: Select all

#include "irrlicht.h"

#pragma comment(lib, "Irrlicht.lib")

// Irrlicht Namespaces
using namespace irr;
using namespace core;

vector3df randomlyFeflectVectorFromSurface(const vector3df & incident,
                                           const vector3df & normalisedSurfaceNormal)
{
    vector3df reflection(incident);
    reflection.invert();

	const f32 rotationAngle = 
		(f32)(90 + (rand() % 61) + (rand() % 61) + (rand() % 61)) * DEGTORAD;

    quaternion MrQuaternion;
	MrQuaternion.fromAngleAxis(rotationAngle, normalisedSurfaceNormal);

    matrix4 rotationMatrix;
    MrQuaternion.getMatrix(rotationMatrix);

    rotationMatrix.rotateVect(reflection);

    return reflection;
}

int main()
{
	const vector3df incident(0, 0, 1);
	const vector3df normal(vector3df(0, 1, -1).normalize());
	// So the reflection will be based around (0, 1, 0)

	for(int i = 0; i < 10; ++i)
	{
		const vector3df reflection = randomlyFeflectVectorFromSurface(incident, normal);
		(void)printf("%f %f %f\n", reflection.X, reflection.Y, reflection.Z);
	}
} 
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
fritzgryphon
Posts: 22
Joined: Mon Sep 08, 2008 1:22 am

Post by fritzgryphon »

That will certainly come in handy!

I've got the resultant velocities being reduced by a random value (or in case of Y, sometimes increasing), and the drag coefficient increasing a random amount after each impact.

Of course, rather than random, all of these things should be affected by the incidence angle of the impact (more perpendicular = more speed loss & more scatter). More importantly, the incidence angle is needed to determine if the bullet should bounce in the first place.

I'll see if I can figure that one out before one of you does all my work for me :)
Post Reply