First Person Camera with Ogrenewt -> SOLUTION

Hansel

04-09-2006 16:00:27

Hey people :D

I have found a lot of people with a lot of problems to implement a fps camera with Ogrenewt. Now I want to show you how I implement mine, or at least I'll try it :mrgreen: Hope it helps to all the people with this problem :D


First, a video of my implementation. If you don't like it just let it pass :lol:

http://www.youtube.com/watch?v=uPYt4Pvfjg8

Just follow the steps:


1- Var list


Real camera_rotation_x;
Real camera_rotation_y;

Vector3 cam_size = Vector3(10,10,10);

Real gravity = -9.8;


SceneNode* cam_node ;
Body* cam_body;
Real cam_mass = 40;

SceneNode* cam_view_node;


Real cam_height;
Real jump_power = 5;
Real fps_speed = 3;
bool no_movement = true;
Real x_sensibility = 5;
Real y_sensibility = 5;
Real y_rotation_cont = 0;
Real y_limit_a = 15;
Real y_limit_b = -40;





2- We need to create a force_callback function for the camera. This a function to define what kind of force we want to aply to the camera every time Newton updates the World.






void camera_force_callback( OgreNewt::Body* me )
{
//apply a simple gravity force.
Ogre::Real mass;
Ogre::Vector3 inertia;

me->getMassMatrix(mass, inertia);
Ogre::Vector3 force(0,gravity,0);
force *= mass;

me->addForce( force );
me->setOmega(Vector3(0,camera_rotation_x,0)); // To rotate the camera in the X axes
}




3- Define an scale size and then create an SceneNode and an ellipsoid body. Then attach the node to body




cam_node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); // initialise node

cam_node->setScale(cam_size); // define it's scale

Collision* cam_collision = new OgreNewt::CollisionPrimitives::Ellipsoid( mWorld, cam_size ); // create a collision for the body

cam_body= new OgreNewt::Body( mWorld, cam_collision ); // create the body
delete cam_collision; // now the collision can be deleted
cam_body->attachToNode( cam_node); // attach the node to the body. Now, when the body moves the node moves too


Vector3 cam_inertia = OgreNewt::MomentOfInertia::CalcEllipsoidSolid( cam_mass, cam_size ); // calculate the inertia ov the body
cam_body->setMassMatrix( cam_mass, inercia);
cam_body->setCustomForceAndTorqueCallback( camera_force_callback ); // add the previous defined callback function as the body custom force and torque callback

OgreNewt::BasicJoints::UpVector* uv2 = new OgreNewt::BasicJoints::UpVector(mWorld,cam_body,Vector3::UNIT_Y); // create an upvector. This forces the body to rotate just in the X and Z axes.





4.- Create a child node and attach the camera to it



cam_view_node = cam_node->createChildSceneNode(Vector3(0,5,0)); // crete a child 5 units above the cam_node
cam_view_node->attachObject(mCamera); // attach the camera to the view_node.







5.- FPS Camera.

Vector3 get_body_position(Body* bod) // get the position of the body
{
Quaternion orient;
Vector3 pos;

bod->getPositionOrientation(pos, orient);

return pos;
}


Quaternion get_body_orientation(Body* bod) // get the orientation of the body
{
Quaternion orient;
Vector3 pos;

bod->getPositionOrientation(pos, orient);

return orient;
}





no_movement = true; // for the moment there ins't movement


OgreNewt::BasicRaycast cam_ray(mWorld,get_body_position(cam_bod), get_body_position(cam_bod), + Vector3::NEGATIVE_UNIT_Y * 2000 ); // throw a ray from the body to 2000 units below to calculate the // height of the body regard to the floor.

if (cam_ray.getHitCount() > 0)
{
cam_height = cam_ray.getFirstHit().mDistance*10000; // calculale the camera height.
}



if ((mInputDevice->isKeyDown(KC_SPACE))) // jump. cam_height depends of the scale of your nodes and the position of them, probably you need to recalculate this values to use jumping in your app.
{
if ((cam_height > 10)&& (cam_height<22))
{
cam_body->setVelocity(cam_body->getVelocity()*Vector3(1,0,1)+Vector3(0,40,0)*jump_power);

}

}





if ((mInputDevice->isKeyDown(KC_LSHIFT))) // run
{
fps_speed = 3;
}
else fps_speed = 1;





if (mInputDevice->isKeyDown(KC_S)) // move backward
{
Vector3 direction = get_body_orientation(cam_body) * Vector3::UNIT_Z;
cam_body->setVelocity(cam_body->getVelocity()*Vector3(0,1,0) + direction*30*fps_speed);
no_movement = false;
}

if (mInputDevice->isKeyDown(KC_W)) // move forward
{
Vector3 direction = get_body_orientation(cam_body) * Vector3::NEGATIVE_UNIT_Z;
cam_body->setVelocity(cam_body->getVelocity()*Vector3(0,1,0) + direction*30*fps_speed);
no_movement = false;
}


if (mInputDevice->isKeyDown(KC_D)) // move to the right
{
Vector3 direction = get_body_orientation(cam_body) * Vector3::UNIT_X;
cam_body->setVelocity(cam_body->getVelocity()*Vector3(0,1,0) + direction*30*fps_speed);
no_movement = false;
}

