Reflecting a beam problem Created 1 year ago2023-02-05 18:57:01 UTC by nikenzzy nikenzzy

Created 1 year ago2023-02-05 18:57:01 UTC by nikenzzy nikenzzy

Posted 1 year ago2023-02-05 18:57:01 UTC Post #347301
Hi, so i am having fun with sdk and i am trying to reflect a beam when it hits a wall. So my approach is this:

1. Get normalized beam vector and normalized hit plane normal vector.
2. Find first orthogonal vector from cross product between beam vector and plane normal vector. This one represents z-axis in the new vector basis while plane normal vector represents x-axis in the new vector basis. Find second orthogonal vector from cross product between first orthogonal vector and the plane normal vector. This new vector represents y-axis in the new vector basis.
3. Create a Change to Basis Matrix from plane normal vector, first orthogonal vector and second orthogonal vector columns, in that order. Also calculate its inverse.
4. Create a composite matrix by multiplying Inverse Change to Basis Matrix, X-axis Mirror Transformation Matrix(mirroring a beam vector in regards to plane normal vector) and Change to Basis Matrix, in that order.
5. Transform beam vector with calculated transformation matrix. A new vector should be a reflected vector.

While testing, i found out it does properly reflect in certain situations, but it does not i others. What i understood is that it never reflects correctly when neither of new basis vectors is perpendicular to either of the global basis vectors (1,0,0), (0,1,0), (0,0,1). However, if one of the new basis vectors is perpendicular to a certain global basis vector, it might reflect correctly. I checked my matrix methods (inverse, multiplication...) and they all work correctly. I also tried a formula that rotates a vector around another vector, but that also does not work. So i am stuck.
void CTripmineGrenade::ReflectBeam(const Vector& vecStart, Vector beamDir, Vector planeNormal, Vector playerPos)
{
    Vector vecOrthoX = planeNormal.Normalize();
    Vector vecOrthoZ = CrossProduct(-beamDir.Normalize(), vecOrthoX).Normalize();
    Vector vecOrthoY = CrossProduct(vecOrthoZ, vecOrthoX).Normalize();

    float* changeToBasis = VectorsToMatrix(vecOrthoX, vecOrthoY, vecOrthoZ);
    float* inverted_changeToBasis = InvertMatrix(changeToBasis);

    float* transformMatrix = MultiplyMatrix(MultiplyMatrix(inverted_changeToBasis, GetX_AxisMirrorMatrix()), changeToBasis);
    Vector newVecDir = TransformVector(-beamDir.Normalize(), transformMatrix);

    Vector test_end = RotateVectorAroundAxisVector(-beamDir.Normalize(), vecOrthoZ, GetAngleBetweenVectors(-beamDir.Normalize(), vecOrthoX) * 2);

    m_pReflectedBeam = CBeam::BeamCreate(g_pModelNameLaser2, 10);
    m_pReflectedBeam->PointsInit(vecStart, vecStart + test_end * 256);

}
What am i doing wrong? is my approach completely wrong or is there some other problem?
Posted 1 year ago2023-02-06 01:51:37 UTC Post #347303
well from what i noticed in-game, all projectiles such as fragmentation grenades bounce with perfect reflection. as in, their velocity vector is changed accordingly to have a perfect bounce off of the wall or floor (with a bit of basic friction of course, so it slows down with each bounce). if you can find where they programmed bouncing entity physics (i think its MOVETYPE_BOUNCE which tells the entity to bounce when it hits something), you can find whatever perfect reflection formula they may be using to accomplish that.
Posted 1 year ago2023-02-06 13:26:54 UTC Post #347304
There is a way simpler way to get a reflection vector.

Let's construct it piece by piece. Say you have an incoming vector V:
User posted image
And you would like to obtain the reflected vector R:
User posted image
You also happen to know the normal vector of your surface, N:
User posted image
So, we're aiming at something that is roughly the opposite direction of V. We can obtain the dot product of V and N, and it'll give us, well, something for a start:
User posted image
(I'm visualising this rather unconventionally, just note that the dot product will be negative in this instance, something like -0.8)

Now check this out. What if you take that dot product, and multiply V with it in some way? And then add (V*d) on top of N?
User posted image
Hell yeah, we're GETTING somewhere now! (actually you should subtract to get this result, because remember, the dot product is negative in this case)

Now, this is not actually it. Instead of N - V*d let's actually try -2N*d + V and see what happens:
User posted image
This expression can be simplified a bit: V - 2*N*d

So yeah, there's your formula right there.
const float doubleDot = 2.0f * direction.Dot( normal );
return direction - (doubleDot * normal);
If you don't believe me, here's how some engines & maths libraries do it:
https://github.com/godotengine/godot/blob/master/core/math/vector3.h#L516 -> Godot game engine
https://github.com/g-truc/glm/blob/master/glm/detail/func_geometric.inl#L104 -> GLM maths library
I'm surprised this isn't present in some engines & physics engines I know.

What you can do next is also add a bias that multiplies the influence of the normal:
Vector Reflect( const Vector& normal, float normalBias = 1.0f )
{
   const float doubleDot = 2.0f * normalBias * Dot( normal );
   return *this - (doubleDot * normal);
}
And then have a random number on each bounce to simulate surface imperfections. I guess you don't want that, but it's just a fun thought.

Also I honestly don't know how people came up with the exact formula, and I don't know myself, but through experimentation it eventually makes somewhat of a sense. No wonder I'm failing Maths in college lmao. But yeah, hope this helps!
Admer456 Admer456If it ain't broken, don't fox it!
You must be logged in to post a response.