Archived

This topic is now archived and is closed to further replies.

brekehan

camera movement

Recommended Posts

I am trying to get the camera to move foward towards the direction it is currently facing. My code seems to suck the camera towards the origin no matter which direction it is facing. The function to do so is CamerLH::MoveZ(float speed); My yaw pitch and roll functions seem to work ok. Anyone have any ideas on how to fix the following code?
#ifndef CAMERA_H
#define CAMERA_H
//----------------------------------------------------------------------

// camera.h

// 

// A 3D camera

//

// Christopher Pisz

// 01/04/04

//----------------------------------------------------------------------          

#include <d3dx9.h>

class CameraLH
{
public:
	CameraLH(D3DXVECTOR3 &position = D3DXVECTOR3( 0.0f,  0.0f, -5.0f),
			float xan = 0.0f, float yan = 0.0f, float zan = 0.0f);
	~CameraLH();

	// Accessors

	D3DXMATRIX * GetMatrix(D3DXMATRIX * in);

	// Mutators

	void Yaw  (float angle, bool relative);
	void Pitch(float angle, bool relative);
	void Roll (float angle, bool relative);
	void MoveZ(float speed);

private:
	D3DXMATRIX  m_rotation;      // The rotation matrix           

    D3DXMATRIX  m_translation;   // The translation matrix

};

#endif //CAMERA_H


//----------------------------------------------------------------------

// camera.cpp

// 

// A 3D camera

//

// Christopher Pisz

// 01/04/04

//----------------------------------------------------------------------

#include "camera.h"


//------------------------------------------------------------------------

CameraLH::CameraLH(D3DXVECTOR3 &position, float xan, float yan, float zan)
{
	D3DXMatrixIdentity(&m_translation);
	m_translation._41 =  -position.x;
	m_translation._42 =  -position.y;
	m_translation._43 =  -position.z;

	D3DXMatrixIdentity(&m_rotation);
	D3DXMatrixRotationYawPitchRoll(&m_rotation, -yan, -xan, -zan);
}

//------------------------------------------------------------------------

CameraLH::~CameraLH()
{
}

//------------------------------------------------------------------------

void CameraLH::Yaw(float angle, bool relative)
{
	D3DXMATRIX yaw;
	D3DXMatrixRotationY(&yaw, -angle);
	if(relative)
		m_rotation = m_rotation * yaw;
	else
		m_rotation = yaw * m_rotation;
}

//------------------------------------------------------------------------

void CameraLH::Pitch(float angle, bool relative)
{
	D3DXMATRIX pitch;
	D3DXMatrixRotationX(&pitch, -angle);
	if(relative)
		m_rotation = m_rotation * pitch;
	else
		m_rotation = pitch * m_rotation;
}

//------------------------------------------------------------------------

void CameraLH::Roll(float angle, bool relative)
{
	D3DXMATRIX roll;
	D3DXMatrixRotationZ(&roll, -angle);
	if(relative)
		m_rotation = m_rotation * roll;
	else
		m_rotation = roll * m_rotation;
}

//------------------------------------------------------------------------

void CameraLH::MoveZ(float speed)
{
	// The only data we have is the translation and rotation

	// matrices that made up the last view matrix, we want to

	// move the camera towards the point it is currently facing


	D3DXVECTOR3 axis_z, position, temp;
    
	// Extract the foward vector

	axis_z.x = m_rotation._31;
	axis_z.y = m_rotation._32;
	axis_z.z = m_rotation._33;

	D3DXVec3Normalize(&axis_z, &axis_z);

	m_translation._41 = m_translation._41 + (speed * axis_z.x);
	m_translation._42 = m_translation._42 + (speed * axis_z.y);
	m_translation._43 = m_translation._43 + (speed * axis_z.z);

}

//------------------------------------------------------------------------

D3DXMATRIX * CameraLH::GetMatrix(D3DXMATRIX * in)
{
	D3DXMatrixIdentity(in);
	return D3DXMatrixMultiply(in, &m_translation , &m_rotation);
}

//--------------------------------------------------------------------

// driver.cpp

// 

// Drawing basic primitives with Direct3D

//

// Christopher Pisz

// 11/06/02

//-------------------------------------------------------------------- 

<snip>
CameraLH g_camera(D3DXVECTOR3( 0.0f, 200.0f, 0.0f),    // Camera object

				  PI / 2, 0, 0);
<snip>
//---------------------------------------------------------------------

// Process Input

//---------------------------------------------------------------------