if (mInputDevice->isKeyDown(KC_A)) // move to the left
{
Vector3 direction = get_body_orientation(cam_body) * Vector3::NEGATIVE_UNIT_Z;
cam_body->setVelocity(cam_body->getVelocity()*Vector3(0,1,0) + direction*30*fps_speed);
no_movement = false;
}





camera_rotation_x = -mInputDevice->getMouseRelativeX() * x_sensibility/(100*evt.timeSinceLastFrame); // this is used in the defined callback function to rotate the camera in the X axes, with mouse
camera_rotation_y = -mInputDevice->getMouseRelativeY() * y_sensibility/(100*evt.timeSinceLastFrame); // to rotate the camera in the Y axes, with mouse

cam_view_node->pitch(Degree(camera_rotation_y)); // roate the view node
y_rotation_cont += camera_rotation_y; // calculate the total of the rotations we have done

if (y_rotation_cont > y_limit_a || y_rotation_cont < y_limit_b) // if the total is bigger or smallest than the limits it will be reseted to it's previous value
{
cam_view_node->pitch(Degree(-camera_rotation_y));
y_rotation_cont -= camera_rotation_y;
}

if (no_movement) cam_body->setVelocity(cam_body->getVelocity()*Vector3(0,1,0)); // if there is no_movement then we set the velocity in the X and Z axes to 0. If you want to add some inertia change the X //and Z values to another









Now you just need to set your materials, but that's another lesson :mrgreen:







pd.- Thanks Walaber :D

majc

04-09-2006 21:33:48

Thanks hansel!!
Because of you code i think i know what i did wrong in mine.
I put the camera inside the collision body instead of put it above the body, and for what i see the body only moves forward, backwards, etc... dont pitch or yaw, you let the camera deal with that.
Correct me if im wrong.
I only want to ask one thing if the only collision part its the body and not the cam if your character wants to pass through a door that have the size of your body but its smaller than body+camera how you deal with that?

abecam

05-09-2006 10:56:16

Wow! As always, your video looks great (you are good both in programming and in graphics, that's impressive) ! I was wondering, after I have seen you have some stacks in your video, if it does not have a big impact on the performance? (I guess it help to have a simple column too) It is so far the big issue I have encountered with Newton.

Drakon

05-09-2006 14:19:31

Hansel thanks for your code:) This helps me a lot.

Your video is cool.

I have one question : could you tell me how you created this reflections on the floor??

Drakon

06-09-2006 02:16:24

And here is my soft with camera moving,rotating with force.

http://rapidshare.de/files/32100617/demo.rar.html

I change your code a little but it works now:)

Falagard

06-09-2006 19:43:02

Drakon, you are using forces to move the character's body instead of setVelocity?

Care to share your code? :-)

Drakon

07-09-2006 00:04:37

Yes i'm using forces to move character body and of course i will share my code:)

FPPCamera.h
#ifndef FPPCAMERA_H
#define FPPCAMERA_H

#include "Ogre.h"
#include "OgreNewt.h"

using namespace Ogre;
using namespace OgreNewt;

class FPPCamera
{
public:

Real camera_rotation_x;
Real camera_rotation_y;

Vector3 cam_size;

Real gravity;


Vector3 stra,poo2;

SceneNode* cam_node;
Body* cam_body;
Real cam_mass;
Ogre::SceneManager* mSceneMgr;
OgreNewt::World* mWorld;
Ogre::Camera* mCamera;
OgreNewt::MaterialID * FPPmat;

SceneNode* cam_view_node;

Ogre::Vector3 MyVel;
Ogre::Vector3 direction;

Real cam_height;
Real jump_power;
Real fps_speed;
bool no_movement,jump,on_earth;
Real x_sensibility;
Real y_sensibility;
Real y_rotation_cont;
Real y_limit_a;
Real y_limit_b;


FPPCamera(Ogre::SceneManager* _mSceneMgr, OgreNewt::World* _mWorld,Ogre::Camera* _mCamera);
~FPPCamera();


void camera_force_callback( OgreNewt::Body* me );

Vector3 get_body_position(OgreNewt::Body* bod);

Quaternion get_body_orientation( OgreNewt::Body* bod );

void FPPleft();
void FPPright();
void FPPup();
void FPPdown();
void FPPjump();

void FPPleftEnd();
void FPPrightEnd();
void FPPupEnd();
void FPPdownEnd();
void FPPjumpEnd();

void FPPUpdate();

};


#endif


and now FPPCamera.cpp
#include "FPPCamera.h"
#include "Ogre.h"
#include "OgreNewt.h"

using namespace Ogre;
using namespace OgreNewt;

FPPCamera::FPPCamera(Ogre::SceneManager* _mSceneMgr,OgreNewt::World* _mWorld,Ogre::Camera* _mCamera)
{

cam_size = Vector3(10,10,10);

gravity = -9.8;


cam_mass = 40;

jump_power = 5;
fps_speed = 3;
no_movement = true;
x_sensibility = 30;
y_sensibility = 30;
y_rotation_cont = 0;
y_limit_a = 90;
y_limit_b = -90;
jump = false;
this->on_earth = true;

poo2 = 0;
stra = 0;


mSceneMgr = _mSceneMgr;
mWorld = _mWorld;
mCamera = _mCamera;


cam_node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); // initialise node
cam_node->setScale(cam_size); // define it's scale


Collision* cam_collision = new OgreNewt::CollisionPrimitives::Ellipsoid( mWorld, cam_size ); // create a collision for the body

