How to create a FPS style camera? SOLUTION IN HERE

balizeiro

16-08-2007 18:15:25

I guess this is the most asked question around here, at least by the number of posts that i read. Unfortunately for me, I wasn't able to make any of the mini-tutorials present in some of them work correctly for me. Maybe they were made for another version of OGRE or OgreNewton :?

So I leave here yet another post about the same theme :(
I'm using both the latest version of OGRE and OgreNewton.

My application consists basically of 2 mesh files, one is a room to which I must detect collisions with the player (camera) to prevent wall and floor walkthrough, and the other is a small cube thats must move in a real way when the player (camera) touches it.

If someone has some tutorial or sample application from which I could derive mine from, and that would do the big favor of posting it here, it would be more than perfect :wink:

Thanks in advance

balizeiro

20-08-2007 15:33:15

Just finished my implementation of a FPS camera that is able to move up stairs, based on this implementation http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=1261 of shoki's camera.

I'll post it here by the end of the day, because I still need to optimize it a little bit.

This implementation, in contrast to all the others present in the forum, is fully compatible with Eihort and the the latest version of OgreNewt :wink:

balizeiro

21-08-2007 22:52:05

As promised here it goes:


OgreNewtonApplication.h


#pragma once
#include <ExampleApplication.h>

#include <OgreNewt.h>
using namespace Ogre;
using namespace OgreNewt;


class OgreNewtonApplication : public ExampleApplication
{
public:
OgreNewtonApplication(void);
~OgreNewtonApplication(void);

protected:
void createFrameListener();
void createScene();
void force_callback(Body* me);

private:
World* m_World;
SceneNode* CamNode;
SceneNode* NodePrincipal;
FrameListener* mNewtonListener;
Body* FormaPlayer;
Entity* mEntity;

};







OgreNewtonApplication.cpp


#include "OgreNewtonApplication.h"
#include "OgreNewtonFrameListener.h"
#include <OgreNewt.h>



const Vector3 PlayerSize = Vector3(20,150,20);
const Real PlayerWeight = 100;
const Real gravity = 9.8;

OgreNewtonApplication::OgreNewtonApplication(void)
{
// create OgreNewt world.
m_World = new World();
m_World->setWorldSize(Vector3(-10000,-10000,-10000),Vector3(10000,10000,10000));
}

OgreNewtonApplication::~OgreNewtonApplication(void)
{
// delete the world when we're done.
delete m_World;

// de-initialize the debugger.
Debugger::getSingleton().deInit();
}



void OgreNewtonApplication::createScene()
{
mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
mSceneMgr->setShadowTechnique( SHADOWTYPE_STENCIL_ADDITIVE );


Entity* floor;
SceneNode* floornode;
floor = mSceneMgr->createEntity("Floor", "c:\\adeus.mesh" );
floornode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "FloorNode" );
floornode->setPosition(0,0,0);
floornode->attachObject( floor );
floor->setMaterialName( "Simple/BeachStones" );
floor->setCastShadows( false );

Collision* col = new CollisionPrimitives::TreeCollision( m_World, floornode, false );
Body* bod = new Body( m_World, col );
delete col;

bod->attachToNode( floornode );
bod->setPositionOrientation( Vector3(0,0,0), Quaternion::IDENTITY );



NodePrincipal = mSceneMgr->getRootSceneNode()->createChildSceneNode();

CamNode = NodePrincipal->createChildSceneNode();
CamNode->attachObject( mCamera );

mCamera->setPosition(0.0, 75.0, 0.0);

Collision* ent_col = new CollisionPrimitives::Box( m_World,PlayerSize);
FormaPlayer = new Body( m_World, ent_col );
delete ent_col;

//Set PlayerPosition
FormaPlayer->setPositionOrientation(Vector3(70,-68,200),Quaternion::IDENTITY);

Vector3 ent_inertia = MomentOfInertia::CalcBoxSolid(PlayerWeight,PlayerSize);
FormaPlayer->setMassMatrix( 100 , ent_inertia );
FormaPlayer->attachToNode( NodePrincipal );


Vector3 Up_Direction_1( 0 , 1 , 0 );
BasicJoints::UpVector* Up_Vector_1;
Up_Vector_1 = new BasicJoints::UpVector( m_World, FormaPlayer, Up_Direction_1 );

Vector3 Up_Direction_2 ( 1 , 0 , 0 );
BasicJoints::UpVector* Up_Vector_2;
Up_Vector_2 = new BasicJoints::UpVector( m_World, FormaPlayer, Up_Direction_2 );


FormaPlayer->setCustomForceAndTorqueCallback< OgreNewtonApplication >( &OgreNewtonApplication::force_callback, this );


Light* light;
light = mSceneMgr->createLight( "Light1" );
light->setType( Light::LT_POINT );
light->setPosition( Vector3(0.0, 100.0, 100.0) );



}

