如何解决奇怪的相机旋转移动相机与sdl,opengl在c ++ [英] How to fix weird camera rotation while moving camera with sdl, opengl in c++

查看:236
本文介绍了如何解决奇怪的相机旋转移动相机与sdl,opengl在c ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个相机对象,我从网上读取,处理向前和向后移动,strafe左右,甚至环顾四周用鼠标放在一起。但是当我向任何方向移动时,尝试环顾四周,它会跳到所有的地方,但是当我不移动,看看它周围的罚款。





main.h

pre> #includeSDL / SDL.h
#includeSDL / SDL_opengl.h

#include< cmath>


#define CAMERASPEED 0.03f //相机速度



struct tVector3 //扩展的3D矢量结构

{

tVector3(){} // Struct构造函数

tVector3(float new_x,float new_y,float new_z)// Init构造函数

{x = new_x; y = new_y; z = new_z; }

// overload + operator

tVector3 operator +(tVector3 vVector){return tVector3(vVector.x + x,vVector.y + y,vVector.z + z) ;}

// overload - operator

tVector3 operator-(tVector3 vVector){return tVector3(x-vVector.x,y-vVector.y,z-vVector。 z);}

//重载*运算符

tVector3运算符*(浮点数){return tVector3(x * number,y * number,z * number)

// overload / operator

tVector3 operator /(float number){return tVector3(x / number,y / number,z / number);}



float x,y,z; // 3D vector coordinates

};



class CCamera

{

public:



tVector3 mPos;

tVector3 mView;

tVector3 mUp;



void Strafe_Camera(float speed);



void Move_Camera(float speed);

void Rotate_View(float speed);
void Position_Camera(float pos_x,float pos_y,float pos_z,

float view_x,float view_y,float view_z,

float up_x,float up_y,float up_z) ;

};



void Draw_Grid();

camera.cpp



< #includemain.h

void CCamera :: Position_Camera(float pos_x,float pos_y,float pos_z,
float view_x,float view_y,float view_z,
float up_x,float up_y,float up_z)
{
mPos = tVector3(pos_x,pos_y,pos_z)
mView = tVector3(view_x,view_y,view_z);
mUp = tVector3(up_x,up_y,up_z);
}

void CCamera :: Move_Camera(float speed)
{
tVector3 vVector = mView - mPos;

mPos.x = mPos.x + vVector.x * speed;

mPos.z = mPos.z + vVector.z * speed;

mView.x = mView.x + vVector.x * speed;

mView.z = mView.z + vVector.z * speed;
}

void CCamera :: Strafe_Camera(float speed)
{
tVector3 vVector = mView - mPos;

tVector3 vOrthoVector;



vOrthoVector.x = -vVector.z;

vOrthoVector.z = vVector.x;



mPos.x = mPos.x + vOrthoVector.x * speed;

mPos.z = mPos.z + vOrthoVector.z * speed;

mView.x = mView.x + vOrthoVector.x * speed;

mView.z = mView.z + vOrthoVector.z * speed;
}

void CCamera :: Rotate_View(float speed)
{
tVector3 vVector = mView - mPos;
tVector3 vOrthoVector;

vOrthoVector.x = -vVector.z;

vOrthoVector.z = vVector.x;


mView.z =(float)(mPos.z + sin(speed)* vVector.x + cos(speed)* vVector.z);

mView.x =(float)(mPos.x + cos(speed)* vVector.x-sin(speed)* vVector.z);

}

和mousemotion代码

  void processEvents()
{
int mid_x = screen_width> 1;

int mid_y = screen_height>> 1;
int mpx = event.motion.x;
int mpy = event.motion.y;

float angle_y = 0.0f;

float angle_z = 0.0f;

while(SDL_PollEvent(& event))
{
switch(event.type)
{
case SDL_MOUSEMOTION:
if (mpx == mid_x)&&(mpy = mid_y))return;



//从鼠标光标获取方向,设置一个合理的机动速度

angle_y =(float)((mid_x - mpx) )/ 1000; // 1000

angle_z =(float)((mid_y - mpy))/ 1000; // 1000


//值越高,相机看起来越快。

objCamera.mView.y + = angle_z * 2;



//限制绕x轴的旋转

if((objCamera.mView.y - objCamera.mPos.y)> ; 8)objCamera.mView.y = objCamera.mPos.y + 8;

if((objCamera.mView.y - objCamera.mPos.y)< -8)objCamera.mView.y = objCamera.mPos.y - 8;


objCamera.Rotate_View(-angle_y);
SDL_WarpMouse(mid_x,mid_y);
break;

case SDL_KEYUP:
objKeyb.handleKeyboardEvent(event,true);
break;
case SDL_KEYDOWN:
objKeyb.handleKeyboardEvent(event,false);
break;

case SDL_QUIT:
quit = true;
break;

case SDL_VIDEORESIZE:
screen = SDL_SetVideoMode(event.resize.w,event.resize.h,screen_bpp,SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE);
screen_width = event.resize.w;
screen_height = event.resize.h;
init_opengl();
std :: cout<< Resized to width:< event.resize.w< height:< event.resize.h<< std :: endl;
break;

默认值:
break;
}
}
}