cam_body= new OgreNewt::Body( mWorld, cam_collision ); // create the body
delete cam_collision; // now the collision can be deleted
cam_body->attachToNode( cam_node); // attach the node to the body. Now, when the body moves the node moves too



Vector3 cam_inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( cam_mass, cam_size ); // calculate the inertia ov the body
cam_body->setMassMatrix( cam_mass, cam_inertia);
cam_body->setCustomForceAndTorqueCallback<FPPCamera>(&FPPCamera::camera_force_callback,this); // add the previous defined callback function as the body custom force and torque callback

OgreNewt::BasicJoints::UpVector* uv2 = new OgreNewt::BasicJoints::UpVector(mWorld,cam_body,Vector3::UNIT_Y); // create an upvector. This forces the body to rotate just in the X and Z axes.

cam_view_node = cam_node->createChildSceneNode(Vector3(0,5,0)); // crete a child 5 units above the cam_node
cam_view_node->attachObject(mCamera); // attach the camera to the view_node.

cam_body->setPositionOrientation(Ogre::Vector3(0.0,500.0,0.0),Ogre::Quaternion::IDENTITY);

cam_body->setAutoFreeze(0);

FPPmat = new OgreNewt::MaterialID(mWorld);
cam_body->setMaterialGroupID(FPPmat);
}

FPPCamera::~FPPCamera()
{
}

void FPPCamera::camera_force_callback(OgreNewt::Body* me)
{


FPPCamera *camPlayer = (FPPCamera*)me->getUserData();
Ogre::Real mass;
Ogre::Vector3 inertia;

me->getMassMatrix(mass, inertia);
Ogre::Vector3 force(0,gravity,0);
Ogre::Vector3 force2(0,gravity,0);


Ogre::Quaternion q;
Ogre::Vector3 qq,s;
direction = (get_body_orientation(cam_body) * Vector3::NEGATIVE_UNIT_Z);
poo2=(get_body_orientation(cam_body) * Vector3::NEGATIVE_UNIT_X);//for strafe
qq = direction;
s = poo2;//for strafe
Ogre::Vector3 V0 = me->getVelocity();
Ogre::Vector3 V1(qq * this->MyVel);
Ogre::Vector3 V2 (s * this->stra);//for strafe
Ogre::Vector3 acel = (V1 - V0);
Ogre::Vector3 acel2 = (V2 - V0);//for strafe
acel = acel * 0.5f;
acel2 = acel2 * 0.5f;

force.x = acel.x;
//force.y = acel.y;
force.z = acel.z;

force2.x = acel2.x;//for strafe
force2.z = acel2.z;//for strafe

//Ogre::Vector3 skok = this->get_body_position(cam_body);
if(jump == true)
{
force.y = 20*this->jump_power;
}

force *= mass;

force2 *= mass;

me->addForce( force );
me->addForce( force2 );//for strafe
me->setOmega(Vector3(0,camera_rotation_x,0)); //to rotate camera in x


}

Ogre::Quaternion FPPCamera::get_body_orientation(OgreNewt::Body* bod)
{

Quaternion orient;
Vector3 pos;

bod->getPositionOrientation(pos, orient);

return orient;

}

Ogre::Vector3 FPPCamera::get_body_position(Body* bod)
{

Quaternion orient;
Vector3 pos;

bod->getPositionOrientation(pos, orient);

return pos;

}

void FPPCamera::FPPUpdate()
{
OgreNewt::BasicRaycast cam_ray(mWorld,get_body_position(cam_body),Vector3::NEGATIVE_UNIT_Y * 2000 ); // throw a ray from the body to 2000 units below to calculate the // height of the body regard to the floor.
if (cam_ray.getHitCount() > 0)
{
cam_height = cam_ray.getFirstHit().mDistance*10000; // calculale the camera height.
}



}
void FPPCamera::FPPjump()
{
this->jump = true;
}

void FPPCamera::FPPjumpEnd()
{
jump = false;

}
void FPPCamera::FPPup()
{
this->MyVel = this->fps_speed*30;
}

void FPPCamera::FPPdown()
{
this->MyVel = -this->fps_speed*30;
}

void FPPCamera::FPPleft()
{
this->stra = this->fps_speed*30;
}

void FPPCamera::FPPright()
{
this->stra = -this->fps_speed*30;
}


void FPPCamera::FPPupEnd()
{
this->MyVel.z = 0;
this->MyVel.x = 0;
}

void FPPCamera::FPPdownEnd()
{
this->MyVel.z = 0;
this->MyVel.x = 0;
}

void FPPCamera::FPPleftEnd()
{
this->stra.z = 0;
this->stra.x = 0;
}

void FPPCamera::FPPrightEnd()
{
this->stra.z = 0;
this->stra.x = 0;
}


Ok now in PlayState.cpp some part of code:


(...)
//add my camera and apply material pair with floor
FPPcamera = new FPPCamera(mSceneMgr,m_World,mCamera);

OgreNewt::MaterialPair* material_pair2 = new OgreNewt::MaterialPair( m_World, FPPcamera->FPPmat, floormat );

material_pair2->setDefaultFriction(0.0f, 0.0f);
material_pair2->setDefaultSoftness(1);
material_pair2->setDefaultElasticity(0);
material_pair2->setContinuousCollisionMode(0);
(...)


