Page 1 of 1

custom camera problem... plz help !

Posted: Mon Apr 16, 2007 7:33 pm
by danut007ro
Hello !

I'm developing a custom camera that is fps and maya-style in the same time... my code is based on the source code from the FPS camera, but I'm having problems including the code for maya-style camera...

Problem is that when you switch to maya-style (right-click) and move the mouse, the camera is moving silly, and also it is not moving right around YZ.

I'm posting the source-code, maybe someone can help me...

Thanks !

myCamera.h

Code: Select all

#ifndef MYCAMERA_INCLUDED
#define MYCAMERA_INCLUDED

#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

extern IrrlichtDevice *device;
extern IVideoDriver *driver;
extern ISceneManager *smgr;
extern IGUIEnvironment *guienv;

class CMyCamera : public ICameraSceneNode
{
public:
	CMyCamera(ISceneNode* parent, ISceneManager* mgr, IrrlichtDevice* device, s32 id,
		const core::vector3df &position = core::vector3df(0,0,0),
		const core::vector3df &lookat = core::vector3df(0,0,0));
	virtual ~CMyCamera();

	virtual bool OnEvent(SEvent event);
	virtual void OnAnimate(u32 timeMs);

	virtual void setProjectionMatrix(const core::matrix4& projection);
	virtual const core::matrix4& getProjectionMatrix();
	virtual const core::matrix4& getViewMatrix();
	virtual void setTarget(const core::vector3df& pos);
	virtual core::vector3df getTarget() const;
	virtual void setUpVector(const core::vector3df& pos);
	virtual core::vector3df getUpVector() const;
	virtual f32 getNearValue();
	virtual f32 getFarValue();
	virtual f32 getAspectRatio();
	virtual f32 getFOV();
	virtual void setNearValue(f32 zn);
	virtual void setFarValue(f32 zf);
	virtual void setAspectRatio(f32 aspect);
	virtual void setFOV(f32 fovy);

	virtual void OnRegisterSceneNode();
	virtual void render();

	virtual const core::aabbox3d<f32>& getBoundingBox() const;
	virtual const SViewFrustum* getViewFrustum() const;
	virtual void setInputReceiverEnabled(bool enabled);
	virtual bool isInputReceiverEnabled();
	virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0);
	virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
	virtual ESCENE_NODE_TYPE getType() { return ESNT_CAMERA; }

	virtual core::vector3df getAbsolutePosition() const;

	virtual void setRotateSpeed(const f32 speed);
	virtual void setMoveSpeed(const f32 speed);
	virtual void setAroundSpeed(const f32 speed);
	virtual f32 getRotateSpeed();
	virtual f32 getMoveSpeed();
	virtual f32 getAroundSpeed();

protected:
	void animate(u32 timeMs);
	void recalculateProjectionMatrix();
	void recalculateViewArea();

	IrrlichtDevice* pDevice;
	gui::ICursorControl* CursorControl;
	core::position2d<f32> CenterCursor;
	bool Keys[8];

	core::vector3df Target;
	core::vector3df UpVector;
	f32 Fovy;
	f32 Aspect;
	f32 ZNear;
	f32 ZFar;
	SViewFrustum ViewArea;
	bool InputReceiverEnabled;

	f32 MoveSpeed;
	f32 RotateSpeed;
	f32 AroundSpeed;

	bool firstUpdate;
	s32 LastAnimationTime;
	core::vector3df TargetVector;

	vector3df initPosition, initTarget;
};

#endif
myCamera.cpp

Code: Select all

#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#include "myCamera.h"

const f32 MAX_VERTICAL_ANGLE = 88;

