changing camera position

Get technical support about the C++ source code and about Lua scripts for maps, entities, GUIs, the console, materials, etc. Also covered are the Cafu libraries and APIs, as well as compiling, linking, and the build system.
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31
changing camera position

Post by .red » 2010-08-06, 19:48

I started working with the engine a bit, and am now trying to change the player from first person to a third person camera. I actually archieved first success by using the code that was actually written for rendering the other players as a replacement for the code that renders the weapon for the own player.
(HumanPlayer.cpp Line 954 ff)

Code: Select all

 if (FirstPersonView)
    {
 -draw first person weapon-
}
    else
    {
-draw character model for others-
}
I think you know what i mean.

However, this of course results in the camera being right in the player models head.
Now im still new and just cant manage the game to place the camera somewhere else. It simply stays where it is and some attempts like:

Code: Select all

Vector3fT EyePos(MatSys::Renderer->GetCurrentEyePosition());
EyePos.y-=20.0f;
MatSys::Renderer->SetCurrentEyePosition(EyePos.x, EyePos.y, EyePos.z);
did compile, but not change anything. I tried different values for the 2nd line.
I guess thats been a pointless attempt so.

Can anyone tell me how to actually realize what i was trying?
Thanks in advance^^
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-07, 13:02

Dear .red,
welcome to the Cafu forums! :welcome:
.red wrote:Can anyone tell me how to actually realize what i was trying?
Changing the parameters to MatSys::Renderer->SetCurrentEyePosition() in fact only changes the eye position for the Material System, e.g. when the MatSys renders a reflection of specular contribution of light, it uses this coordinate.

The right way to go is to modify the point where the whole world is rendered from, you should look at DrawState->Origin that is used in ClientStateInGameT::Render() as an argument to CaClientWorldT::Draw().
Best regards,
Carsten
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-07, 15:04

But isnt origin the center point of the entity? So that when i modify the origin, it wont change a thing for the view since everything else uses the origin too?
Or am mixing things up now? Wouldnt that mean id have to seperate the cameras origin from the entity origin whereever its used in the code?
Could you give me another hint or idea?


If any of those guys who already attempted to change camera positions could share their experience i would be very delighted too =)
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-09, 11:04

.red wrote:But isnt origin the center point of the entity? So that when i modify the origin, it wont change a thing for the view since everything else uses the origin too?
Well, yes and no: The camera origin is originally the origin of the local player entity (the default for 1st person views), but when you modify the origin where it is used for camera setup, the local entity should stay in the world where it is, but you can render the scene e.g. from a short distance behind the local entity - third person setup.

For example, in method CaClientWorldT::Draw(), add near the beginning of the method

Code: Select all

Vector3dT ThirdPersonOrigin=DrawState->Origin;
then modify ThirdPersonOrigin as required, e.g.

Code: Select all

ThirdPersonOrigin.y-=300.0;
offsets the origin about 30cm in y-direction.

Then in the rest of the method, replace DrawState->Origin with ThirdPersonOrigin, and it should work (I've not currently tested this, last time I wrote a third person view was several years ago).

Some notes though:
  • The simple change of subtracting (or adding) 300 above will probably not be enough for more advanced use -- you'll probably want to make the camera "orbit" around the player depending on DrawState->Heading, so a bit more math is required.
    The best solution is probably to combine this with tracing a ray from the player origin through the offset camera, in order to not move the camera through a solid wall.
  • The PVS might get in the way when you offset the camera in a simple manner, because it might be offset into another BSP leaf (another "room") and thus the scene may not render correctly. Please see this post for toggling the PVS on and off.
Or am mixing things up now? Wouldnt that mean id have to seperate the cameras origin from the entity origin whereever its used in the code?
Only in the method mentioned above, which should not be a big deal though.

Let me know if this works - 3rd person rendering is a (relatively) frequently asked question, and I'm considering making a page on the Wiki that briefly explains all required modifications (or even better, submit a patch to the issue tracker). :up:
Best regards,
Carsten
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-09, 12:55

Thanks alot, this is probably really gonna help me solving that problem ;)
When i got it to work ill send you the results for sure.
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-11, 17:20

Ok im stuck again and probably dont see something simple.

I was trying to create that "camera sphere", beginning by moving it around the player in a circle on the x/y coordinates, ignoring z yet.