(...)
void PlayState::keyPressed(KeyEvent* e)
{

if (e->getKey() == KC_W)
{
FPPcamera->FPPup();
}

if (e->getKey() == KC_S)
{
FPPcamera->FPPdown();
}

if (e->getKey() == KC_A)
{
FPPcamera->FPPleft();
}

if (e->getKey() == KC_D)
{
FPPcamera->FPPright();
}
}
(...)


(...)
void PlayState::keyReleased(KeyEvent* e)
{
if (e->getKey() == KC_W)
{
FPPcamera->FPPupEnd();
}

if (e->getKey() == KC_S)
{
FPPcamera->FPPdownEnd();

}

if (e->getKey() == KC_A)
{
FPPcamera->FPPleftEnd();

}

if (e->getKey() == KC_D)
{
FPPcamera->FPPrightEnd();

}
}
(...)



(...)
void PlayState::mouseMoved(MouseEvent* e)
{

FPPcamera->camera_rotation_x = -e->getRelX() * FPPcamera->x_sensibility;
FPPcamera->camera_rotation_y = -e->getRelY() * FPPcamera->y_sensibility;

FPPcamera->cam_view_node->pitch(Degree(FPPcamera->camera_rotation_y));
FPPcamera->y_rotation_cont += FPPcamera->camera_rotation_y;

if (FPPcamera->y_rotation_cont > FPPcamera->y_limit_a || FPPcamera->y_rotation_cont < FPPcamera->y_limit_b) // if the total is bigger or smallest than the limits it will be reseted to it's previous value
{
FPPcamera->cam_view_node->pitch(Degree(-FPPcamera->camera_rotation_y ));
FPPcamera->y_rotation_cont -= FPPcamera->camera_rotation_y;
}

}
(...)


(...)
bool PlayState::frameStarted(const FrameEvent& evt)
{

FPPcamera->FPPUpdate();

FPPcamera->camera_rotation_x = 0;
FPPcamera->camera_rotation_y = 0;

return true;
}
(...)


I'm begginer so my code is not very beautiful, but it work :)

This is my whole solution of fppcamera, as you can see i mixed some solutions from other posts. There are some issues but i'm still working.

OvermindDL1

07-09-2006 01:01:50

I'm still amazed at how different everyone seems to do their camera implementations compared to how I do mine. I always have the camera be abstract, able to 'view' things, and it is one of (possibly many, but usually just one) View of a Controller. When told to 'view' something then it either attaches to the eyepoint (or center of object if undefined) if in first-person mode, attaches to third-eye point pointing at the point offset (and not static, it is very fluid, but still not collidable). The Controller, when not attached to anything is a collisionless invisible thing, when it is attached to an Actor class, then it takes control of it by hooking events and other things, also setting the view by default on the possessed item as well. You can infer the rest well enough, but notice how different it is compared to what people generally see/use?

ProfesorX

08-09-2006 01:00:13


Collision* cam_collision = new OgreNewt::CollisionPrimitives::Ellipsoid( mWorld, cam_size ); // create a collision for the body



Vector3 cam_inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( cam_mass, cam_size ); // calculate the inertia ov the body


I have one question with the above code, why do yo calculate inertia of the body using a box, if you defined the body of the camera as an ellipsoid?

Drakon

08-09-2006 05:54:56

...... :oops: my mistake....

it should be:


Vector3 cam_inertia = OgreNewt::MomentOfInertia::CalcEllipsoidSolid(cam_mass,cam_size);

Hansel

11-09-2006 18:16:17

Thanks hansel!!
Because of you code i think i know what i did wrong in mine.
I put the camera inside the collision body instead of put it above the body, and for what i see the body only moves forward, backwards, etc... dont pitch or yaw, you let the camera deal with that.
Correct me if im wrong.
I only want to ask one thing if the only collision part its the body and not the cam if your character wants to pass through a door that have the size of your body but its smaller than body+camera how you deal with that?



Wait for the second part :D

Hansel

11-09-2006 18:17:40

Hansel thanks for your code:) This helps me a lot.

Your video is cool.

I have one question : could you tell me how you created this reflections on the floor??


Look at the fresnel demo in the OgreSDK samples ;)

Hansel

11-09-2006 18:24:48

