PDA

View Full Version : Camera Vectors in R5 - how to use, READ THIS!


JernejL
24/03/2010, 06:20 PM
First of all, discard the "UP" vector, the only vector of use currently is the FRONT vector.

The FRONT vector is simply a unit length (1 unit) vector direction in which the player is aiming from the camera position.

How to make sense of this..:

Basically, if you add camera front vector to the camera position vector, you will get another point in game space which is exactly 1 unit apart from the player and is in the direction where the player is looking at.

That camera target point can be then moved forward and backwards to have a point of reference against a specific target and see if the player is aiming towards it.

Example usage:

1. calculate distance from camera position to target check position (say a specific object)
2. rescale the front vector so it's length will be the distance to object to check, THIS IS VERY EASY - Since the vector is always of 1.0 length you can simply multiply the front vector XYZ values by the distance from #1, we will call this vector a tempcamtarget vector.
3. Now since you have the tempcamtarget point that is of known distance away from the target point and towards what the player is looking at, you can do a simple distance check from the tempcamtarget to the object position, the distance returned will be how far off from target object the player is looking, so you can know if he's looking at a certain object, or looking away from it.

EXAMPLE CODE:


Float:DistanceCameraTargetToLocation(Float:CamX, Float:CamY, Float:CamZ, Float:ObjX, Float:ObjY, Float:ObjZ, Float:FrX, Float:FrY, Float:FrZ) {

new Float:TGTDistance;

// get distance from camera to target
TGTDistance = floatsqroot((CamX - ObjX) * (CamX - ObjX) + (CamY - ObjY) * (CamY - ObjY) + (CamZ - ObjZ) * (CamZ - ObjZ));

new Float:tmpX, Float:tmpY, Float:tmpZ;

tmpX = FrX * TGTDistance + CamX;
tmpY = FrY * TGTDistance + CamY;
tmpZ = FrZ * TGTDistance + CamZ;

return floatsqroot((tmpX - ObjX) * (tmpX - ObjX) + (tmpY - ObjY) * (tmpY - ObjY) + (tmpZ - ObjZ) * (tmpZ - ObjZ));
}


The result of the function is how close to the object centre the player is looking at, use it like - if value is < 1.0 then the player is looking at the object within target diameter of 2.0 units (for 1.0 radius.. diameter is 2.0)

Code is untested, but compiles and should work.

Norn
24/03/2010, 06:42 PM
From this can we calculate a vehicle in front of the players distance/players distance simply by looking at it?

JernejL
24/03/2010, 06:44 PM
]
From this can we calculate a vehicle in front of the players distance/players distance simply by looking at it?


Yes, the script can know exact what car you are looking at.

wafffllesss
24/03/2010, 06:47 PM
Will be waiting for your example code.

( More upgrades to my zombie script =D )

Norn
24/03/2010, 07:23 PM
]
From this can we calculate a vehicle in front of the players distance/players distance simply by looking at it?


Yes, the script can know exact what car you are looking at.



Epic thanks for explaining this in simple terms.

JernejL
24/03/2010, 09:13 PM
CODE EDITED - THIS IS CORRECT AND TESTED!

Float:DistanceCameraTargetToLocation(Float:CamX, Float:CamY, Float:CamZ, Float:ObjX, Float:ObjY, Float:ObjZ, Float:FrX, Float:FrY, Float:FrZ) {

new Float:TGTDistance;

// get distance from camera to target
TGTDistance = floatsqroot((CamX - ObjX) * (CamX - ObjX) + (CamY - ObjY) * (CamY - ObjY) + (CamZ - ObjZ) * (CamZ - ObjZ));

new Float:tmpX, Float:tmpY, Float:tmpZ;

tmpX = FrX * TGTDistance + CamX;
tmpY = FrY * TGTDistance + CamY;
tmpZ = FrZ * TGTDistance + CamZ;

return floatsqroot((tmpX - ObjX) * (tmpX - ObjX) + (tmpY - ObjY) * (tmpY - ObjY) + (tmpZ - ObjZ) * (tmpZ - ObjZ));
}


// EXAMPLE USAGE:

checkforcamera(PlayerID) {

new Float:CameraPos[3];
new Float:CameraFront[3];
new Float:CheckObjectPos[3] = {-2661.2764,915.7676,79.6685}; // trash can near partyserver torenos

GetPlayerCameraPos(PlayerID, CameraPos[0], CameraPos[1], CameraPos[2]);
GetPlayerCameraFrontVector(PlayerID, CameraFront[0], CameraFront[1], CameraFront[2]);

new Float:distc;
distc = DistanceCameraTargetToLocation(CameraPos[0], CameraPos[1], CameraPos[2], CheckObjectPos[0], CheckObjectPos[1], CheckObjectPos[2], CameraFront[0], CameraFront[1], CameraFront[2]);

new string[128];
if (distc < 2.0) {
format(string,sizeof(string),"YOU SEE IT.");
SendClientMessage(PlayerID, COLOR_RED, string);
}

return true;
}

CracK
25/03/2010, 05:15 AM
stock IsPlayerAimingAt(playerid, Float:x, Float:y, Float:z, Float:radius)
{
new Float:cx,Float:cy,Float:cz,Float:fx,Float:fy,Float :fz;
GetPlayerCameraPos(playerid, cx, cy, cz);
GetPlayerCameraFrontVector(playerid, fx, fy, fz);
return (radius >= DistanceCameraTargetToLocation(cx, cy, cz, x, y, z, fx, fy, fz));
}
returns 1, if a player is looking at position x,y,z
Use radius 1.0 for players

Burridge
25/03/2010, 07:08 AM
Thanks, RedShirt. Good post.

boelie
25/03/2010, 07:18 PM
Hmm this might sound noobish but

im trying IsPlayerAimingAt in a command but im not sure if im doing it correct.
Can someone give an example ?

JernejL
25/03/2010, 07:30 PM
Hmm this might sound noobish but

im trying IsPlayerAimingAt in a command but im not sure if im doing it correct.
Can someone give an example ?



Just call it with playerid, target coords and target radius, how hard is that?

boelie
25/03/2010, 07:37 PM
I did.... never mind i better put this in scripting discussion instead of server support if i keep finding problems.

MaykoX
25/03/2010, 07:59 PM
Thanks for this, Helped me a lot.

Rac3r
26/03/2010, 07:22 AM
Thanks, I had a brain freeze and couldn't think of any use for this.

Interesting post.

CracK
26/03/2010, 11:22 AM
stock GetPosFromView(playerid, Float:distance, &Float:x, &Float:y, &Float:z)
{
new Float:cx,Float:cy,Float:cz,Float:fx,Float:fy,Float :fz;
GetPlayerCameraPos(playerid, cx, cy, cz);
GetPlayerCameraFrontVector(playerid, fx, fy, fz);
x = fx * distance + cx;
y = fy * distance + cy;
z = fz * distance + cz;
}I couldn't think of other name..
This function returns coords of the point a player is looking at, depending on the distance.

Example:
zcmd(bang,playerid,params[])
{
new Float:r;
if(sscanf(params,"f",r)) {}
else
{
new Float:x,Float:y,Float:z;
GetPlayerPos(playerid, x, y, z);
GetPosFromView(playerid, r, x, y, z);
CreateExplosion(x, y, z, 2, 10);
}
return 1;
}
If you type /bang 20 there will be an explosion 20 gta units far from you.

