How to avoid the object floating around with the camera?

Started by
6 comments, last by Choo Wagga Choo Choo 6 years, 4 months ago

I want it to stay at one place, say where the position with transformations by the world matrix only. But I don't think if I drop the view and projection matrices, it will work anyway.
But now the thing is moving with the camera.


outVS.position = mul(mul(float4(position.xyz, 1.0), modelViewMatrix), projectionMatrix);



Thanks
Jack
Advertisement

Basically dont change camera position?

Oh...

It's difficult to see how you are building your view matrix. Do you build it as inverse transpose?

No, the view matrix is right retrieved from the camera and pass right down, oh, I need to inverse transpose it?
Thanks
Jack

Try this to get an understanding of the view matrix.

The link above is openGL based but the information is adaptable to what I assume from your shader snippet is hlsl. Below is a code dump of a camera from one of my directX projects for reference.


//
// file : transform.h
//

#ifndef _nub_device_transform_h_
#define _nub_device_transform_h_

#include <DirectXMath.h>

typedef DirectX::XMFLOAT3 vec3;
typedef DirectX::XMVECTOR vec;
typedef DirectX::XMFLOAT4X4 mat4;

namespace Component
{
	class cTransform
	{
	public:
		cTransform()
		{
			_position  = vec3(0.0f, 0.0f, 0.0f);
			_rotations = vec3(0.0f, 0.0f, 0.0f);
			_scale     = vec3(1.0f, 1.0f, 1.0f);

			_forward   = vec3(0.0f, 0.0f, 1.0f);
			_right     = vec3(1.0f, 0.0f, 0.0f);
			_up        = vec3(0.0f, 1.0f, 0.0f);

			DirectX::XMStoreFloat4x4(&_matrix, DirectX::XMMatrixIdentity());
			_isDirty   = false;
		}

		vec3 getPosition()      { return _position;  }
		vec3 getAxisRotations() { return _rotations; }
		vec3 getForward()       { return _forward;   } //
		vec3 getRight()         { return _right;     } // if these are dirty they won't be current this frame
		vec3 getUp()            { return _up;        } // todo: add assertions 
		mat4 getMatrix()        { return _matrix;    } //

		void setPosition(vec3 p)      { _position = p;                      }
		void setScale   (vec3 s)      { _scale = s;        _isDirty = true; }
		void setRotation(vec3 r)      { _rotations = r;    _isDirty = true; }

		void move(vec3 v)             { _position.x += v.x;            _position.y += v.y;            _position.z += v.z;            }
		void moveForward(float t)     { _position.x += t * _forward.x; _position.y += t * _forward.y; _position.z += t * _forward.z; }
		void moveRight(float t)       { _position.x += t * _right.x;   _position.y += t * _right.y;   _position.z += t * _right.z;   }
		void moveUp(float t)          { _position.x += t * _up.x;      _position.y += t * _up.y;      _position.z += t * _up.z;      }

		void addDeltaPosition(vec3 p) { _position.x += p.x; _position.y += p.y; _position.z += p.z; }
		void addDeltaYaw(float t)     { _rotations.y += t; _isDirty = true; }
		void addDeltaPitch(float t)   { _rotations.x += t; _isDirty = true; }
		void addDeltaRoll (float t)   { _rotations.z += t; _isDirty = true; }