Wow! As always, your video looks great (you are good both in programming and in graphics, that's impressive) ! I was wondering, after I have seen you have some stacks in your video, if it does not have a big impact on the performance? (I guess it help to have a simple column too) It is so far the big issue I have encountered with Newton.


If i put a lot of boxes in the scene with their collisions activated the performance drops exponentially, specially if the continouscollisionmode is on or a lot of bodies are getting collisions at the same time. I wiss to know if Newton is capable of calculate scenes with more than 100 bodies without framerate drops :(

Hansel

11-09-2006 18:29:59

And here is my soft with camera moving,rotating with force.

http://rapidshare.de/files/32100617/demo.rar.html

I change your code a little but it works now:)



The X sensibilty is so low, have you update it to the framerate? And the program crashes when i exit. But it's very well ;)

I like the design of you "air platform" :D

Hansel

11-09-2006 18:35:15


Collision* cam_collision = new OgreNewt::CollisionPrimitives::Ellipsoid( mWorld, cam_size ); // create a collision for the body



Vector3 cam_inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( cam_mass, cam_size ); // calculate the inertia ov the body


I have one question with the above code, why do yo calculate inertia of the body using a box, if you defined the body of the camera as an ellipsoid?


It's a mistake ;)

Hansel

11-09-2006 18:43:57

I'm still amazed at how different everyone seems to do their camera implementations compared to how I do mine. I always have the camera be abstract, able to 'view' things, and it is one of (possibly many, but usually just one) View of a Controller. When told to 'view' something then it either attaches to the eyepoint (or center of object if undefined) if in first-person mode, attaches to third-eye point pointing at the point offset (and not static, it is very fluid, but still not collidable). The Controller, when not attached to anything is a collisionless invisible thing, when it is attached to an Actor class, then it takes control of it by hooking events and other things, also setting the view by default on the possessed item as well. You can infer the rest well enough, but notice how different it is compared to what people generally see/use?


It's just an example of how to implement a fps camera but no the exact code I use. In my real implementation I define the camera as a type of view for any objet i attach to it. I just need to pass the object to the camera to move it with each "character" ;)

pra

11-09-2006 19:31:03

i just tried out the movement parts of both examples (forces and velocity) for movement, it works, but always when i run over a small object or against a ramp-like object, my player ellipsoid just jumps. here a little paint drawing of it:

it seems to be similar in demo07...


PS: sorry for my bad english :oops:

Hansel

11-09-2006 21:12:59

Yes, I have that problem too. I will investigate it, I promise :D

And don't worry for your english level, a lot of people here have the same problem and nothing happens, just try it. Whre are you from? :D

pra

11-09-2006 21:16:38

/me is from germany^^

I#ll try out some stuff now, like what happens if i make my player smaller, and then i will try this thingy with the ellipsoid with a rolling ball attached at the bottom of it... it was here in this forum somewhere...

Drakon

14-09-2006 23:30:18

Hi Hansel:)

I changed my demo and i want to show you what i did... hehe
...but there is still a lot of work.

first 3 avi

http://drakon.ovh.org/for%20marian%201.avi
http://drakon.ovh.org/for%20marian%202.avi
http://drakon.ovh.org/for%20marian%203.avi

and here is demo:)

http://rapidshare.de/files/32840529/demo_vr_0.2.rar.html

and a little patch for beeter mouse....

http://rapidshare.de/files/32847086/demo_vr_0.2.1.rar.html

i put source in demo folder if anyone want(but it's not cleaned very well;)

Hansel

15-09-2006 11:58:50

Very good demo, Drakon :D


I'm very busy this days but in 1-2 weeks I hope to fix the camera system :D

pra

16-09-2006 13:28:18

i think i have a solution for the ramp/jumping problem...
instead of addForce, try addLocalForce.
(the force vector is added relative to the body's orientation, so you don't need to multiply the orientation with direction vectors)

danni

21-10-2006 19:12:52

I am trying to use this code with PLSM2 and the wiki tutorial on PLSM2 and OgreNewt but I keep falling through the terrain. I tried with and without material pairs but get the same result and inverting the poly's per another threads suggestion.

I could press f3 and see the collision mesh for the terrain, all correct. After loading the serialized data, it crashes if i hit f3. I know others are having this issue too, but their collisions still work.

From searching the forums I have yet to see code where someone has successfully got the wiki tutorial to work.

Anyone have any suggestions what I could be missing?

daedar

25-10-2006 11:29:12

Look at this post:
http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=1445&highlight=plsm2
I had the same problem and it worked well for me.
I also had a problem with loading tiles, do you use tileLoaded method with your own terrain manager?

danni

29-10-2006 14:59:50

I saw this post, but if so this is either a bug in OgreNewt which should be fixed or a hack to make the collision mesh work for PLSM but potentially break other instances of TreeCollision.

I would rather find a cleaner solution than altering the plugins/engine.

Maklaud

08-01-2007 10:09:39

Hi! I use this code, but it doesn't work. My camera is stay on one point and I can't move it. I just can rotate it up and down, but can't rotate it right and left. Can you give me full code, how I can do my camera collide and move?
P.S. I'm so sorry for my bad English :(

Anonymous

18-01-2007 20:08:22

Does someone has the full files (a example running) of this post, where is included the FPPCamera.h and FPPCamera.cpp?

The listed links do not work.

Thanks
Felipe

Drakon

19-01-2007 14:23:39

Here is the link where you can find binaries of my demo

http://www.4shared.com/file/9127225/d3e380eb/demo_vr_023.html

and here is the last source

http://www.4shared.com/file/9126774/67e4e1b6/demo_source.html

pra

20-01-2007 23:10:31

thanks, your demo seems to work pretty good, opposing to my attempts. i'll try to make it the same way, or at least similar

but your code is quite...uhm... hard to understand... you should perhaps tidy it up a little...

pra

25-01-2007 12:53:17

*push*
it works fine for me now, but:
//in the force callback
if(jump)
{
force.y = 20*jump_power;
}

is it "clean" this way? i mean, it adds the jump_power each frame, wouldn't the height depend of the FPS?
would it be better to use a huge jump_power and multiply it with mWorld->getTimeStep()?

RichTufty

06-03-2007 11:38:18

Hansel! Great work, do you know if anyone has converted this to C# and Mogre? If no one has i can convert it, let me know!

balizeiro

15-08-2007 14:49:28

Here is the link where you can find binaries of my demo

http://www.4shared.com/file/9127225/d3e380eb/demo_vr_023.html

and here is the last source

http://www.4shared.com/file/9126774/67e4e1b6/demo_source.html


Both the links are not working, could someone please upload the files again? Thanks ;)