CMyCamera::CMyCamera(ISceneNode* parent, ISceneManager* mgr, IrrlichtDevice* device, s32 id, const core::vector3df& position, const core::vector3df& lookat)
: ICameraSceneNode(parent, mgr, id, position, core::vector3df(0, 0, 0), core::vector3df(1, 1, 1)),
pDevice(device), Target(lookat), UpVector(0, 1, 0), Fovy(core::PI / 2), Aspect(4 / 3), ZNear(1), ZFar(3000),
InputReceiverEnabled(true), MoveSpeed(100), RotateSpeed(100), AroundSpeed(-150), firstUpdate(true), initPosition(position), initTarget(lookat)
{
	video::IVideoDriver* d = mgr->getVideoDriver();
	if (d)
		Aspect = (f32)d->getCurrentRenderTargetSize().Width / (f32)d->getCurrentRenderTargetSize().Height;

	if (pDevice)
	{
		CursorControl = pDevice->getCursorControl();
		if (CursorControl)
			CursorControl->grab();
	}

	MoveSpeed /= 1000.0f;
	for (int i = 0; i < 8; i++)
        Keys[i] = false;

	recalculateProjectionMatrix();
	recalculateViewArea();
}

CMyCamera::~CMyCamera()
{
	if (CursorControl)
		CursorControl->drop();
}

bool CMyCamera::OnEvent(SEvent event)
{
	if (InputReceiverEnabled)
	{
		if (event.EventType == EET_KEY_INPUT_EVENT)
			switch (event.KeyInput.Key)
			{
			case irr::KEY_KEY_W :
				Keys[0] = event.KeyInput.PressedDown;
				return true;
			case irr::KEY_KEY_S :
				Keys[1] = event.KeyInput.PressedDown;
				return true;
			case irr::KEY_KEY_A :
				Keys[2] = event.KeyInput.PressedDown;
				return true;
			case irr::KEY_KEY_D :
				Keys[3] = event.KeyInput.PressedDown;
				return true;
			case irr::KEY_KEY_R :
				Keys[4] = event.KeyInput.PressedDown;
				return true;
			case irr::KEY_KEY_F :
				Keys[5] = event.KeyInput.PressedDown;
				return true;
            case irr::KEY_SHIFT :
                Keys[6] = event.KeyInput.PressedDown;
                return true;
            case irr::KEY_KEY_X :
                setPosition(initPosition);
                setTarget(initTarget);
                return true;
            default :
                return false;
			}

        if (event.EventType == EET_MOUSE_INPUT_EVENT)
            switch (event.MouseInput.Event)
            {
            case irr::EMIE_RMOUSE_PRESSED_DOWN :
                Keys[7] = true;
                return true;
            case irr::EMIE_RMOUSE_LEFT_UP :
                Keys[7] = false;
                return true;
            default :
                return false;
            }
	}
	return false;
}