ev0lution
27/03/2010, 01:36 AM
After about an hour thinking about this idea last night, and how it would be possible, then about an hour making it today, I present to you...
GetPlayerFacingPoint (couldn't think of a better name)
Finally, a function which will return the X, Y and Z coordinate which your player is currently facing/aiming at.

NOTE: This needs the MapAndreas (http://forum.sa-mp.com/index.php?topic=145196.0) plugin to work!

The code will be at the end of this post, but first..

What does it do?
- It returns the X, Y and Z coordinate in the world which your player is currently aiming at.

What could it be used for?
- Anything you want. While I was testing, I made a random "gun" which created an explosion at the point the player was looking at. The possibilities are endless*.
* The possibilities aren't endless due to technical limitations, but it still sounds cool to say that.

How does it work?
- It works by using the players camera vector and position, and map data from the MapAndreas plugin to detect where objects are.

Wait, so it actually gets the position where the player is aiming? The thing that noobs have been requesting for the past 4 years?
- Yes, although with slight limitations listed below.

Are there any problems or limitations?
- Actually, yes. Because of the way the MapAndreas plugin works, as well as the way it's used in this function, it's not perfect. Potential problems are listed below;

It, sadly, doesn't detect players - this is possible to implement but would require a player loop and IsPlayerInRangeOfPoint on every increment. :|
Because of the way walls are detected, this will not work in covered areas such as car parks, and attempting to shoot from outside into a carpark will cause the point to be returned at the entrance.
Also because of the way walls are detected, if you aim something with a cover (of any sort) before it (such as a shop with a small covered area on the outside of it, or even an extended bit of the wall), the point will be at that object, the one closest to you, even if there is no wall at that position. (sort of same problem as above)
It doesn't work with custom objects, either (although this functionality may be added to MapAndreas)
AFAIK, the MapAndreas data is accurate to 1 GTA unit. Some objects are less than this size, and are not in this data (such as fences or walls), which means these will be skipped and the position will "go through" it.
Some objects, like metal fences, are not in the MapAndreas data because they are dynamic and can be destroyed. This is the same problem as above.
Over long distances (very long, or on shitty computers) the function will take a while to execute (nup, read below)
Camera data seems to only update every second or two. This means if you're using the function on a moving player, it may detect the point at a previous camera position. (nup, read below)

BUT, the function still works exceptionally well considering how it detects the point.

Who made this function?
- I did, of course. With attempted help from Kye when the default values on the function wouldn't work while it was public, but nobody else helped on the actual function itself. Credit to Kye for creating the MapAndreas plugin (and SA-MP), and JernejL for helping explain the camera position/vector functions.

Any demo for this?
- I was going to upload a video to YouTube of a small script I made which creates an explosion where you're aiming, but I couldn't be bothered. I'll leave it up to you guys.

Holy shiznit, I found a bug!
- I have tested this thoroughly and haven't found anything wrong with the actual code, besides the limitations listed above. If you believe there is something else wrong with it, PM me or reply to this thread.

Could you explain the parameters?
GetPlayerFacingPoint(playerid,&Float:x,&Float:y,&Float:z,Float:limit=30.0,Float:increment=1.0)

playerid - If you can't figure out what "playerid" might be, this function is definitely not for you.
&Float:x - Variable to store the result of the X axis.
&Float:y - Variable to store the result of the Y axis.
&Float:z - Variable to store the result of the Z axis.
Float:limit=30.0 - The limit (in game units) before the loop will stop. If no objects are detected before the limit, the result will be the position at this point.
Float:increment=1.0 - The amount to increment each time the position is checked for objects. MapAndreas data is accurate to 1 GTA unit, so it shouldn't be less than 1.0. Lower values = higher accuracy (except <1), slower processing. Higher values = lower accuracy, faster processing.


GIVE US THE F***ING CODE ALREADY
Oh, right, sorry...
// This is where the fun starts
// Note: this needs the MapAndreas plugin to work!
GetPlayerFacingPoint(playerid,&Float:x,&Float:y,&Float:z,Float:limit=30.0,Float:increment=1.0) {
// Create the variables used
new Float:camvector[3],Float:campos[3],Float:last[4],Float:cur[4],a=0,started=0;
// Get the players camera front vector and position
GetPlayerCameraFrontVector(playerid,camvector[0],camvector[1],camvector[2]);
GetPlayerCameraPos(playerid,campos[0],campos[1],campos[2]);
// Start the loop
// This loop will go through, and at each (increment) from the players camera vector/position it will check that
// position and whether there are obstacles there. It hopes to be reasonably accurate at detecting objects so that
// it's able to return the exact(-ish) position a player is aiming at.
// See the "if" check in the loop for how it detects objects.
// If no position is found before (limit), the position at (limit) will be returned
for(new Float:i=0.1;i<=limit;i+=increment) {
for(a=0;a<3;a++) cur[a] = (camvector[a] * i) + campos[a];
MapAndreas_FindZ_For2DCoord(cur[0],cur[1],cur[3]);
// Make sure this isn't the first run. Probably better just to check last[0-3] results. eh.
if(started &&
// Player is aiming up, current highest point higher than test Z, last highest point lower than test Z
(((cur[3] > cur[2]) && (last[3] < cur[2])) ||
// Player is aiming down, current highest point higher than test Z, last test Z higher than highest point
((cur[3] > cur[2]) && (last[2] > cur[3])))) {
// We have a rough point where the player is aiming; between the current and last point
// Average these points to get a (generally) more accurate/acceptable result
for(a=0;a<4;a++) last[a] = ((cur[a] + last[a]) / 2); // Save all last values as average of results
// Note (above) although all 4 values (X, Y, Z, highest Z) are saved, only 3 are used/returned
break; // Break out of the loop with the last values saved
}
else {
for(a=0;a<4;a++) last[a] = cur[a]; // Save all last values
}
started = 1; // If it wasn't set already, (first) indicate this is now past the first run
}
// Save the final values into the referenced variables
x = last[0];
y = last[1];
z = last[2];
return 1;
}
The function is well commented so that scripters can understand what the hell I'm doing, and so that I could as well, while I was making it. (I usually confuse myself with things like this)


Some more boring notes for you to read;
- The GTA map is, AFAIK, 6000 units wide and high. This means it's the maximum limit before it's just useless. If you had this as the limit, though, you're an idiot and should be shot. I don't recommend it to be any higher than 100.
- I also don't recommend that the increment be set any lower than 1.0, it will be useless because of the MapAndreas map data.
- I ALSO, finally, don't recommend that you use this function constantly. The function (default) averaged around ~20ms on a reasonable computer. This is 0.2% of a second, so it's really not much, but people get crazy ideas (like saving files OnPlayerUpdate) so be careful. Anyway, most servers will be more powerful than my computer, and will execute the function much faster.

And regarding the stuff above which is crossed out...
- About using the function constantly, or it running slowly, well I re-tested and found it took <1ms to execute each time on default settings.
- About the camera positions not updating, well it seemed to be the case before, but for some reason it now seems to update instantly, and testing while running with 20 checks per second seems to prove this.

Enjoy. :)

Norn
27/03/2010, 08:11 AM
* The possibilities aren't endless due to technical limitations, but it still sounds cool to say that.


Lmao you brightened up my day, thanks!

Although unfortunately i'm not going to use a plugin that uses 70mb ram for one function.

ev0lution
28/03/2010, 08:35 AM
]