storiman

30-09-2007 00:42:20

can you please update download links, thanks.

storiman

30-09-2007 23:35:29

if someone has the working full source of this project please help me and send a download link. thanks very much.

Drakon

01-10-2007 20:49:12

sorry for not answering... here is proper link for binaries and source
---> http://www.4shared.com/file/22187754/9dee1225/old_demo.html

storiman

01-10-2007 21:13:39

Thanks very much Drakon. Your help is appreciated. :wink:

redhead

19-12-2008 16:43:08

Hi,
the video is great, but I have trouble running your code.
It crashes with:
Run-Time Check Failure #2 - Stack around the variable 'cam_ray' was corrupted.

I wonder, if anyone know what produces the error or if any other better system of fps-like camera have been published.

thanks

pra

23-12-2008 16:35:38

i believe my system to be better, but every time I think it's perfect, I find new bugs :/

especially climbing stairs caused me a lot of trouble. atm i'm using contact callbacks to find out whenever the lower part of the character's body is touching the ground instead of raycasting, and setting contact friction when the character should not move

deshan

08-06-2009 18:32:45

i believe my system to be better, but every time I think it's perfect, I find new bugs :/

Hi pra
Could you please share your experience. All of the links where this thread has provided no longer works. So it is great if u can share ur experience.
I am really sorry if anyone get disturbed with waking up this thread,

pra

22-01-2010 09:26:31

okay. i think i have cleaned my code enough for others to be capable of using it:

please read the comments!
this code won't work. you will still have to make adaptions, of course. for example, i omitted the body creation part, since it's a little complicated in my code.
also, there might be still a lot of unnecessary stuff, or stuff could be missing.

GameChar.h:
using namespace OgreNewt;




class GameChar: public GameObject
{
public:

//i actually have much more parameters and multiple constructors, therefore the init()-function
GameChar(Ogre::Vector3 pos,Ogre::Quaternion orient = Ogre::Quaternion::IDENTITY)
{
init(pos,orient);
}


//standard destruktor
~GameChar();

//OgreNewt force callback.
void forceCallback( OgreNewt::Body* me );
//lvl updates this
void update(Ogre::Real time);
//for the collision callback
void onCollision(GameObject *with,ContCallback *cb);



//aktiviert/deaktiviert das Springen des Chars.
//wird once auf true gesetzt, wird das Springen
//nach dem ersten sprung automatisch deaktiviert
inline void setMoveJump(bool set,bool once = false)
{
jump = set;
jumpOnce = once;

}



inline void setMoveUp(bool set)
{
mvUp = set;

}

inline void setMoveDown(bool set)
{

mvDown = set;

}

inline void setMoveLeft(bool set)
{

mvLeft = set;
}

inline void setMoveRight(bool set)
{
mvRight = set;
}


inline void moveStop()
{
mvDown = false;
mvUp = false;
mvRight = false;
mvLeft = false;
jump = false;
}


inline bool isMoving()
{
bool moveUD = mvDown != mvUp;//i tried to emulate the XOR operator here
bool moveLR = mvRight != mvLeft;
return (moveUD || moveLR);
}


inline void setRun(bool set)
{
run = set;
}

inline bool getRun()
{
return run;
}



inline bool isJumping()
{
return jump;
}

//for looking around with the mouse
void modLookingDirection(Ogre::Real x, Ogre::Real y);
//look along this vector
void setLookingDirection(Ogre::Vector3 dir);

Ogre::Vector3 getLookingDirection()
{
return camNode->getOrientation()*Ogre::Vector3::NEGATIVE_UNIT_Z;
}
//returns the direction where the user wants the char to go
Ogre::Vector3 getMovementVector();
//look at this point
void lookAt(Ogre::Vector3 target);


void setJumpHeight(Ogre::Real height);

Ogre::Real getJumpHeight();




bool
mvUp,
mvDown,
mvLeft,
mvRight; //i decided that this is better than a vector3. not sure why anymore, though

inline Ogre::Vector3 getSize()
{
return mSize;
}



inline Ogre::Quaternion getFullOrientation()
{
return camNode->_getDerivedOrientation();
//return camNode->_getDerivedOrientation();
}
inline Ogre::Vector3 getHeadPosition()
{
return camNode->_getDerivedPosition();//camNode->_getDerivedPosition();
}



private:

void init(Ogre::Vector3 pos,Ogre::Quaternion orient = Ogre::Quaternion::IDENTITY);






Ogre::Real mMass,

maxAccel,
distToFloor,


rotation_x,
y_rotation_cont,
y_limit_a,
y_limit_b;

bool floorColliding; //if lower part is colliding
//JUMPING STUFF
bool jump;//should I jump?
bool jumping;//if I am jumping, is set to false on landing


bool jumpStartFinished; //true if jumping start sequence finished
bool jumpLanded; //true as soon as I land. importand for the landing sound
Ogre::Real jumpTime; //time since jump start
Ogre::Real jumpLandedTime; //time since landing
Ogre::Real jumpPower; //jump accel



//on earth or not?
bool onEarth;

//running or not?
bool run;




Ogre::Vector3 mSize;
Ogre::Vector3 currentVel;


Ogre::SceneNode *camNode;
Ogre::SceneNode *meshNode;
//Ogre::SceneNode *mNode;
Ogre::Entity *ent;





};