		void update()
		{
			if (_isDirty)
			{
				// if all rotations being tracked are zero, forward points 'into' the screen
				//
				// Notes:
				// cos(0) = 1    cos(pi/2) = 0    cos(pi) = -1    cos(pi+pi/2) =  0    cos(2pi) = 1
				// sin(0) = 0    sin(pi/2) = 1    sin(pi) =  0    sin(pi+pi/2) = -1    sin(2pi) = 0
				//
				//

				_forward = vec3(cosf(_rotations.x) * sinf(_rotations.y),
					            sinf(_rotations.x),
					            cosf(_rotations.x) * cosf(_rotations.y));
						
				_right = vec3(cosf(_rotations.z) * sinf(_rotations.y + DirectX::XM_PIDIV2),
					          sinf(_rotations.z),
					          cosf(_rotations.z) * cosf(_rotations.y + DirectX::XM_PIDIV2));
				DirectX::XMStoreFloat3(&_right, DirectX::XMVector3Normalize(DirectX::XMLoadFloat3(&_right)));
				
				vec vecForward = DirectX::XMLoadFloat3(&_forward);
				vec vecRight   = DirectX::XMLoadFloat3(&_right);
				vec vecUp      = DirectX::XMVector3Normalize(DirectX::XMVector3Cross(vecForward, vecRight));
				
				//DirectX::XMStoreFloat3(&_right, DirectX::XMVector3Normalize(DirectX::XMVector3Cross(vecUp, vecForward)));
				DirectX::XMStoreFloat3(&_up, vecUp);
				

				_matrix.m[0][0] = _right.x * _scale.x;
				_matrix.m[0][1] = _right.y;
				_matrix.m[0][2] = _right.z;
				_matrix.m[0][3] = 0.0f;

				_matrix.m[1][0] = _up.x;
				_matrix.m[1][1] = _up.y * _scale.y;
				_matrix.m[1][2] = _up.z;
				_matrix.m[1][3] = 0.0f;

				_matrix.m[2][0] = _forward.x;
				_matrix.m[2][1] = _forward.y;
				_matrix.m[2][2] = _forward.z * _scale.z;
				_matrix.m[2][3] = 0.0f;
				_isDirty = false;
			}
			_matrix.m[3][0] = _position.x;
			_matrix.m[3][1] = _position.y;
			_matrix.m[3][2] = _position.z;
			_matrix.m[3][3] = 1.0f;
		}

	private:
		vec3 _position;
		vec3 _rotations; // per axis rotation amounts in radians
		vec3 _scale;

		vec3 _forward;
		vec3 _right;
		vec3 _up;

		mat4 _matrix;
		
		bool _isDirty;
	};
	
} // end namespace Component
#endif //_nub_device_transform_h_

//
// file : camera.h
//

#ifndef _nub_device_camera_h_
#define _nub_device_camera_h_

#include "transform.h"

class cCamera
{
public:
	cCamera();
	cCamera(const cCamera&) { /*empty copy constructor*/ }
    ~cCamera()              { /*empty destructor*/       }

	DirectX::XMFLOAT4X4   getViewMatrix();
	DirectX::XMFLOAT4X4   getReflectionViewMatrix();

	void update();
	void updateReflection( float );
	
//	void addPosition( float, float, float );
//	void addRotation( float, float, float );

	Component::cTransform transform;

private:
	DirectX::XMFLOAT4X4   _reflectionMatrix;
	DirectX::XMFLOAT4X4   _viewMatrix;
};

#endif //_nub_device_camera_h_

//
// file : camera.cpp
//

#include "stdafx.h"
#include "camera.h"

using namespace DirectX;

cCamera::cCamera() {}

DirectX::XMFLOAT4X4 cCamera::getViewMatrix()
{
	return _viewMatrix;
}

DirectX::XMFLOAT4X4 cCamera::getReflectionViewMatrix()
{
	return _reflectionMatrix;
}