* The possibilities aren't endless due to technical limitations, but it still sounds cool to say that.


Lmao you brightened up my day, thanks!

Although unfortunately i'm not going to use a plugin that uses 70mb ram for one function.
Fair enough. I don't see it as much, really.
Unless you're on an overloaded server and need to spare as much memory as possible, it's not a problem for most hosts. And I don't do much else while I'm testing on my PC, so an extra 70 MB of RAM being used doesn't bother me either.

[HLF]Southclaw
01/04/2010, 01:44 PM
Here's a question for a dev if they read it: Is collision detection possible in SA? because if you combine that with the new camera functions [great work by the way :P] you could make something cool.

Anyway another question for anyone really:

If I used GetPlayerCameraPos then GetPlayerPos then subtracted the camera pos from the player pos, would I get the position in front of the player, the same distance form the player as the camera is form the player.

Thanks :D

ev0lution
02/04/2010, 12:15 AM
ǾǖŦĦŁΛẄ ]
Here's a question for a dev if they read it: Is collision detection possible in SA? because if you combine that with the new camera functions [great work by the way :P] you could make something cool.

Collision detection is basically what my function does, or attempts to do. (last post on the first page of this topic)

Also guys, to those who saw my function before, it seems two of the potential problems aren't problems anymore. I'll also be posting a video of the function in action (in a reasonably exciting way) soon.

SourceCode
20/09/2011, 01:34 AM
How to actually detect if there is player in my view and store the playerid who is in the view?

JernejL
28/09/2011, 09:05 PM
How to actually detect if there is player in my view and store the playerid who is in the view?

You can do it in a easy way with new math plugin:
http://forum.sa-mp.com/showthread.php?t=270508

SourceCode
15/11/2011, 02:45 PM
Ability to use vehicle id in native MPGetAimTarget(PlayerID, Float:SeekRadius = 50.0);