GameChar.cpp:
using namespace Ogre;
using namespace OgreNewt;

#define GRAVITY -9.81
#define MAX_JUMPTIME 0.1
#define MIN_JUMPPAUSE 0.5



void GameChar::init(Level *lvl,gamedata_char *myData,Ogre::Vector3 pos,Ogre::Quaternion orient,int SaveGameID)
{
floorColliding = false;


resetLag = 5; //erstmal ne sekunde
startingPos = pos;
startingOrnt = orient;


mNode = NULL;


mSize = Ogre::Vector3(0.5,1.5,0.5);


//uName = myData->id;
mMass = 75;
//jumpPower = 75;
setJumpHeight(1.75);
jumping = false;
jumpTime = 0;
jumpLandedTime = 0;
jump = false;
jumpStartFinished = true;

y_rotation_cont = 0;
y_limit_a = 90;
y_limit_b = -90;

onEarth = false;
attacking = false;
action = false;
run = false;

mvUp = false;
mvDown = false;
mvRight = false;
mvLeft = false;

ent = NULL;


//maxSpeed = 5;
maxAccel = 120;
noMovement = true;
animType = AT_NONE;


//creating scenenodes and stuff...

//creating the body. I use an ellipsoid with 'mSize' as params
//i also have a special function for that, therefore it's not here
mBody->setCustomForceAndTorqueCallback<GameChar>(&GameChar::forceCallback,this);
mBody->setPositionOrientation(pos,orient);
mBody->setMaterialGroupID(mLevel->charMaterial);
mBody->setAutoFreeze(0);


}



GameChar::~GameChar()
{

}


void GameChar::onCollision(GameObject *with,ContCallback *cb)
{
Ogre::Vector3 cPos, cNorm;
cb->getContactPositionAndNormal(cPos,cNorm);
cPos -= getPosition();
if(cPos.y < -(3*mSize.y/4) )//if the contact is in the lower 1/4 of the ellipsoid
{
floorColliding = true;
}
//floorColliding is resetted by forceCallback()

if(!isMoving())
{
cb->setContactStaticFrictionCoef(1,0);
cb->setContactStaticFrictionCoef(1,1);
cb->setContactKineticFrictionCoef(0.1,0);
cb->setContactKineticFrictionCoef(0.1,1);
cb->setContactFrictionState(1,0);
cb->setContactFrictionState(1,1);

}
}


void GameChar::update(Ogre::Real time)
{
//this is updated from frameStarted
//i actually have A LOT of stuff in here (like, animation, sound, weapons, healing,...)
//but for movement, only this is relevant:
onEarth = isOnEarth();
}

void GameChar::forceCallback(OgreNewt::Body* me)
{

currentVel = mBody->getVelocity();


movDirAbs = getMovementVector();




Ogre::Real curMaxSpeed = 1;
if(run)
curMaxSpeed = 5;

movAccel = (-currentVel + movDirAbs*curMaxSpeed) / mWorld->getTimeStep();
if(!onEarth)
movAccel.y = 0;//ignore falling velocity


if(movAccel.squaredLength() > maxAccel*maxAccel)
{
movAccel.normalise();
movAccel *= maxAccel;//do not use too much acceleration, or it's the same as if you use setVelocity
}


//JUMPING BEGIN
//i hate this part. i'm sure it is too complicated and could be MUCH easier...

//jumping = whenever I'm jumping ATM
//jump = if I should jump, because the user pressed the jump button
//jumpLanded = landed after the jump
//jumpTime = time since jump started
//jumpLandedTime = time since landed after the jump o_O
//jumpStartFinished = whenever the jump start sequence is finished
if(jumping && !jump)
{
jumpStartFinished = true;
}

if(jump && !jumping && onEarth)
{
//preparing to jump
jumpLanded = false;
jumping = true;
jumpTime = 0;
jumpLandedTime = 0;
jumpStartFinished = false;
}

Ogre::Real timeStep = mWorld->getTimeStep();
if(jumping)//in the jump
{

jumpTime += timeStep;

if(jumpTime <= MAX_JUMPTIME)
{
if(!jumpStartFinished)
{
//we only add jumpPower in the MAX_JUMPTIME time intervall

movAccel.y = jumpPower;

}
}
else
{
//now time is up, and if we are not on earth anymore, then the start sequence is finished
if(!onEarth)
jumpStartFinished = true;

}


if(onEarth && jumpStartFinished && jumping)//means we landed, but time is not up yet
{
if(!jumpLanded)
{
jumpLanded = true;
}
jumpLandedTime += timeStep;

if(jumpLandedTime >= MIN_JUMPPAUSE)//you need a little time to rest after the jump. otherwise you can use jumping to accelerate, which might not be so good
{
//reset everything
jumping = false;
}
}
}

//FINALLY, add force
mBody->addForce((movAccel+gravAccel) * mMass);




mBody->setOmega(Ogre::Vector3(0,rotation_x*2,0)); //rotate
rotation_x = 0;


floorColliding = false; //reset, onCollision might set it again

}