void CMyCamera::animate(u32 timeMs)
{
	// camera activa ?
	const u32 camIsMe = SceneManager->getActiveCamera() == this;

	if (firstUpdate)
	{
		if (CursorControl && camIsMe)
		{
			CursorControl->setPosition(0.5f, 0.5f);
			CenterCursor = CursorControl->getRelativePosition();
		}

		LastAnimationTime = pDevice->getTimer()->getTime();

		firstUpdate = false;
	}

	// calculeaza diferenta de timp, doar pt. camera activa = curenta
	f32 timeDiff = 0.f;
	if (camIsMe)
	{
		timeDiff = (f32)(timeMs - LastAnimationTime);
		LastAnimationTime = timeMs;
	}

	// update position
	core::vector3df pos = getPosition();

    if (Keys[7])
    {
		Target.set(0,0,1);

        f32 rotX = 0, rotY = 0;

		if (CursorControl && InputReceiverEnabled && camIsMe)
		{
			core::position2d<f32> cursorpos = CursorControl->getRelativePosition();

			if (!core::equals(cursorpos.X, CenterCursor.X) || !core::equals(cursorpos.Y, CenterCursor.Y))
			{
			    f32 aroundSpeed = AroundSpeed;
                if (Keys[6])
                    aroundSpeed /= 3;
			    rotY = (0.5f - cursorpos.Y) * timeDiff * aroundSpeed;
                rotX = (0.5f - cursorpos.X) * timeDiff * aroundSpeed;
				CursorControl->setPosition(0.5f, 0.5f);
				CenterCursor = CursorControl->getRelativePosition();
			}
		}

		// set target
		core::matrix4 mat;
		mat.setRotationDegrees(core::vector3df(RelativeRotation.X, RelativeRotation.Y, 0));
		mat.transformVect(Target);

		core::vector3df movedir = Target;
		movedir.normalize();

		if (InputReceiverEnabled && camIsMe)
		{
		    f32 moveSpeed = MoveSpeed;
		    if (Keys[6])
                moveSpeed /= 3;
			if (Keys[0])
				pos += movedir * timeDiff * moveSpeed;
			if (Keys[1])
				pos -= movedir * timeDiff * moveSpeed;
		}

        pos.rotateXZBy(rotX, vector3df(0, 0, 0));
        pos.rotateYZBy(rotY, vector3df(0, 0, 0));

        UpVector.set(0, 1, 0);
        UpVector.rotateXYBy(-rotY, core::vector3df(0, 0, 0));
        UpVector.rotateXZBy(-rotX + 180.f, core::vector3df(0, 0, 0));

        setTarget(vector3df(0, 0, 0));
		setPosition(pos);
    }
	else
	{
		Target.set(0, 0, 1);

		if (CursorControl && InputReceiverEnabled && camIsMe)
		{
			core::position2d<f32> cursorpos = CursorControl->getRelativePosition();

			if (!core::equals(cursorpos.X, CenterCursor.X) || !core::equals(cursorpos.Y, CenterCursor.Y))
			{
				RelativeRotation.X *= -1.0f;
				RelativeRotation.Y *= -1.0f;
				RelativeRotation.Y += (0.5f - cursorpos.X) * RotateSpeed;
				RelativeRotation.X = core::clamp(RelativeRotation.X + (0.5f - cursorpos.Y) * RotateSpeed, -MAX_VERTICAL_ANGLE, +MAX_VERTICAL_ANGLE);
				RelativeRotation.X *= -1.0f;
				RelativeRotation.Y *= -1.0f;

				CursorControl->setPosition(0.5f, 0.5f);
				CenterCursor = CursorControl->getRelativePosition();
			}
		}

		// set target
		core::matrix4 mat;
		mat.setRotationDegrees(core::vector3df(RelativeRotation.X, RelativeRotation.Y, 0));
		mat.transformVect(Target);

		core::vector3df movedir = Target;
		movedir.normalize();

		if (InputReceiverEnabled && camIsMe)
		{
		    f32 moveSpeed = MoveSpeed;
		    if (Keys[6])
                moveSpeed /= 3;
			if (Keys[0])
				pos += movedir * timeDiff * moveSpeed;
			if (Keys[1])
				pos -= movedir * timeDiff * moveSpeed;
			core::vector3df strafevect = Target;
			strafevect = strafevect.crossProduct(UpVector);
			strafevect.normalize();
			if (Keys[2])
				pos += strafevect * timeDiff * moveSpeed;
			if (Keys[3])
				pos -= strafevect * timeDiff * moveSpeed;
            if (Keys[4])
                pos += vector3df(0, 1, 0) * timeDiff * moveSpeed;
            if (Keys[5])
                pos -= vector3df(0, 1, 0) * timeDiff * moveSpeed;
		}

		setPosition(pos);
	}

    TargetVector = Target;
    Target += pos;
}

void CMyCamera::OnAnimate(u32 timeMs)
{
	animate(timeMs);

	core::list<ISceneNodeAnimator*>::Iterator ait = Animators.begin();
	for (; ait != Animators.end(); ait++)
		(*ait)->animateNode(this, timeMs);

	updateAbsolutePosition();
	Target = getPosition() + TargetVector;

	core::list<ISceneNode*>::Iterator it = Children.begin();
	for (; it != Children.end(); it++)
		(*it)->OnAnimate(timeMs);
}

void CMyCamera::setInputReceiverEnabled(bool enabled)
{
   if(!InputReceiverEnabled && enabled)
      firstUpdate = true;

   InputReceiverEnabled = enabled;
}

bool CMyCamera::isInputReceiverEnabled()
{
	_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
	return InputReceiverEnabled;
}

void CMyCamera::setProjectionMatrix(const core::matrix4& projection)
{
	ViewArea.Matrices[video::ETS_PROJECTION] = projection;
	ViewArea.setTransformState(video::ETS_PROJECTION);
}

const core::matrix4& CMyCamera::getProjectionMatrix()
{
	return ViewArea.Matrices[video::ETS_PROJECTION];
}