void OgreNewtonApplication::createFrameListener()
{
mFrameListener = new OgreNewtonFrameListener( mWindow, mCamera, mSceneMgr, m_World, CamNode, FormaPlayer, mEntity );
mRoot->addFrameListener(mFrameListener);

mNewtonListener = new BasicFrameListener( mWindow, mSceneMgr, m_World, 60 );
mRoot->addFrameListener(mNewtonListener);
}


void OgreNewtonApplication::force_callback(Body* me)
{
me->addForce(Vector3(0,gravity * -10000,0));
}







OgreNewtonFrameListener.h


#pragma once
#include "ExampleFrameListener.h"
#include <OgreNewt.h>

using namespace OgreNewt;



class OgreNewtonFrameListener : public ExampleFrameListener
{
private:
void OgreNewtonFrameListener::force_callback(Body* me);
bool frameStarted(const FrameEvent &evt);
void climbStairs();
void showRay(Vector3 point1, Vector3 point2,int nb);

protected:
World* m_World;
SceneNode* CamNode;
SceneManager* mSceneMgr;
int BallCount;
Body* FormaPlayer;
Collision* ent_col;
Entity* mEntity;

public:
OgreNewtonFrameListener(RenderWindow* win, Camera* cam, SceneManager* mgr, World* W, SceneNode* ncam, Body* entity_body, Entity* mEntity_buffer);
~OgreNewtonFrameListener(void);
};






OgreNewtonFrameListener.cpp


#include "OgreNewtonFrameListener.h"
#include <math.h>

using namespace OgreNewt;

OIS::Keyboard* KeyboardInput;
OIS::Mouse* MouseInput;

int IteradorRectas=0;
MaterialPtr myManualObjectMaterial;
const Real MovementSpeed = 200;
Real timer = 0;



class SimpleKeyListener : public OIS::KeyListener
{
private:
Body* PlayerBody;

public:
SimpleKeyListener(Body* onb)
{
PlayerBody = onb;
}

bool keyPressed(const OIS::KeyEvent& e)
{
return true;
}

bool keyReleased(const OIS::KeyEvent& e)
{
PlayerBody->setVelocity(Vector3(0,0,0));
return true;
}
};


OgreNewtonFrameListener::OgreNewtonFrameListener(RenderWindow* win, Camera* cam, SceneManager* mgr, World* W, SceneNode* ncam, Body* entity_body, Entity* mEntity_buffer) :
ExampleFrameListener(win,cam, true, true)
{
m_World = W;
CamNode = ncam;
mSceneMgr = mgr;
FormaPlayer = entity_body;
mEntity = mEntity_buffer;


KeyboardInput = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
MouseInput = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));

SimpleKeyListener* keyListener = new SimpleKeyListener(FormaPlayer);
KeyboardInput->setEventCallback(keyListener);


myManualObjectMaterial = MaterialManager::getSingleton().create("manualMaterial","debugger");
myManualObjectMaterial->setReceiveShadows(false);
myManualObjectMaterial->getTechnique(0)->setLightingEnabled(true);
myManualObjectMaterial->getTechnique(0)->getPass(0)->setDiffuse(1,0,0,0);
myManualObjectMaterial->getTechnique(0)->getPass(0)->setAmbient(1,0,0);
myManualObjectMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1,0,0);
}

OgreNewtonFrameListener::~OgreNewtonFrameListener(void)
{
}



