Pottus / ColAndreas

Collision Plugin For San Andreas Multiplayer
GNU General Public License v3.0
67 stars 40 forks source link

CA_RayCastLineAngle() #4

Open Pottus opened 9 years ago

Pottus commented 9 years ago

This function needs to be updated to return the correct rx/ry/rz angles for in game objects. I've tried a lot of different things but I am still unsure how to accurately translate the normal to an object rotation in that the object would align perpendicular to the orientation of the collision plane.

I am hoping some math guys out there could figure out the steps to do this correctly it is very important for advanced mapping features.

Crayder commented 9 years ago

Kinda lol moment. I'm completely new to the normals and shit, I came up with the following but it doesn't work. I figured it'd be something along those lines.

stock SurfaceNormals(Float:P1[3], Float:P2[3], Float:P3[3], &Float:normX, &Float:normY, &Float:normZ, &Float:vectX, &Float:vectY, &Float:vectZ)
{
    //Normal of three points?
    normX = (P2[0] - P1[0]) * (P3[0] - P1[0]);
    normY = (P2[1] - P1[1]) * (P3[1] - P1[1]);
    normZ = (P2[2] - P1[2]) * (P3[2] - P1[2]);

    //Make sum of 'vect' come out as 1, it shouldn't be 0.
    vectX = normX / (floatabs(normX) + floatabs(normY) + floatabs(normZ));
    vectY = normY / (floatabs(normX) + floatabs(normY) + floatabs(normZ));
    vectZ = normZ / (floatabs(normX) + floatabs(normY) + floatabs(normZ));
}

stock CA_SurfaceNormals(Float:StartX, Float:StartY, Float:StartZ, Float:EndX, Float:EndY, Float:EndZ, &Float:normX, &Float:normY, &Float:normZ, &Float:vectX, &Float:vectY, &Float:vectZ)
{
    new Float:P1[3], Float:P2[3], Float:P3[3];

    //floatsin(120, degrees) = 0.86602540378443864676372317075294
    //floatcos(120, degrees) = -0.5000000000000000000000000000000
    //floattan(120, degrees) = -1.7320508075688772935274463415059

    //Get three points on a surface (NOT the best method but yea).
    CA_RayCastLine(StartX, StartY, StartZ, 
        EndX + 0.01, EndY + 0.01, EndZ, 
        P1[0], P1[1], P1[2]);
    CA_RayCastLine(StartX, StartY, StartZ, 
        EndX, EndY + 0.01, EndZ + 0.01, 
        P2[0], P2[1], P2[2]);
    CA_RayCastLine(StartX, StartY, StartZ, 
        EndX + 0.01, EndY, EndZ + 0.01, 
        P3[0], P3[1], P3[2]);

    SurfaceNormals(P1, P2, P3, normX, normY, normZ, vectX, vectY, vectZ);
}

The vectors of the CA func always come out to one of the following (it seems):

0, 0, 0
0, 1, 0
0, 0, 1
Pottus commented 9 years ago

It is kind of confusing not to say the least.

Crayder commented 9 years ago

normX = (P2[0] - P1[0]) * (P3[0] - P1[0]); normY = (P2[1] - P1[1]) * (P3[1] - P1[1]); normZ = (P2[2] - P1[2]) * (P3[2] - P1[2]); Is in short: N = (P2-P1)*(P3-P1)

Then for the vectors I'm sure I have it incorrect. Is should be something like: n^=1v/n OR Vx=Nx/(|Nx|+|Ny|+|Nz|) Vy=Ny/(|Nx|+|Ny|+|Nz|) Vz=Nz/(|Nx|+|Ny|+|Nz|)

codectile commented 9 years ago

@Crayder your algorithm is valid for tri-meshes, if you are ray tracing at three different points to get a triangle, you are doing it absolutely wrong. What if the object is a sphere or a hull shape or the traced ray is tangent to the surface ? and your triangle can consist of various other tri-meshes which is totally in accurate.

Getting the normal can be very complicated. Steps:

 • Get the face where the ray has hit
 • Get the vertices of it.
 • calculate the normal using your algorithm.

The main complication here, is getting the hit face and it's vertices.

Crayder commented 9 years ago
  1. I said "(NOT the best method but yea)."
  2. Yes, that is the best way (yours not mine).
codectile commented 9 years ago

Did you google it ? (your method)

If you did, that site might contain information about triangles, which you passed out.