Ogre::Vector3 GameChar::getMovementVector()
{
Ogre::Vector3 movDir = Ogre::Vector3::ZERO; //Movement Direction, relative to char's orientation
if(mvUp)
movDir.z -= 1;
if(mvDown)
movDir.z += 1;
if(mvLeft)
movDir.x -= 1;
if(mvRight)
movDir.x += 1;
if(movDir == Ogre::Vector3::ZERO)
return Ogre::Vector3::ZERO;

if(movDir.squaredLength() != 1)
movDir.normalise();

Ogre::Vector3 movDirAbs;
Ogre::Quaternion currentOrient;

currentOrient = getOrientation();
movDirAbs = currentOrient * movDir;
movDirAbs.y = 0;

return movDirAbs;


}


bool GameChar::isOnEarth()
{
if(floorColliding)//this is set in the collision callback
return true;

//this part checks distance to floor
Ogre::Vector3 myPos = getPosition();


OgreNewt::BasicRaycast floorRay(mLevel->getWorld(),myPos,myPos+Ogre::Vector3::NEGATIVE_UNIT_Y * 10);

if (floorRay.getHitCount() > 0)
{
OgreNewt::BasicRaycast::BasicRaycastInfo hit;
hit.mBody = NULL;
hit.mDistance = 500;
for(int i=0;i<floorRay.getHitCount();i++)
{
OgreNewt::BasicRaycast::BasicRaycastInfo found = floorRay.getInfoAt(i);
if(found.mBody != mBody && found.mBody->getType() != otWater && found.mDistance < hit.mDistance)
{
//if the body I found is not my own, and is not water and is closer than last result
//you will probably have a different water system than me...
hit = found;
//break;
}
}
if(!hit.mBody)
return false;
distToFloor = hit.mDistance * 10; // calculale the distance to the floor
distToFloor -= mSize.y;// remove char's height;


if(distToFloor > 0.05) //this much over the floor is considered on the floor
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}

}


void GameChar::modLookingDirection(Ogre::Real x, Ogre::Real y)
{

//for the callback:
rotation_x = x;


y_rotation_cont += y;
if (y_rotation_cont > y_limit_a || y_rotation_cont < y_limit_b) // if the total is bigger or smallest than the limits it will be reseted to it's previous value
{
y_rotation_cont -= y;
}
else
{
camNode->pitch(Ogre::Degree(y));
}


}





void GameChar::setLookingDirection(Ogre::Vector3 dir)
{
Ogre::Quaternion curOrnt = getOrientation();
Ogre::Vector3 curLookingDir = curOrnt*Ogre::Vector3::NEGATIVE_UNIT_Z;
Ogre::Vector3 target_noY = dir;
target_noY.y = 0;
Ogre::Vector3 curLookingDir_noY = curLookingDir;
curLookingDir_noY.y=0;
if(!target_noY.positionEquals(Ogre::Vector3::ZERO))
{
Ogre::Quaternion q = curLookingDir_noY.getRotationTo(target_noY);
rotate(q);
}
camNode->setDirection(dir,Ogre::Node::TS_WORLD);


}

void GameChar::lookAt(Ogre::Vector3 target)
{
Ogre::Vector3 lookDir = target - getPosition();
setLookingDirection(lookDir);

}

void GameChar::setJumpHeight(Ogre::Real height)
{
//I actually do not use the GRAVITY constant, it can actually vary...
jumpPower = Ogre::Math::Sqrt ( - height * (2*GRAVITY) ) / MAX_JUMPTIME;

}

Ogre::Real GameChar::getJumpHeight()
{
return - Ogre::Math::Sqr(jumpPower * MAX_JUMPTIME) / (2*GRAVITY);


}


contact callback stuff:
//***ContCallBack.h***
class ContCallback: public OgreNewt::ContactCallback
{
public:
ContCallback();
~ContCallback();

int userBegin();

int userProcess();

void userEnd();

private:
GameObject *obj_0;
GameObject *obj_1;


};
//***ContCallback.cpp***
int ContCallback::userBegin()
{

obj_0 = static_cast<GameObject*>(m_body0->getUserData());
obj_1 = static_cast<GameObject*>(m_body1->getUserData());


return true;

}
int ContCallback::userProcess()
{
//this is the important part
if(obj_0)
obj_0->onCollision(obj_1,this);
if(obj_1)
obj_1->onCollision(obj_0,this);

return true;
}

//usage:

//i use the same callback for everything, and sort them out later
OgreNewt::MaterialPair* defDef = new OgreNewt::MaterialPair( mWorld, defaultMaterialID, defaultMaterialID );
defDef->setContactCallback(mCallback);

Houdini

09-02-2010 18:54:04

pra,

I noticed your source doesn't include the GameObject class. Is this just an empty class with some pure virtual functions or does it contain required variables/function logic needed for everything to work properly?

- Houdini

pra

14-02-2010 00:07:18

I don't think GameObject is necessary.
It's primary function is to contain the body and the scenenode of an object, and to provide some methods like getPosition, which just calls getPositionOrientation of the body and returns only the vector...

there's still a lot of garbage in my code, though. especially in the header part

tod

16-02-2010 21:36:27

For all the beginners out there I'd like to point out that the first examples in this post don't compile with the latest OgreNewt, and pra's sample is incomplete and too much for me to handle/ fix.
I just thought I'll spare someone the pain of trying to use these examples like I did :D.
Anyway, I found this code that at least compiles, with some trivial modifications I think, didn't yet seen it in action though, but it should be a better starting point
http://www.ogre3d.org/addonforums/viewtopic.php?f=4&t=11890.