bool OgreNewtonFrameListener::frameStarted(const FrameEvent &evt)
{
Vector3 trans, strafe;
Quaternion quat;
[b][u]quat = mCamera->getOrientation();[/u][/b]


trans = quat * Vector3(0.0,0.0,-MovementSpeed);

strafe = quat * Vector3(MovementSpeed,0.0,0.0);

KeyboardInput->capture();
MouseInput->capture();


FormaPlayer->unFreeze();


if (MouseInput->getMouseState().buttonDown(OIS::MB_Right))
{
const OIS::MouseState &ms = MouseInput->getMouseState();
[b][u]mCamera->pitch( Degree(ms.Y.rel * -0.5) );
mCamera->yaw( Degree(ms.X.rel * -0.5) );[/b][/u]
}

if (KeyboardInput->isKeyDown(OIS::KC_ESCAPE))
return false;

if (KeyboardInput->isKeyDown(OIS::KC_SPACE))
{
if (timer <= 0.0)
{
Real RaioEsfera=15;

String name = "Body "+StringConverter::toString( BallCount++ );

Entity* ent = mSceneMgr->createEntity( name, "ellipsoid.mesh" );
SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
node->setScale(RaioEsfera,RaioEsfera,RaioEsfera);
node->attachObject( ent );

ent->setMaterialName( "Simple/dirt01" );
ent->setNormaliseNormals(true);

Collision* col = new CollisionPrimitives::Ellipsoid( m_World, Vector3(RaioEsfera,RaioEsfera,RaioEsfera) );
Body* body = new Body( m_World, col );
delete col;

body->setMassMatrix( 10 , MomentOfInertia::CalcSphereSolid( 10 , RaioEsfera ) );
body->attachToNode( node );

float zDif = cos(quat.getYaw().valueRadians())*50; //*50 so that it gets away from the body
float xDif = sin(quat.getYaw().valueRadians())*50;

Vector3 startingPoint = CamNode->getWorldPosition();
startingPoint.x -= xDif;
startingPoint.z -= zDif;
startingPoint.y += 50;

Vector3 dir = quat * Vector3(0,0,-1);

body->setStandardForceCallback();
body->setPositionOrientation( startingPoint, quat );
body->setVelocity( (dir * 500) );


timer = 0.2;
}
timer -= evt.timeSinceLastFrame;
}


if (KeyboardInput->isKeyDown(OIS::KC_A) && KeyboardInput->isKeyDown(OIS::KC_W))
{
FormaPlayer->setVelocity( trans - strafe );

goto continuaExec;
}


if (KeyboardInput->isKeyDown(OIS::KC_W) && KeyboardInput->isKeyDown(OIS::KC_D))
{
FormaPlayer->setVelocity( trans + strafe );

goto continuaExec;
}


if (KeyboardInput->isKeyDown(OIS::KC_D) && KeyboardInput->isKeyDown(OIS::KC_S))
{
FormaPlayer->setVelocity( -trans + strafe );

goto continuaExec;
}


if (KeyboardInput->isKeyDown(OIS::KC_S) && KeyboardInput->isKeyDown(OIS::KC_A))
{
FormaPlayer->setVelocity( -trans - strafe );

goto continuaExec;
}


if (KeyboardInput->isKeyDown(OIS::KC_A))
{
FormaPlayer->setVelocity( -strafe );

goto continuaExec;
}

if (KeyboardInput->isKeyDown(OIS::KC_D))
{
FormaPlayer->setVelocity( strafe );

goto continuaExec;
}

if (KeyboardInput->isKeyDown(OIS::KC_W))
{
FormaPlayer->setVelocity( trans );

goto continuaExec;
}

if (KeyboardInput->isKeyDown(OIS::KC_S))
{
FormaPlayer->setVelocity( -trans );

goto continuaExec;
}


continuaExec:
climbStairs();

return true;
}



void OgreNewtonFrameListener::force_callback(Body* me)
{
me->addForce(Vector3(0,9.8 * -1000,0)); //zzz Meter a gravidade no global
}





void OgreNewtonFrameListener::climbStairs()
{

const int numeroRaios = 31;
int i;

Vector3 pos;
Quaternion quat;

Vector3 startPoint;
Vector3 endPoint;

Vector3 rayBegin;
Vector3 rayDirection;

Vector3 floor;


BasicRaycast** rayTable = new BasicRaycast* [numeroRaios];
Ray* ray[numeroRaios];


FormaPlayer->getPositionOrientation(pos,quat);
[b][u]quat=mCamera->getOrientation();[/u][/b]
Ray camRay(pos,Vector3(0,-1,0));
floor = pos;
floor.y = floor.y-35;





for (i = 0 ; i < numeroRaios ; i++)
{
rayBegin = floor;
rayBegin.y = rayBegin.y + i;

rayDirection = FormaPlayer->getVelocity();
rayDirection.y = 100;
rayDirection.x = -rayDirection.x;
rayDirection.z = -rayDirection.z;


rayDirection = rayDirection.normalisedCopy();

ray[i] = new Ray(rayBegin,rayDirection);

startPoint = ray[i]->getOrigin();
endPoint = ray[i]->getPoint(-40.0f);

rayTable[i] = new BasicRaycast(m_World,startPoint,endPoint);


showRay(startPoint,endPoint,i);
}
IteradorRectas++;



int PrimeiraColisao = -1;
const int NumMaxVect = numeroRaios-1;

for (i = NumMaxVect ; i >= 0 ; i--)
{
if (rayTable[i]->getFirstHit().mBody != NULL)
{
PrimeiraColisao=i;
break;
}
}


if ( PrimeiraColisao > 0 && PrimeiraColisao < NumMaxVect)
{
Vector3 highestPt = ray[PrimeiraColisao]->getPoint(rayTable[PrimeiraColisao]->getFirstHit().mDistance);
highestPt.y = highestPt.y + 75;
FormaPlayer->setPositionOrientation(highestPt , Quaternion::IDENTITY);
}
}