codectile commented 9 years ago

I think there is a way to do it in bullet.

if(rayCall.hasHit()) 
{
    btVector3 normal = rayCall.m_hitNormalWorld;
}

Tell me whether it works or not.

Crayder commented 9 years ago
Did you google it ? (your method)

If you did, that site might contain information about triangles, which you passed out.

Well I googled the small things above; I translated it to x, y, and z.

codectile commented 9 years ago

@Pottus Are you looking for something like this:

Normals

If I got it wrong, then please correct me.

Crayder commented 9 years ago

Yes, that's what he needs.

codectile commented 9 years ago

Okay, so if you want to calculate the angle which is made by the ray and the normal. You have to do this, I guess.

if(rayCall.hasHit()) 
{
    btVector3 normal = rayCall.m_hitNormalWorld.angle(vector); //start or end vector of the ray
}
Pottus commented 9 years ago

Yes picture those lines as objects, I am looking for the correct rotation so that the object would be aligned on the surface perfectly.

I will check you pull requests Saturday thanks, I am away for two days.

codectile commented 9 years ago

Okay, now I get you. I am finding a way for it, looks very difficult though.

Yes, do look at the pull request. I have closed two of them because I did some mistake there. Although, there is one open clean request.

EDIT: I think it can only be done with objects consisting of meshes because you cannot have a vertex on a spherical child shape.

Crayder commented 9 years ago

What do you mean by "spherical child shape"?

I'm pretty sure every object has a triangular mesh, even spheres. Look at JernejL's collision mesh (wireframe) layer in Map Construction, it has triangles for every object's collision. These triangle faces are all you would need to do this. Is it possible to get the three points of the face collided in bullet?

Crayder commented 9 years ago

For example, these two objects: image Their mesh looks like this: image We just need a way to detect the exact face collided and take it's three points (or three points on the face), calculate the normal vectors, convert to angles.

On a side note, has Chris made any progress with loading SA-MP objects? Mumble has been quite the past few days.

codectile commented 9 years ago

All samp objects consist of meshes but not all gta objects contains meshes, I guess. Try to check the wireframe of id 2114 I think it is ball.

Crayder commented 9 years ago

Object 2114 does have a mesh, without a mesh there would be no shape or anything to apply texture to; but, it doesn't have a collision, and without a collision you can't collide with it in GTA, SA-MP, or CA.

There are however three basketball objects. 1946, 2114, and 3065. The first two do not have collisions, the last one does. Here are all three, listed from least to greatest: image Here are their collisions: image And finally, the wireframes: image As you can see, the only basketball that would work from your defensive example is 3065, the only one with a collision (and therefore, a tri-mesh).

codectile commented 9 years ago

Yes, I think renderware consider spherical objects as a polyhedral shape. I am not sure about bullet's consideration. Okay, test it with object, 2887, 19789, 2896, 2942. They don't have meshes at all and they are quite inaccurate in terms of their shape, especially object 2942.

Crayder commented 9 years ago
Yes, I think renderware consider spherical objects as a polyhedral shape. I am not sure about bullet's consideration.

The objects have multiple meshes (i.e. collision mesh, and the other one). Also, spheres are not spheres in terms of gta objects.

Okay, test it with object, 2887, 19789, 2896, 2942. They don't have meshes at all and they are quite inaccurate in terms of their shape, especially object 2942.

Those also have meshes. They are just a few of the exceptional ones that do not have a good collision mesh. SInce their collision mesh is so simplified you could just take three corners and work like a trimesh. You can use any three on the same face, they will all give the same vectors.

codectile commented 9 years ago
The objects have multiple meshes (i.e. collision mesh, and the other one)

What's "the other one" ? EDIT: A single object cannot posses multiple meshes. (either collision mesh or no-collision mesh)

 Also, spheres are not spheres in terms of gta objects.

That's what I said, they are polyhedral.

Those also have meshes. They are just a few of the exceptional ones that do not have a good collision mesh.

No, they do not have collision trimeshes. They only consist of texture mapping meshes, textures and collision volumes.

SInce their collision mesh is so simplified you could just take three corners and work like a trimesh. You can use any three on the same face, they will all give the same vectors.

Well, how will you determine their face ? GTA SA does not provide vertices for collision volumes, just only for meshes.

Crayder commented 9 years ago
Well, how will you determine their face ? GTA SA does not provide vertices for collision volumes, just only for meshes.

