Senior Member
|
05-01-2023
, 13:14
FOV and Vector tutorial
|
#1
|
Introduction:
This is an example to explain what is FOV in game, and how can we use FOV to do someting.
Start: - Vector
To explain what is FOV, we need to understand what is position and vector at first.
Recommanded to read this page https://forums.alliedmods.net/showthread.php?t=91474
it has explained position and vector in detail.
Simply, you can image that there are two points in our life a(x,y,z), b(x1,y1,z1), and then let x1 -x, y1 -y, z1 -z, and use there result to make a new objec C(x2, y2, z2), then C is a vector from a to b.it's length is equal to the distance between point a and point b.All ot them is float[3]
- FOV
Now think that player is stand and his eyes is in the origin of coordinates, and eye sight is going to right. In this case we can draw his screen and FOV.
Actually, FOV is a degree that tell the Horizontal+ Angular Field of View of player. In image it is θ the degree of that player can see in horizontal. If you are good at "space rectangular coordinate system", it is very clear to understand it.
How to use - If you want to know that player can see an entity or not, FOV can help you do this more efficiency than Trace.Here is old code to check this situation.
Github
PHP Code:
stock bool PointWithinViewAngle(const float vecSrcPosition[3], const float vecTargetPosition[3], const float vecLookDirection[3], float flCosHalfFOV) { float vecDelta[3]; SubtractVectors(vecTargetPosition, vecSrcPosition, vecDelta); float cosDiff = GetVectorDotProduct(vecLookDirection, vecDelta); if (cosDiff < 0.0) { return false; } float flLen2 = GetVectorLength(vecDelta, true); // a/sqrt(b) > c == a^2 > b * c ^2 return ( cosDiff * cosDiff >= flLen2 * flCosHalfFOV * flCosHalfFOV ); }/** * Calculates the width of the forward view cone as a dot product result from the given angle. * This manually calculates the value of CBaseCombatCharacter's `m_flFieldOfView` data property. * * For reference: https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/hl2/npc_bullseye.cpp#L151 * * @param angle The FOV value in degree * @return Width of the forward view cone as a dot product result */ float GetFOVDotProduct(float angle) { return Cosine(DegToRad(angle) / 2.0); }
- It looks very difficult to understand what each function do,( i spend two hours to know what he done...) especially the return.
( Why compare those var and what they are? )
So i rewrite this code and make it easily to read.
PHP Code:
bool IsInClientView(int entity, int client) { float ent_pos[3],player_pos[3],player_ang[3]; float eye2ent_vector[3]; float eye2fwd_vector[3]; char temp[16]; GetClientInfo(client, "fov_desired", temp, sizeof(temp)); int fov = StringToInt(temp);
GetClientEyePosition(client,player_pos); GetEntPropVector(entity,Prop_Data,"m_vecOrigin",ent_pos); MakeVectorFromPoints(player_pos,ent_pos,eye2ent_vector);
GetClientEyeAngles(client,player_ang); GetAngleVectors(player_ang,eye2fwd_vector,NULL_VECTOR,NULL_VECTOR);
NormalizeVector(eye2ent_vector, eye2ent_vector); NormalizeVector(eye2fwd_vector, eye2fwd_vector);
float radian = ArcCosine( GetVectorDotProduct(eye2ent_vector, eye2fwd_vector) ); /** * let me explain how this degree radian. * * DotProduct = |a||b|cosθ, this is the vector theorem. * we have normalize the vector so |a| = |b| = 1. * in this case DotProduct = cosθ. * ArcCosine() let us get the radian of θ. * FOV is a degree, we need make it become radian. */ return radian <= DegToRad(fov + 0.0) / 2; }
- Let me explain it by img.
[1] Get the eye sight vector by eye angle.[the sky blue line in img]
(note that eye angle is not equal to the vector)
[2] Get ehe eye to ent vector by eye position and entity position.[the brown line in img]
[3] Use DotProduct to get the δ degree between this two vector.
[4] FOV is a degree , change it to radian.
[5] Compare δ with FOV / 2, if bigger than FOV / 2, it is out of the screen.
- So what is the diffierent betweent old code and new code?
Actually, both of them are the same in getting the vector of eye sight and eye 2 ent.One difference comes when new code start normalize the vector.
In fact, DotProduct = |a||b|cosθ, this is the vector theorem. if we have normalize the vector, |a| will be equal to |b| and equal to 1, since vector now becomes substrate vector.
Now it is easy to get the value of cosθ, use ArcCosine so we get the θ in radian. The scond different comes when function in return. We already get the θ, so all we need is compare this radian with FOV in radian and since player sight is always in the middle of the screen, FOV degree need to divide 2.
If θ is smaller than FOV / 2, it is in player view and return true, false otherwise.
- Code Compare
[1] There are the same before normalize the vector. Old code don't normalize this vector, so it's value is not the same as cosθ, it is just a float value. Only one thing can be confirm is that if this value is less than 0, it means θ is larger than 90°, so it is impossible to show in player screen.
[2] Second, old code get the lenght of eye 2 ent vector. Know that the value is square.
[3] Now comes to return, what is dotproduct * dot product? We don't need to know what it is in image, just use his function : |a||b|cosθ * |a||b|cosθ = |a|⑵|b|⑵cos⑵θ.
[4] Now return is clear. Old code compare |a|⑵|b|⑵cos⑵θ >= |b|⑵ * cos⑵(FOV / 2)
[5] Since eye sight vector is made by angle, it is length is 1. Return now can now can be equal to cos⑵θ >=cos⑵(FOV / 2).
[6] This is the cosine value image. You can see that when angle is zero, the value comes the biggest.
which mean that if ent is in player sight, θ should less than FOV / 2, and it is cosine value is larger than FOV / 2.
That is what old code do.
Problem: - Because FOV of player is just the horizontal angle of player screen. It is not the same as bot and player screen is rectangle so it will cause a problem that the area size FOV draw is over the screen in vertical as the image show. And in the four angle of player screen , it is not include in the area since it is angle is larger than FOV / 2.
- FOV can also get the ent that behind wall. since this function only check this in math, not include the game entity. Trace is still need if you want a more correctly check.
Last edited by LinLinLin; 05-03-2023 at 18:36.
|
|