const core::matrix4& CMyCamera::getViewMatrix()
{
	return ViewArea.Matrices[video::ETS_VIEW];
}

void CMyCamera::setTarget(const core::vector3df& pos)
{
	updateAbsolutePosition();
	core::vector3df vect = pos - getAbsolutePosition();
	vect = vect.getHorizontalAngle();
	RelativeRotation.X = vect.X;
	RelativeRotation.Y = vect.Y;

	if (RelativeRotation.X > MAX_VERTICAL_ANGLE)
		 RelativeRotation.X -= 360.0f;
}

core::vector3df CMyCamera::getTarget() const
{
	return Target;
}

void CMyCamera::setUpVector(const core::vector3df& pos)
{
	UpVector = pos;
}

core::vector3df CMyCamera::getUpVector() const
{
	return UpVector;
}

f32 CMyCamera::getNearValue()
{
	return ZNear;
}

f32 CMyCamera::getFarValue()
{
	return ZFar;
}

f32 CMyCamera::getAspectRatio()
{
	return Aspect;
}

f32 CMyCamera::getFOV()
{
	return Fovy;
}

void CMyCamera::setNearValue(f32 f)
{
	ZNear = f;
	recalculateProjectionMatrix();
}

void CMyCamera::setFarValue(f32 f)
{
	ZFar = f;
	recalculateProjectionMatrix();
}

void CMyCamera::setAspectRatio(f32 f)
{
	Aspect = f;
	recalculateProjectionMatrix();
}

void CMyCamera::setFOV(f32 f)
{
	Fovy = f;
	recalculateProjectionMatrix();
}

void CMyCamera::recalculateProjectionMatrix()
{
	ViewArea.Matrices[video::ETS_PROJECTION].buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar);
	ViewArea.setTransformState(video::ETS_PROJECTION);
}

void CMyCamera::OnRegisterSceneNode()
{
	core::vector3df pos = getAbsolutePosition();
	core::vector3df tgtv = Target - pos;
	tgtv.normalize();

	core::vector3df up = UpVector;
	up.normalize();

	f32 dp = tgtv.dotProduct(up);

	if (core::equals(fabs(dp), 1.f))
	{
		up.X += 0.5f;
	}

	ViewArea.Matrices[video::ETS_VIEW].buildCameraLookAtMatrixLH(pos, Target, up);
	ViewArea.setTransformState(video::ETS_VIEW);
	recalculateViewArea();

	if (SceneManager->getActiveCamera() == this)
		SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);

	if (IsVisible)
		ISceneNode::OnRegisterSceneNode();
}

void CMyCamera::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	if (driver)
	{
		driver->setTransform(video::ETS_PROJECTION, ViewArea.Matrices[video::ETS_PROJECTION]);
		driver->setTransform(video::ETS_VIEW, ViewArea.Matrices[video::ETS_VIEW]);
	}
}

const core::aabbox3d<f32>& CMyCamera::getBoundingBox() const
{
	return ViewArea.getBoundingBox();
}

const SViewFrustum* CMyCamera::getViewFrustum() const
{
	return &ViewArea;
}

core::vector3df CMyCamera::getAbsolutePosition() const
{
	return AbsoluteTransformation.getTranslation();
}

void CMyCamera::recalculateViewArea()
{
	ViewArea.cameraPosition = getAbsolutePosition();
	ViewArea.setFrom ( ViewArea.Matrices [ SViewFrustum::ETS_VIEW_PROJECTION_3 ] );
/*
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	if ( driver)
	{
		driver->setTransform(video::ETS_PROJECTION, ViewArea.Matrices [ video::ETS_PROJECTION ] );
		driver->setTransform(video::ETS_VIEW, ViewArea.Matrices [ video::ETS_VIEW ] );
	}
*/
}

void CMyCamera::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
{
	ISceneNode::serializeAttributes(out, options);

	out->addVector3d("Target", Target);
	out->addVector3d("UpVector", UpVector);
	out->addFloat("Fovy", Fovy);
	out->addFloat("Aspect", Aspect);
	out->addFloat("ZNear", ZNear);
	out->addFloat("ZFar", ZFar);
}