Code: Select all

	ThirdPersonOrigin.y -= cos(float(DrawState->Heading)) * CameraDistance;
	ThirdPersonOrigin.x += sin(float(DrawState->Heading)) * CameraDistance;
However, this results in the camera spinning around the player with enourmous speed.

Then i noticed you multiplied it with 360/2^16 some lines below, so i tried that as well

Code: Select all

	ThirdPersonOrigin.y -= cos(float(DrawState->Heading)*45.0f/8192.0f) * CameraDistance;
	ThirdPersonOrigin.x += sin(float(DrawState->Heading)*45.0f/8192.0f) * CameraDistance;
However, it still circles the player ~16 times per 90° turn.
I absolutely dont understand why, especially not since afaik 360/2^16 has nothing to do with radiants or anything, so i dont even understand why that numbers are used.
So why is the camera circling around the player too often and what system is actually used to display the rotation? The idea for the calculations should be right, at least in my eyes its the simplest way to do it.


Edit: Ok seems a circle is devided into 65536 units (thats why its 360/2^16, sometimes im blind to the obvious). Now i still gotta find out whats causing the spin =/
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-11, 18:15

.red wrote:However, it still circles the player ~16 times per 90° turn.
I absolutely dont understand why, especially not since afaik 360/2^16 has nothing to do with radiants or anything, so i dont even understand why that numbers are used.
So why is the camera circling around the player too often and what system is actually used to display the rotation? The idea for the calculations should be right, at least in my eyes its the simplest way to do it.
Yes, you are certainly on the right track:

The variables that store the angles are of type unsigned short, so we represent a full circle not by number 360, but by 2^16 == 65536, making optimal use of all 16 bits of the variable.

Multiplying such numbers by 360/2^16 converts back to degrees, and in order to use radians (which the sin() and cos() in your code expect), you must multiply by 2Pi/2^16 instead. (You can (re-)use the PI constant from Libs/Math3D/Angles.hpp here is you wish.) :up:
Best regards,
Carsten
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-12, 14:09

Sometimes the answer is too obvious to be seen oO.

Anyway, the third person cam works great so far:

Code: Select all

	ThirdPersonOrigin.x -= sin(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.y -= cos(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.z += sin(float(DrawState->Pitch  )*(M_PI /32768.0f)) * CameraDistance;
Would still have to be modified for a third person shooter, since the croshair is always covered by the players head, but i dont need the player to aim atm.

However, i now tried to cast a ray from the player origin to the thirdpersonorigin to check if it hits level geometry. if it does, the thirdpersonorigin would have to be set to the point where the ray hits the wall.

The idea looks like this:

Code: Select all

Vector3dT ThirdPersonOrigin=DrawState->Origin;
	float CameraDistance = 1600.0;
	
	ThirdPersonOrigin.x -= sin(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.y -= cos(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.z += sin(float(DrawState->Pitch  )*(M_PI /32768.0f)) * CameraDistance;


    RayResultT RayResult(NULL /*No object to ignore*/);
    PhysicsWorld->TraceRay(DrawState->Origin/1000.0, ThirdPersonOrigin/1000.0), RayResult);

    if (RayResult.hasHit())
	{
        ThirdPersonOrigin=convd(RayResult.m_hitPointWorld)*1000.0;
	}

Now the problem is, that RayResultT belongs to PhysicsWorld.hpp wich is located in the deathmatch folder.
i wouldnt want to import that, and even when i tried, it resulted in other cant-find-file-errors while compiling.
Now still being new to c++ and not fully understanding the engine yet im pretty much puzzled.

Another thing im still thinking about is, that i want first AND third person view possible, depending on for example a team or character chosen. Im unsure how to realize that as well, especially since the drawing "type" in the clientworld.cpp then depends on something you chose and set in the game files....
Same problem as above so, not fully understanding yet.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-13, 13:11

Anyway, the third person cam works great so far:
Great to hear that! :-)
Now the problem is, that RayResultT belongs to PhysicsWorld.hpp wich is located in the deathmatch folder.
Yes, I would not recommend using that anyways, but instead use the (for this purpose) more performant and more readily available classes in CaClientWorldT::Ca3DEWorld.

That is, for the ray-test in the CaClientWorldT::Draw() code, you can either use Ca3DEWorld->ClipWorld or Ca3DEWorld->CollModel. I would recommend to use the latter, as it only takes the static geometry into account (the ClipWorld also considers all the entities).

You could for example write

Code: Select all

TraceResultT Result;
Ca3DEWorld->CollModel.TraceRay(DrawState->Origin, ThirdPersonOrigin - DrawState->Origin, MaterialT::Clip_AllBlocking, Result);

// Result.Fraction*=0.99;    // Just an example for increased safety margin.
ThirdPersonOrigin=ThirdPersonOrigin*Result.Fraction + DrawState->Origin*(1.0-Result.Fraction);
With this, the camera should stay on the DrawState->Origin's side of walls and other geometry (I've not tested anything of this, but you get the gist). Multiplying Result.Fraction with 0.99 before doing the interpolations might give it an extra safety margin to the walls.
Another thing im still thinking about is, that i want first AND third person view possible, depending on for example a team or character chosen. Im unsure how to realize that as well, especially since the drawing "type" in the clientworld.cpp then depends on something you chose and set in the game files....
Well, we'd have to find a proper switch for the two view modes then, e.g. some entity attribute... :wink:
Best regards,
Carsten
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-14, 17:20

Thanks alot, works so far. I just needed to include ClipSys/TraceResult.hpp and MaterialSystem/Material.hpp and correct 2 or 3 small things.
So, for everyone who also tried to implement a third person camera, here are the changes made so far:

in /games/deathmatch/code/HumanPlayer.cpp
EntHumanPlayerT::Draw (line 940)

Code: Select all

    if (FirstPersonView)
    {
		//draw player in third person
		if (State.StateOfExistance!=StateOfExistance_Alive && State.StateOfExistance!=StateOfExistance_Dead) return;

        const float OffsetZ=(State.StateOfExistance!=StateOfExistance_Dead) ? -32.0f : -32.0f+float(State.Dimensions.Min.z+1728.8)/25.4f;

        MatSys::Renderer->GetCurrentLightSourcePosition()[2]-=OffsetZ;
        MatSys::Renderer->GetCurrentEyePosition        ()[2]-=OffsetZ;
        MatSys::Renderer->Translate(MatSys::RendererI::MODEL_TO_WORLD, 0.0f, 0.0f, OffsetZ);



        // Draw the own player body model and the "_p" (player) model of the active weapon as sub-model of the body.
        ModelProxyT& PlayerModel=GetModelFromPlayerModelIndex(State.ModelIndex);

        PlayerModel.Draw(State.ModelSequNr, State.ModelFrameNr, LodDist, (State.HaveWeapons & (1 << State.ActiveWeaponSlot)) ? &CarriedWeaponT::GetCarriedWeapon(State.ActiveWeaponSlot)->GetPlayerWeaponModel() : NULL);
  
    }
    
Basically thats a copy/paste from the code below it that is used to draw the other players. You could as well just remove the If-statement and use the same code for both of them, I kept it this way to keep the ability to have both rendered differently.

in /Ca3DE/Client/ClientWorld.cpp

add to the given includes:

Code: Select all

#define _USE_MATH_DEFINES 
#include "math.h"

#include "ClipSys/TraceResult.hpp"
#include "MaterialSystem/Material.hpp"
and then in CaClientWorldT::Draw (line 327)

Code: Select all

Vector3dT ThirdPersonOrigin=DrawState->Origin;
	float CameraDistance = 1600.0;

	ThirdPersonOrigin.x -= sin(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.y -= cos(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.z += sin(float(DrawState->Pitch  )*(M_PI /32768.0f)) * CameraDistance;

    cf::ClipSys::TraceResultT Result;
	Ca3DEWorld->CollModel->TraceRay(DrawState->Origin, ThirdPersonOrigin - DrawState->Origin, MaterialT::Clip_AllBlocking, Result);
	Result.Fraction*=0.85; 
	ThirdPersonOrigin=ThirdPersonOrigin*Result.Fraction + DrawState->Origin*(1.0-Result.Fraction);
Then replace every "DrawState->Origin" with "ThirdPersonOrigin".

This is for a third person camera that aims directly at the player. This however wouldnt work with any game where you need to aim at something, e.g. shooters, because your head will occlude your target.

Code: Select all

Vector3dT ThirdPersonOrigin=DrawState->Origin;
	float CameraDistance = 600.0;
	float SideDistance   = 150.0;

	ThirdPersonOrigin.x -= SideDistance * sin((float(DrawState->Heading)*(M_PI /32768.0f))-(M_PI/2));
	ThirdPersonOrigin.y -= SideDistance * cos((float(DrawState->Heading)*(M_PI /32768.0f))-(M_PI/2));

	ThirdPersonOrigin.x -= sin(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.y -= cos(float(DrawState->Heading)*(M_PI /32768.0f)) * CameraDistance *cos(float(DrawState->Pitch  )*(M_PI /32768.0f));
	ThirdPersonOrigin.z += sin(float(DrawState->Pitch  )*(M_PI /32768.0f)) * CameraDistance;


    cf::ClipSys::TraceResultT Result;
	Ca3DEWorld->CollModel->TraceRay(DrawState->Origin, ThirdPersonOrigin - DrawState->Origin, MaterialT::Clip_AllBlocking, Result);
	Result.Fraction*=0.85; 
	ThirdPersonOrigin=ThirdPersonOrigin*Result.Fraction + DrawState->Origin*(1.0-Result.Fraction);
This will place the camera a little to the right, like an over-the-shoulder view. Its not perfect yet, but thats an idea how to do it. Working on a better solution though.

For those who dont understand the math:

Image

We have:
A = player positon
c = camera distance
? (angle alpha) = heading

We need:
B = camera position, which consists of
a = value added to player pos on x-axis
b = value added to player pos on y-axis

Go check trigonometric functions on wikipedia:
http://en.wikipedia.org/wiki/Sine#Sine. ... nd_tangent

Same for z axis then as well of course.

PS: Yes, almost everyone disliked them at school. We still need them. ;)
Last edited by .red on 2010-08-17, 10:58, edited 1 time in total.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-16, 10:22

Hi .red,
So, for everyone who also tried to implement a third person camera, here are the changes made so far:
many thanks for posting your summary of changes! :-D

Could you also please create a patch from your changes? We could submit the patch as a ticket then as well. As a result, the changes would be well documented and very easy to apply by others.

If you cannot create the patch yourself, could you please send me the complete changed files (e.g. via e-mail), so that I can create the patch myself?

Again, many thanks!
Best regards,
Carsten
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-16, 14:38

I attached a zip with the files in their correct folders. They have a short description included as a comment, and 3 different views available by simple commenting/uncommenting (on player, over the head, over the shoulder).
Please make a patch out of it since im short of time today and need to get some other things done. Thank you.

Whoever wants to use them and doesnt want to wait for a patch can use them as well of course :wink: If you have modified the files yourself already just check the above post for what changes need to be made.
ThirdPersonView.zip
(24.82KiB)Downloaded 310 times
EDIT: Just a quick question without starting a new topic for it: Its not yet implemented into the engine to have player characters move their head at the point the player is looking? Especially as animation blending, like while the player is walking?
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-17, 15:14

.red wrote:Its not yet implemented into the engine to have player characters move their head at the point the player is looking? Especially as animation blending, like while the player is walking?
If I understand your question correctly, then no, the players whole body is always rotated into the direction of view. Separating the view direction from the move direction only makes sense (and in fact occurs) when the player is strafing (or otherwise we'd have to separate the control input for view and movement as well).

For strafing, we would indeed need separate animations for forward/backward and sideways movement, and attempt to blend them for combined (e.g. diagonal) movement.
For all model questions, the new model editor that I'm currently working on (currently temporarily interrupted by ticket 34) is an important factor or even a prerequisite though, so any help is welcome. :-)
Best regards,
Carsten
User avatar
.red
Posts:10
Joined:2010-08-06, 19:31

Re: changing camera position

Post by .red » 2010-08-17, 15:28

the heading is not so important, the pitch is. i need players to be able to see if somebody is looking at the ceiling or at the floor. especially for cases in which they have lights or lasers or anything that changes with viewing direction it would look akward if the whatever-beam goes right up, while the player model stares straight forward.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: changing camera position

Post by Carsten » 2010-08-17, 16:23

.red wrote:the heading is not so important, the pitch is.
Ah, I see. Yes, that is of course very desirable. As mentioned before, all help is welcome in implementing it! :up:
Best regards,
Carsten
Post Reply

Who is online

Users browsing this forum: No registered users and 19 guests