void cCamera::update()
{
	transform.update();

	// build inverse transpose for the view matrix
	vec3 viewX   = transform.getRight();
	vec3 viewY   = transform.getUp();
	vec3 viewZ   = transform.getForward();
	XMVECTOR vp  = XMLoadFloat3(&transform.getPosition());
	
	_viewMatrix.m[0][0] = viewX.x;
	_viewMatrix.m[0][1] = viewY.x;
	_viewMatrix.m[0][2] = viewZ.x;
	_viewMatrix.m[0][3] = 0.0f;

	_viewMatrix.m[1][0] = viewX.y;
	_viewMatrix.m[1][1] = viewY.y;
	_viewMatrix.m[1][2] = viewZ.y;
	_viewMatrix.m[1][3] = 0.0f;
	
	_viewMatrix.m[2][0] = viewX.z;
	_viewMatrix.m[2][1] = viewY.z;
	_viewMatrix.m[2][2] = viewZ.z;
	_viewMatrix.m[2][3] = 0.0f;
	
	_viewMatrix.m[3][0] = XMVectorGetX(XMVector3Dot(-vp, XMLoadFloat3(&viewX)));
	_viewMatrix.m[3][1] = XMVectorGetY(XMVector3Dot(-vp, XMLoadFloat3(&viewY)));
	_viewMatrix.m[3][2] = XMVectorGetZ(XMVector3Dot(-vp, XMLoadFloat3(&viewZ)));
	_viewMatrix.m[3][3] = 1.0f;

	/*
	// kept this here for future attempt towards a 'look at' routine

	XMMATRIX rotationMatrix;
	XMVECTOR up, position, lookat;
	float yaw, pitch, roll;
	
	position = XMLoadFloat4(&_position);
	up       = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
	lookat   = XMVectorSet( 0.0f, 0.0f, 1.0f, 0.0f );

	yaw      = _rotation.y;
	pitch    = _rotation.x;
	roll     = _rotation.z;
	rotationMatrix = XMMatrixRotationRollPitchYaw( -pitch, yaw, roll );

	// move to camera space
	lookat = XMVector3TransformCoord( lookat, rotationMatrix );
	up     = XMVector3TransformCoord( up, rotationMatrix );
	lookat = position + lookat;
	XMStoreFloat4x4(&_viewMatrix, XMMatrixLookAtLH( position, lookat, up ));
	*/
}


void cCamera::updateReflection( float height )
{
	XMVECTOR up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
	
	XMFLOAT3 pos = transform.getPosition();
	pos.y = -pos.y + (height*2.0f);

	float yaw = transform.getAxisRotations().y;
	XMVECTOR lookat = XMVectorSet( sinf(yaw) + pos.x, pos.y, cosf(yaw) + pos.z, 0.0f );
	XMStoreFloat4x4(&_reflectionMatrix, XMMatrixLookAtLH( XMLoadFloat3(&pos), lookat, up )); 
}

 

In my camera class i extract up right front vectors same like you and then to apply camera position i multiple rotation camera matrix with translation matrix so you should define constant position and apply that to transslation mat tthen multiple rot * trans


template <class T> void
glLookAt(Matrix44<T> &matrix, t3dpoint<T> eyePosition3D, t3dpoint<T> center3D, t3dpoint<T> upVector3D )
{
   t3dpoint<T>  forward, side, up;
   forward = Normalize( vectorAB(eyePosition3D, center3D) );
   side = Normalize( forward * upVector3D );
   up = side * forward;
  matrix.LoadIdentity();

	matrix.m[0] = side.x;
	matrix.m[1] = side.y;
	matrix.m[2] = side.z;

	matrix.m[4] = up.x;
	matrix.m[5] = up.y;
	matrix.m[6] = up.z;

	matrix.m[8] 	= -forward.x;
	matrix.m[9] 	= -forward.y;
	matrix.m[10] 	= -forward.z;



Matrix44<T> transgender;
transgender.Translate(-eyePosition3D.x, -eyePosition3D.y, -eyePosition3D.z);


matrix = transgender * matrix;
} We

 

@WiredCat That looks great. I'm a huge openGL fan boy...

The difference is 4x4 matrix multiplication involves 64 multiplies and 48 additions, while the dot requires 3 and 2 respectively 3 times for the translation assignment which is 9 multiplications and 6 additions. Perhaps not a big deal for a camera, but apply that logic to a ton of objects begins to get wasteful. 

Here is a visual to compare the two operations to show that matrix multiplication is similar to dot. (pulled from an old openGL project)