void ProcessInput()
{
	// If the 's' key is pressed move foward

	if(g_keys[83])
		g_camera.MoveZ(.1f);

	// If the 'a' key is pressed look towards the left

	if(g_keys[65])
		g_camera.Yaw(-0.01f, true);

	// If the 'd' key is pressed look towards the right

	if(g_keys[68])
		g_camera.Yaw( 0.01f, true);
	
	// If the 'w' key is pressed look up

	if(g_keys[87])
		g_camera.Pitch(-0.01f, true);
	
	// If the 'x' key is pressed look up

	if(g_keys[88])
		g_camera.Pitch( 0.01f, true);

	// If the 'e' key is pressed roll right

	if(g_keys[69])
		g_camera.Roll(-0.01f, true);

	// If the 'q' key is pressed roll left

	if(g_keys[81])
		g_camera.Roll(0.01f, true);
}

//---------------------------------------------------------------------

//

//---------------------------------------------------------------------

void Render()
{
	// Check for valid device

	if(!g_device)
        throw Error("No valid device",
				"Render()", "driver.cpp");

    // Clear the backbuffer

    g_device->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
			D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

	// Set render states

	g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); 
	g_device->SetRenderState(D3DRS_LIGHTING, FALSE); 
    g_device->SetRenderState(D3DRS_ZENABLE,TRUE);
    g_device->SetRenderState(D3DRS_AMBIENT, 0xffffffff);
	
	// Wireframe 

    g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
    
	// Set the view matrix

	g_device->SetTransform(D3DTS_VIEW, g_camera.GetMatrix(&g_matrix_view));

	// Begin the scene

    g_device->BeginScene();
    
	// Draw the terrain

	g_terrain->m_mesh->DrawSubset(0);
        
    // End the scene

    g_device->EndScene();
    
    // Present the backbuffer contents to the display

    g_device->Present(NULL,NULL,NULL,NULL);
}
<snip>
Thanx, brekehan [edited by - brekehan on January 5, 2004 5:29:55 AM]

Share this post


Link to post
Share on other sites
hi, im talking a look at your code right now and it strikes me
that your class is very expensive performance wise..

every one of your functions operates on your matrix class, this is about 7-19 float operations per call if multiplying by a
vector and anywhere between.

what you should do is instead store the roll, pitch, yaw and
calculate everything once per frame, this way you can optimize
out redundant operations and function calls

if you did this, when you call a function to set the roll,
pitch yaw etc, all you have to do is a simple float copy so there
isnt much performance hit when compared to 16 float operations
is there ?

anyway back to figuring out your actual problem
i''ll post later if i figure it out, sorry if i was no help to
you (as of yet)..





Share this post


Link to post
Share on other sites
ok heres how you would do it the way i mentioned above..

add this code to a function nameed MoveCamera or something
and call it once before rendering (ie. when seting up the cam
matrix for the frame)

this creates the 2 vectors you need to setup the matrix
use a function like 3D3XLookAt

float cos_yaw = cos(yaw);
float sin_yaw = sin(yaw);
float sin_pitch = sin(pitch);
float cos_pitch = cos(pitch);

position.x += cos(yaw + 90.0)) * strafe_speed;
position.z += sin(yaw + 90.0)) * strafe_speed;
position.x += cosYaw) * speed;
position.z += sinYaw) * speed;

VECTOR3 view_vector; // Init a vVector for our view


// Get our view vVector (The direciton we are facing)

view_vector.x = look_at.x - position.x; // This gets the direction of the X

view_vector.y = look_at.y - position.y; // This gets the direction of the Y

view_vector.z = look_at.z - position.z; // This gets the direction of the Z


position.y += view_vector.y * speed; // Add our acceleration to our position''s Y


// added *cosPitch

look_at.x = position.x + cos_yaw * cos_pitch;
look_at.y = position.y + sin_pitch;
look_at.z = position.z + sin_yaw * cos_pitch;


im not a directx coder but i think the code (from memory)
to set the view matrix is something like this:


D3DXMATRIX mat_view;
D3DXMatrixLookAtLH( mat_view,
position,
look_at,
D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

d3d_device->SetTransform( D3DT_VIEW, &matView );

Share this post


Link to post
Share on other sites
If I store yaw pitch and roll like you said I will not be able to turn the camera relative to its own axi, but only the world.

I didn''t want to use D3DXLookAt because it needs to know the up and has many problems when the camera looks staright up or down.

But I do think it is a good idea to use vectors instead of the matrices.

Share this post


Link to post
Share on other sites
quote:

you do realize that your "relative" flag does nothing in your yaw pitch roll funcs? m_rotation * yaw = yaw * m_rotation




oh yes it does. they are certainly not equal at all. the relative flag determines the order of multiplication which determines if we are in camera space or world space. Read the SDK..."The order in which the matrix multiplication is performed is crucial. The preceding formula reflects the left-to-right rule of matrix concatenation. That is, the visible effects of the matrices that you use to create a composite matrix occur in left-to-right order. " Not to mention I have the program right here which says otherwise unless my eyes are lieing to me, but they have always beem so faithful.

Thanx,
brekehan

Share this post


Link to post
Share on other sites
Brekehan is correct. Matrix multiplication is definately not commutative (as was taught in most of my High School math classes...)

Share this post


Link to post
Share on other sites