void CMyCamera::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
	ISceneNode::deserializeAttributes(in, options);

	Target = in->getAttributeAsVector3d("Target");
	UpVector = in->getAttributeAsVector3d("UpVector");
	Fovy = in->getAttributeAsFloat("Fovy");
	Aspect = in->getAttributeAsFloat("Aspect");
	ZNear = in->getAttributeAsFloat("ZNear");
	ZFar = in->getAttributeAsFloat("ZFar");

	recalculateProjectionMatrix();
	recalculateViewArea();
}

void CMyCamera::setRotateSpeed(const f32 speed)
{
	RotateSpeed = speed;
}

void CMyCamera::setMoveSpeed(const f32 speed)
{
	MoveSpeed = speed;
}

void CMyCamera::setAroundSpeed(const f32 speed)
{
	MoveSpeed = speed;
}

f32 CMyCamera::getRotateSpeed()
{
	return RotateSpeed;
}

f32 CMyCamera::getMoveSpeed()
{
	return MoveSpeed;
}

f32 CMyCamera::getAroundSpeed()
{
	return MoveSpeed;
}

Posted: Thu Apr 19, 2007 7:58 pm
by danut007ro
no one ?

Posted: Thu Apr 19, 2007 9:17 pm
by monkeycracks
First, you should probably allow more than 25 minutes for someone to answer, a lot of people could be at work/across the world and asleep.

Second, wouldn't it be easier to just setup an event receiver and change the camera when the right mouse button is clicked?

addCameraSceneNodeMaya
addCameraSceneNodeFPS

Third, sorry, don't know how to fix your current problem ;)

Posted: Thu Apr 19, 2007 11:33 pm
by hybrid
:lol: Was 1 day and 25 minutes :wink:
To help with this topic I'd suggest that you cut down the code to the problematic part, i.e. check which parts are working and suggest some possible problems or not working fixes you already tried. This shows that you know at least something about the Engine and C++ such that an advice would not completely wasted.
But I don't know any help here, yet, as I did not read through all the code.

Posted: Thu Apr 19, 2007 11:44 pm
by danut007ro
well, I guess the problem is in the animate() function, somewhere in here :

Code: Select all

    if (Keys[7])
    {
		Target.set(0,0,1);

        f32 rotX = 0, rotY = 0;

		if (CursorControl && InputReceiverEnabled && camIsMe)
		{
			core::position2d<f32> cursorpos = CursorControl->getRelativePosition();

			if (!core::equals(cursorpos.X, CenterCursor.X) || !core::equals(cursorpos.Y, CenterCursor.Y))
			{
			    f32 aroundSpeed = AroundSpeed;
                if (Keys[6])
                    aroundSpeed /= 3;
			    rotY = (0.5f - cursorpos.Y) * timeDiff * aroundSpeed;
                rotX = (0.5f - cursorpos.X) * timeDiff * aroundSpeed;
				CursorControl->setPosition(0.5f, 0.5f);
				CenterCursor = CursorControl->getRelativePosition();
			}
		}

		// set target
		core::matrix4 mat;
		mat.setRotationDegrees(core::vector3df(RelativeRotation.X, RelativeRotation.Y, 0));
		mat.transformVect(Target);

		core::vector3df movedir = Target;
		movedir.normalize();

		if (InputReceiverEnabled && camIsMe)
		{
		    f32 moveSpeed = MoveSpeed;
		    if (Keys[6])
                moveSpeed /= 3;
			if (Keys[0])
				pos += movedir * timeDiff * moveSpeed;
			if (Keys[1])
				pos -= movedir * timeDiff * moveSpeed;
		}

        pos.rotateXZBy(rotX, vector3df(0, 0, 0));
        pos.rotateYZBy(rotY, vector3df(0, 0, 0));

        UpVector.set(0, 1, 0);
        UpVector.rotateXYBy(-rotY, core::vector3df(0, 0, 0));
        UpVector.rotateXZBy(-rotX + 180.f, core::vector3df(0, 0, 0));

        setTarget(vector3df(0, 0, 0));
		setPosition(pos);
    }
But I cannot bet on that since the code from the maya-style (this code) is mixed with the code from fps-style...

Anyway, thank you very much....