inline cMatrix4 &cMatrix4::operator*=(const cMatrix4 &rhs)
{
    cMatrix4 tmp;

    // Row 1.
    tmp.e[0][0] = (e[0][0] * rhs.e[0][0]) + (e[0][1] * rhs.e[1][0]) + (e[0][2] * rhs.e[2][0]) + (e[0][3] * rhs.e[3][0]);
    tmp.e[0][1] = (e[0][0] * rhs.e[0][1]) + (e[0][1] * rhs.e[1][1]) + (e[0][2] * rhs.e[2][1]) + (e[0][3] * rhs.e[3][1]);
    tmp.e[0][2] = (e[0][0] * rhs.e[0][2]) + (e[0][1] * rhs.e[1][2]) + (e[0][2] * rhs.e[2][2]) + (e[0][3] * rhs.e[3][2]);
    tmp.e[0][3] = (e[0][0] * rhs.e[0][3]) + (e[0][1] * rhs.e[1][3]) + (e[0][2] * rhs.e[2][3]) + (e[0][3] * rhs.e[3][3]);

    // Row 2.
    tmp.e[1][0] = (e[1][0] * rhs.e[0][0]) + (e[1][1] * rhs.e[1][0]) + (e[1][2] * rhs.e[2][0]) + (e[1][3] * rhs.e[3][0]);
    tmp.e[1][1] = (e[1][0] * rhs.e[0][1]) + (e[1][1] * rhs.e[1][1]) + (e[1][2] * rhs.e[2][1]) + (e[1][3] * rhs.e[3][1]);
    tmp.e[1][2] = (e[1][0] * rhs.e[0][2]) + (e[1][1] * rhs.e[1][2]) + (e[1][2] * rhs.e[2][2]) + (e[1][3] * rhs.e[3][2]);
    tmp.e[1][3] = (e[1][0] * rhs.e[0][3]) + (e[1][1] * rhs.e[1][3]) + (e[1][2] * rhs.e[2][3]) + (e[1][3] * rhs.e[3][3]);

    // Row 3.
    tmp.e[2][0] = (e[2][0] * rhs.e[0][0]) + (e[2][1] * rhs.e[1][0]) + (e[2][2] * rhs.e[2][0]) + (e[2][3] * rhs.e[3][0]);
    tmp.e[2][1] = (e[2][0] * rhs.e[0][1]) + (e[2][1] * rhs.e[1][1]) + (e[2][2] * rhs.e[2][1]) + (e[2][3] * rhs.e[3][1]);
    tmp.e[2][2] = (e[2][0] * rhs.e[0][2]) + (e[2][1] * rhs.e[1][2]) + (e[2][2] * rhs.e[2][2]) + (e[2][3] * rhs.e[3][2]);
    tmp.e[2][3] = (e[2][0] * rhs.e[0][3]) + (e[2][1] * rhs.e[1][3]) + (e[2][2] * rhs.e[2][3]) + (e[2][3] * rhs.e[3][3]);

    // Row 4.
    tmp.e[3][0] = (e[3][0] * rhs.e[0][0]) + (e[3][1] * rhs.e[1][0]) + (e[3][2] * rhs.e[2][0]) + (e[3][3] * rhs.e[3][0]);
    tmp.e[3][1] = (e[3][0] * rhs.e[0][1]) + (e[3][1] * rhs.e[1][1]) + (e[3][2] * rhs.e[2][1]) + (e[3][3] * rhs.e[3][1]);
    tmp.e[3][2] = (e[3][0] * rhs.e[0][2]) + (e[3][1] * rhs.e[1][2]) + (e[3][2] * rhs.e[2][2]) + (e[3][3] * rhs.e[3][2]);
    tmp.e[3][3] = (e[3][0] * rhs.e[0][3]) + (e[3][1] * rhs.e[1][3]) + (e[3][2] * rhs.e[2][3]) + (e[3][3] * rhs.e[3][3]);

    *this = tmp;
    return *this;
}


inline float cVector3::dot(const cVector3 &p, const cVector3 &q)
{
    return (p.x * q.x) + (p.y * q.y) + (p.z * q.z);
}

 

This topic is closed to new replies.

Advertisement