解决方案>

我不完全确定你在做什么。



我个人只是允许一个简单的4x4矩阵。任何实现都会做。要旋转你,简单地说,需要旋转使用鼠标x和y的变化作为euler输入,围绕y和x轴旋转。



有些矩阵库不会为你提供一个MoveForward()函数。如果这是case的确定,向前走很容易。第三列(或行,如果你使用行主矩阵)是你的前向矢量。提取它。归一化它(它真的应该归一化,所以这一步可能不需要)。乘以你希望向前移动多少,然后将其添加到位置(第4列/行)。



现在这里是奇怪的部分。视图矩阵是一种特殊类型的矩阵。上面的矩阵定义了视图空间。如果你把你的当前模型矩阵乘以这个矩阵,你不会得到你所期望的答案。因为你希望变换它,使摄像机在原点。因此,你需要有效地撤销相机变换,将事物重定向到上面定义的视图。要做到这一点,你的模型矩阵乘以 视图矩阵。



现在你有一个对象定义在正确的视图空间。



这是我很简单的相机类。它不处理你描述的功能,但希望会给你一些关于如何设置类的想法(警告,我使用行主要,即DirectX样式,矩阵)。



BaseCamera.h:

  #ifndef BASE_CAMERA_H_ 
#define BASE_CAMERA_H_

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + - + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + * /

#includeMaths / Vector4.h
#includeMaths / Matrix4x4.h

/ * + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + * /

class BaseCamera
{
protected:
bool mDirty;
MathsLib :: Matrix4x4 mCameraMat;
MathsLib :: Matrix4x4 mViewMat;
public:
BaseCamera();
BaseCamera(const BaseCamera& camera);
BaseCamera(const MathsLib :: Vector4& vPos,const MathsLib :: Vector4& vLookAt);
BaseCamera(const MathsLib :: Matrix4x4& matCamera);

bool IsDirty()const;
void SetDirty();

MathsLib :: Matrix4x4& GetOrientationMatrix();
const MathsLib :: Matrix4x4& GetOrientationMatrix()const;

MathsLib :: Matrix4x4& GetViewMatrix();
};

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + * /

inline MathsLib :: Matrix4x4& BaseCamera :: GetOrientationMatrix()
{
return mCameraMat;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline const MathsLib :: Matrix4x4& BaseCamera :: GetOrientationMatrix()const
{
return mCameraMat;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline bool BaseCamera :: IsDirty()const
{
return mDirty;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

inline void BaseCamera :: SetDirty()
{
mDirty = true;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

#endif

BaseCamera.cpp :

  #includeRender / stdafx.h

#includeBaseCamera.h

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + * /

BaseCamera :: BaseCamera():
mDirty(true)
{
}

/ * + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + * /

BaseCamera :: BaseCamera (const BaseCamera& camera):
mDirty(camera.mDirty),
mCameraMat(camera.mCameraMat),
mViewMat(camera.mViewMat)
{
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + * /

BaseCamera :: BaseCamera(const MathsLib :: Vector4& vPos,const MathsLib :: Vector4& vLookAt):
mDirty(true)
{
MathsLib :: Vector4 vDir =(vLookAt - vPos).Normalise();
MathsLib :: Vector4 vLat = MathsLib :: CrossProduct(MathsLib :: Vector4(0.0f,1.0f,0.0f),vDir).Normalise();
MathsLib :: Vector4 vUp = MathsLib :: CrossProduct(vDir,vLat); //。Normalize();

mCameraMat.Set(vLat,vUp,vDir,vPos);
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /

BaseCamera :: BaseCamera(const MathsLib :: Matrix4x4& matCamera):
mDirty(true),
mCameraMat(matCamera)
{
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + - + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + - + ---- + * /

MathsLib :: Matrix4x4& BaseCamera :: GetViewMatrix()
{
if(IsDirty())
{
mViewMat = mCameraMat.Inverse
mDirty = false;
}
return mViewMat;
}

/ * + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + + ---- + * /


I have a camera object that I have put together from reading on the net that handles moving forward and backward, strafe left and right and even look around with the mouse. But when I move in any direction plus try to look around it jumps all over the place, but when I don't move and look around its fine.

I'm hoping someone can help me work out why I can move and look around at the same time?

main.h

#include "SDL/SDL.h"
#include "SDL/SDL_opengl.h"

#include <cmath>


#define CAMERASPEED 0.03f				// The Camera Speed



struct tVector3 // Extended 3D Vector Struct

{   		

tVector3() {} // Struct Constructor

tVector3 (float new_x, float new_y, float new_z) // Init Constructor	 

{ x = new_x; y = new_y; z = new_z; }

// overload + operator

tVector3 operator+(tVector3 vVector) {return tVector3(vVector.x+x, vVector.y+y, vVector.z+z);}

// overload - operator

tVector3 operator-(tVector3 vVector) {return tVector3(x-vVector.x, y-vVector.y, z-vVector.z);}

// overload * operator

tVector3 operator*(float number)	 {return tVector3(x*number, y*number, z*number);}

// overload / operator

tVector3 operator/(float number)	 {return tVector3(x/number, y/number, z/number);}



float x, y, z;						// 3D vector coordinates

};



class CCamera 

{

public:



	tVector3 mPos;	

	tVector3 mView;		

	tVector3 mUp;			



	void Strafe_Camera(float speed);



	void Move_Camera(float speed);

	void Rotate_View(float speed);
	void Position_Camera(float pos_x, float pos_y,float pos_z,

		 				 float view_x, float view_y, float view_z,

						 float up_x,   float up_y,   float up_z);

};



void Draw_Grid();

camera.cpp

#include "main.h"

void CCamera::Position_Camera(float pos_x, float pos_y, float pos_z,
				float view_x, float view_y, float view_z, 
				float up_x, float up_y, float up_z)
{
mPos = tVector3(pos_x, pos_y, pos_z);
mView = tVector3(view_x, view_y, view_z);
mUp = tVector3(up_x, up_y, up_z);
}

void CCamera::Move_Camera(float speed)
{
tVector3 vVector = mView - mPos;

mPos.x  = mPos.x  + vVector.x * speed;

mPos.z  = mPos.z  + vVector.z * speed;

mView.x = mView.x + vVector.x * speed;

mView.z = mView.z + vVector.z * speed;
}

void CCamera::Strafe_Camera(float speed)
{
tVector3 vVector = mView - mPos;

tVector3 vOrthoVector;



vOrthoVector.x = -vVector.z;

vOrthoVector.z =  vVector.x;



mPos.x  = mPos.x  + vOrthoVector.x * speed;

mPos.z  = mPos.z  + vOrthoVector.z * speed;

mView.x = mView.x + vOrthoVector.x * speed;

mView.z = mView.z + vOrthoVector.z * speed;
}

void CCamera::Rotate_View(float speed)
{
tVector3 vVector = mView - mPos;
tVector3 vOrthoVector;

vOrthoVector.x = -vVector.z;

vOrthoVector.z =  vVector.x;


mView.z = (float)(mPos.z + sin(speed)*vVector.x + cos(speed)*vVector.z);

mView.x = (float)(mPos.x + cos(speed)*vVector.x - sin(speed)*vVector.z);

}

and the mousemotion code

void processEvents()
{
int mid_x = screen_width  >> 1;

int mid_y = screen_height >> 1;
int mpx = event.motion.x;
int mpy = event.motion.y;

float angle_y  = 0.0f;

float angle_z  = 0.0f;

while(SDL_PollEvent(&event))
{
	switch(event.type)
	{
		case SDL_MOUSEMOTION:
			if( (mpx == mid_x) && (mpy == mid_y) ) return;



			// Get the direction from the mouse cursor, set a resonable maneuvering speed

			angle_y = (float)( (mid_x - mpx) ) / 1000; //1000

			angle_z = (float)( (mid_y - mpy) ) / 1000; //1000


			// The higher the value is the faster the camera looks around.

			objCamera.mView.y += angle_z * 2;



			// limit the rotation around the x-axis

			if((objCamera.mView.y - objCamera.mPos.y) > 8)  objCamera.mView.y = objCamera.mPos.y + 8;

			if((objCamera.mView.y - objCamera.mPos.y) <-8)  objCamera.mView.y = objCamera.mPos.y - 8;


			objCamera.Rotate_View(-angle_y);
			SDL_WarpMouse(mid_x, mid_y);
			break;

		case SDL_KEYUP:
			objKeyb.handleKeyboardEvent(event,true);
			break;
		case SDL_KEYDOWN:
			objKeyb.handleKeyboardEvent(event,false);
			break;

		case SDL_QUIT:
			quit = true;
			break;

		case SDL_VIDEORESIZE:
			screen = SDL_SetVideoMode( event.resize.w, event.resize.h, screen_bpp, SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE );
			screen_width = event.resize.w;
			screen_height = event.resize.h;
			init_opengl();
			std::cout << "Resized to width: " << event.resize.w << " height: " << event.resize.h << std::endl;
			break;

		default:
			break;
	}
}
}

解决方案

I'm not entirely sure what you are doing above.

Personally I would just allow a simple 4x4 matrix. Any implementation will do. To rotate you, simply, need to rotate using the change of mouse x and y as euler inputs for rotation around the y and x axes. There is lots of code available all over the internet that will do this for you.

Some of those matrix libraries won't provide you with a "MoveForward()" function. If this is the case its ok, moving forward is pretty easy. The third column (or row if you are using row major matrices) is your forward vector. Extract it. Normalise it (It really should be normalised anyway so this step may not be needed). Multiply it by how much you wish to move forward and then add it to the position (the 4th column/row).

Now here is the odd part. A view matrix is a special type of matrix. The matrix above defines the view space. If you multiply your current model matrix by this matrix you will not get the answer you expect. Because you wish to transform it such that the camera is at the origin. As such you need to, effectively, undo the camera transformation to re-orient things to the view defined above. To do this you multiply your model matrix by the inverse of the view matrix.

You now have an object defined in the correct view space.

This is my very simple camera class. It does not handle the functionality you describe but hopefully will give you a few ideas on how to set up the class (Be warned, I use row major, ie DirectX style, matrices).

BaseCamera.h:

#ifndef BASE_CAMERA_H_
#define BASE_CAMERA_H_

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

#include "Maths/Vector4.h"
#include "Maths/Matrix4x4.h"

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

class BaseCamera
{
protected:
    bool					mDirty;
    MathsLib::Matrix4x4		mCameraMat;
    MathsLib::Matrix4x4		mViewMat;
public:
    BaseCamera();
    BaseCamera( const BaseCamera& camera );
    BaseCamera( const MathsLib::Vector4& vPos, const MathsLib::Vector4& vLookAt );
    BaseCamera( const MathsLib::Matrix4x4& matCamera );

    bool IsDirty() const;
    void SetDirty();

    MathsLib::Matrix4x4&		GetOrientationMatrix();
    const MathsLib::Matrix4x4&	GetOrientationMatrix() const;

    MathsLib::Matrix4x4&		GetViewMatrix();
};

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline MathsLib::Matrix4x4& BaseCamera::GetOrientationMatrix()
{
    return mCameraMat;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline const MathsLib::Matrix4x4& BaseCamera::GetOrientationMatrix() const
{
    return mCameraMat;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline bool BaseCamera::IsDirty() const
{
    return mDirty;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

inline void BaseCamera::SetDirty()
{
    mDirty = true;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

#endif

BaseCamera.cpp:

#include "Render/stdafx.h"

#include "BaseCamera.h"

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

BaseCamera::BaseCamera() :
    mDirty( true )
{
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

BaseCamera::BaseCamera( const BaseCamera& camera ) :
    mDirty( camera.mDirty ),
    mCameraMat( camera.mCameraMat ),
    mViewMat( camera.mViewMat )
{
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

BaseCamera::BaseCamera( const MathsLib::Vector4& vPos, const MathsLib::Vector4& vLookAt ) :
    mDirty( true )
{
    MathsLib::Vector4 vDir	= (vLookAt - vPos).Normalise();
    MathsLib::Vector4 vLat	= MathsLib::CrossProduct( MathsLib::Vector4( 0.0f, 1.0f, 0.0f ), vDir ).Normalise();
    MathsLib::Vector4 vUp	= MathsLib::CrossProduct( vDir, vLat );//.Normalise();

    mCameraMat.Set( vLat, vUp, vDir, vPos );	
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

BaseCamera::BaseCamera( const MathsLib::Matrix4x4& matCamera ) :
    mDirty( true ),
    mCameraMat( matCamera )
{
}

    /*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

MathsLib::Matrix4x4& BaseCamera::GetViewMatrix()
{
    if ( IsDirty() )
    {
    	mViewMat	= mCameraMat.Inverse();
    	mDirty		= false;
    }
    return mViewMat;
}

/*+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+*/

这篇关于如何解决奇怪的相机旋转移动相机与sdl,opengl在c ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