If that's your argument, then mine is how will you determine the vertices on the trimesh? Apparently it's being done already or we wouldn't have the RayCastLineAngle function.

What's "the other one" ?
EDIT: A single object cannot posses multiple meshes. (either collision mesh or no-collision mesh)

Obviously they can, you even said so just after you said this:

They only consist of texture mapping meshes, textures and collision volumes.

Exactly. They have both a collision mesh and a texture mesh. Here is my favorite example (other than the 3065's collision vs texture mesh):

  1. Collision (take a guess what this is): image
  2. Texture (surprise, it's a pair of silos): image

Obviously, the texture mesh is not the same as the collision mesh. The collision mesh is what ColAndreas detects. On this silo object RayCastLineAngle actually returns perfect values, just noting.

codectile commented 9 years ago

We can determine the vertices of trimesh, they are actualy provided in .col files. I've answered your "argumentative" question. Now, you answer mine.

For the silos, it clearly shows that they only consist of texture mapping meshes and collision volumes. If it had collision mesh then it should have a convex hull mesh on the top of it.

Crayder commented 9 years ago
We can determine the vertices of trimesh, they are actualy provided in .col files. I've answered your "argumentative" question. Now, you answer mine.

I think you just answered it yourself, no need. If those are provided there must be a way to get the vertices of the quad meshes like that the silos have. Like I said before, the silos return perfect angles, and they do not have a trimesh.

For the silos, it clearly shows that they only consist of texture mapping meshes and collision volumes. If it had collision mesh then it should have a convex hull mesh on the top of it.

The outer box is the collision. So aren't we both correct there?

codectile commented 9 years ago

We shall not say it as a quad mesh (or poly mesh) because old games contains only trimesh. The silos only have a texture mesh and a collision volume. Collision files does not provide vertices for collision volumes and never will, because we actually do not need it and I did not answer myself, I guess. What angles are you talking about ?

The outer box is the collision. So aren't we both correct there?

Kinda, you said it's a mesh and I said, it is a collision volume. mesh =/= collision volume

Crayder commented 9 years ago
mesh =/= collision volume

true

What angles are you talking about ?

The angles returned by RayCastLineAngle, obviously... :P

codectile commented 9 years ago
// Instead of returning the position of collision this will return the rx / ry rotation of the slope (I could use use someone to check over the math here)
native CA_RayCastLineAngle(Float:StartX, Float:StartY, Float:StartZ, Float:EndX, Float:EndY, Float:EndZ, &Float:x, &Float:y, &Float:z, &Float:rx, &Float:ry);

Yea, it returns the slope so it will be accurate. According to me slope is: theta = tan^-1(StartY-y/StartX-x)

Crayder commented 9 years ago

The point of this issue is finding a way to get the 'slope' of all surfaces in the collision. That's why we need three points and a normal. Go to the performRayTestAngle function in DynamicWorld.cpp to see where the current math is. It's only X and Y, but it works in most cases (like the silos for example XD). There are a few surfaces it doesn't work for such as the sides of some buildings, fences, some ground, and other objects.

codectile commented 9 years ago

Yea, I understood now what he meant by slope.

codectile commented 9 years ago

@Pottus is this what you wanted ?

btVector3 hit = rayCall.m_hitPointWorld;
btVector3 normal = rayCall.m_hitNormalWorld;
float angle = hit.angle(normal);
float rX = (hit.getX() * cos(angle)) - (hit.getY() * sin(angle));
float rY = (hit.getY() * cos(angle)) + (hit.getX() * sin(angle));

Oh wait, you need the angles. EDIT: I think rotations need in depth Quaternions and I have no idea about it. But, if you want something like this without user oriented data. Normals

I can try.

Crayder commented 8 years ago

Basically what we need to do is find the rotation needed to make an object parallel to a surface given the surface's normal.

Crayder commented 8 years ago

What we really need is a version of Unity's Quaternion.FromToRotation

That Unity function aligns an axis of an object with a surface normal. This is exactly what we need to do. So, does anyone have the source code of that function? :3

ikkentim commented 8 years ago

https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/math/Quaternion.java

Contains Quaternion functions. I tried decompiling unity, but all Quaternion functions are implemented in C++, and I can't decompile that.

Crayder commented 8 years ago

The closest thing I found to FromToRotation there was getAxisAngle, I don't think it's what we need.

Crayder commented 8 years ago

@Pottus

Perhaps this (4th post) is what we need?

http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=10790

If not maybe you could post there and provide a better explanation.

Crayder commented 8 years ago
rx = acos(nz);
ry = 0.0;
rz = atan2(ny, nx) + 90.0;

I think this is more accurate than the rx/ry version.

nx, ny, nz: Normal Vector rx, ry, rz: Return Rotations

Also, the new mesh fix added in 3c5cfc478f06c7d2991d3aa4b6fc2db2b4d5104b seemed to fix the old normal vector bugs (the one that would cause rotations to be off by a few degrees).

Pottus commented 8 years ago

I don't think that will work right to be honest currently it works when placing objects on the ground.

Crayder commented 8 years ago

It works perfectly, I've tested it a lot and can provide you results.

Here are just a few, taken in multiple directions.

X = 2322.2290, Y = 1254.1141, Z =   58.1086
nX =    0.0000, nY =   -0.7936, nZ =    0.6084
rX =   52.5243, rY =    0.0000, rZ =    0.0000

X = 2353.2312, Y = 1283.3153, Z =   57.5664
nX =    0.7936, nY =    0.0000, nZ =    0.6084
rX =   52.5243, rY =    0.0000, rZ =   90.0000

X = 2275.1169, Y = 1600.4102, Z =   99.8516
nX =   -0.0003, nY =   -0.5418, nZ =    0.8404
rX =   32.8121, rY =    0.0000, rZ =   -0.0343

X = 2275.1169, Y = 1600.4219, Z =   99.8591
nX =   -0.0003, nY =   -0.5418, nZ =    0.8404
rX =   32.8121, rY =    0.0000, rZ =   -0.034

X = 2272.6640, Y = 1625.3664, Z =   82.7343
nX =   -1.0000, nY =    0.0000, nZ =    0.0000
rX =   89.9999, rY =    0.0000, rZ =  270.0000

X = 2274.1557, Y = 1634.8671, Z =   82.7343
nX =    0.0000, nY =   -1.0000, nZ =    0.0000
rX =   89.9999, rY =    0.0000, rZ =    0.0000

Here is the code I used to ensure the algorithm worked.

GetNormalRot(Float:tx, Float:ty, Float:tz, &Float:rx, &Float:rz) {
    rx = acos(tz);
    rz = atan2(ty, tx) + 90.0;
}

main() {
    CA_Init();

    new Vector(X, Y, Z), Vector(nX, nY, nZ), Vector(rX, rY, rZ);

    CA_RayCastLineNormal(2270.1558, 1625.3665, 82.7344, 2274.1558, 1625.3665, 82.7344, X, Y, Z, nX, nY, nZ);
    GetNormalRot(nX, nY, nZ, rX, rZ);
    printf("X = %4.4f, Y = %4.4f, Z = %4.4f\nnX = %4.4f, nY = %4.4f, nZ = %4.4f\nrX = %4.4f, rY = %4.4f, rZ = %4.4f", X, Y, Z, nX, nY, nZ, rX, rY, rZ);

    CA_RayCastLineNormal(2274.1558, 1625.3665, 82.7344, 2274.1558, 1635.3665, 82.7344, X, Y, Z, nX, nY, nZ);
    GetNormalRot(nX, nY, nZ, rX, rZ);
    printf("X = %4.4f, Y = %4.4f, Z = %4.4f\nnX = %4.4f, nY = %4.4f, nZ = %4.4f\nrX = %4.4f, rY = %4.4f, rZ = %4.4f", X, Y, Z, nX, nY, nZ, rX, rY, rZ);
}
Pottus commented 8 years ago

Lets see

Crayder commented 8 years ago

See as in you're going to test it or as in you want to see pictures, or what? XD

Pottus commented 8 years ago

Pictures lol

Crayder commented 8 years ago

K, a sec

Crayder commented 8 years ago

image

I layed a line of concrete cubes on the hanger, is this good enough? XD

Crayder commented 8 years ago

I think I like the rX/rY angle version better still. With the rX/rZ version rotating on the z axis afterwards fucks things up.

The fix still stands however, I haven't received any odd rotations yet.

Pottus commented 8 years ago

Sounds good.

codectile commented 8 years ago

Will this be more accurate?

rx = acos(nx) * RADIAN_TO_DEGREE; //nx normal x of the hit point
ry = asin(ny) * RADIAN_TO_DEGREE; //ny normal y of the hit point
rz = 0.0;