void OgreNewtonFrameListener::showRay(Vector3 point1, Vector3 point2,int nb)
{

if (nb==0 || nb==30 ) //To only show a couple of lines
{

char ola [50];
sprintf(ola,"manual%d_%d",IteradorRectas, nb);
ManualObject* myManualObject = new ManualObject(ola);
SceneNode* myManualObjectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(ola);


myManualObject->begin("manualMaterial", RenderOperation::OT_LINE_LIST);
myManualObject->position(point1);
myManualObject->position(point2);


myManualObject->end();

myManualObjectNode->attachObject(myManualObject);
}
}



Sorry about the fact that some variable names are in Portuguese, but I was too lazy to change it :)

Comments are more than welcome :wink:

feng007lhf

31-08-2007 15:01:48

can you give me the adeus.mesh file, i want to debug it.
ths.

balizeiro

31-08-2007 17:50:10

The adeus.mesh in any mesh that you want. But when I get home I'll upload it ;)

EDIT: Here you go http://www.4shared.com/file/23278314/45b8160/adeus.html

There's still a little bit of work to do in the mesh, but it works :)

balizeiro

31-08-2007 20:59:35

Just found a couple of bugs in the application concerning camera movement.
I'm just correcting it and will post the changes later on ;)

EDIT: Corrected. Just check the previous code for . Tried to bold and underline the text, but didn't work :wink:

feng007lhf

01-09-2007 01:38:09

thank you! but another mesh file i also need: ellipsoid.mesh file in framestarted funciton.

I meet a question when i make myself FFP Camera in ogrenewt. when i use arrow keys control my camera, it can't move, but i have seted its velocity. if i want to move the camera, i must add a force in the camera orientation and set the camera's velocity along the diretion. is it ?. in my scene, i create a floor body and a camera body, set the firiction bewteen both is 0, but camera can't move. my framestart code as follows:

bool OgreNewtonFrameListener::frameStarted(const FrameEvent &evt)
{
mKeyboard->capture();
mMouse->capture();

mCameraNode->yaw( Degree(mMouse->getMouseState().X.rel * -0.2), SceneNode::TS_WORLD );
//msnCam->pitch(Degree(mMouse->getMouseState().Y.rel * -0.2));
mCameraBody->setPositionOrientation(mCameraNode->getPosition(), mCameraNode->getOrientation());

mSpeed = 50;

Vector3 position;
Vector3 dir;
Quaternion orientation;
mCameraBody->getPositionOrientation(position,orientation);

if (mKeyboard->isKeyDown(OIS::KC_UP))
{
dir = orientation * Vector3::UNIT_Z;
mCameraBody->setVelocity(dir * mSpeed);
}
if (mKeyboard->isKeyDown(OIS::KC_DOWN))
{
dir = orientation * Vector3::NEGATIVE_UNIT_Z;
mCameraBody->setVelocity(dir * mSpeed);
}
if (mKeyboard->isKeyDown(OIS::KC_LEFT))
{
dir = orientation * Vector3::UNIT_X;
mCameraBody->setVelocity(dir * mSpeed);
}
if (mKeyboard->isKeyDown(OIS::KC_RIGHT))
{
dir = orientation * Vector3::NEGATIVE_UNIT_X;
mCameraBody->setVelocity(dir * mSpeed);
}
if (mKeyboard->isKeyDown(OIS::KC_ESCAPE))
return false;
return true;
}

tlc

15-02-2008 04:16:24

Just found a couple of bugs in the application concerning camera movement.
I'm just correcting it and will post the changes later on ;)

EDIT: Corrected. Just check the previous code for . Tried to bold and underline the text, but didn't work :wink:


Hi Balizeiro,

Tried out your wonderful FPS style camera. Successfully compiled, but I have problem with the viewport - a full-grey screen without see any objects, no matter how I moved the mouse and keyboard.

I believe the bugs you mentioned in your earlier post is referring to mCamNode instead of mCamera, am I correct?

Even I changed that, still my viewport is still showing grey screen :(