Archived

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

MatScaling, MatRotation... Help?

This topic is 5594 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve got a function that renders my meshes for me at any scale, position and rotation. This works fine and is giving me no problems. I am using the MatrixScaling, MatrixRotationX, MatrixRotationY and MatrixRotationZ built in functions (straight out of one of the DX examples... i forget which one). The problem is that it seems to be hugely inneficient. I am storing an objects scale and rotation in d3dvector structures, but then I have to extract the information so that I can do the scale and rotation calcs, which effectively translates the information back into a matrix anyway. For example, I store the object''s rotation as normalised D3D vector that essentially describes the direction that model should be facing. To actually render the object, I have to calculate the AngleX, AngleY and AngleZ from the normalised vector (using cos and sin lookup tables), and then these get used to create the new matrix via the matrixrotationx, y and z functions just prior to rendering the model. Is there a way to generate that matrix directly from the normalised vector? Not only would it be faster than having to apply the three seperate matrixrotation functions, but it would also be faster because I wouldn''t have to calculate the individual angles prior to generating the matrix. Anyway, my matrix math skills are very rudimentary so if anyone could point me in the right direction it would be great.

Share this post


Link to post
Share on other sites
Just one question: Why?
Why do you do this?
Store the angles as angles instead of a direction, and if you still need a direction for the object, rotate that direction using the angles instead.


--
MFC is sorta like the swedish police... It''''s full of crap, and nothing can communicate with anything else.

Share this post


Link to post
Share on other sites
ok, if you want to work on a per-model basis, I would do it like this....


class CMesh
{
// responsible for loading and rendering meshes

}

class CModel
{
public:
D3DXMATRIX m_matWorld; // has it''s own positional matrix

void SetXRotation( const float &fY );
void SetYRotation( const float &fX );
void SetZRotation( const float &fY );
void SetXPosition( const float &fX );
void SetYPosition( const float &fY );
void SetZPosition( const float &fZ );
void SetRotation( const D3DXVECTOR3 &vecRot );
void SetPosition( const D3DXVECTOR3 &vecPos );
void SetScale( const float &fScale );

void Orientate( const D3DXVECTOR3 &vecPos,
const D3DXVECTOR3 &vecRot );
private:
CMesh * m_pMesh; // can re-use other meshes
D3DXVECTOR3 m_vecPos; // position
D3DXVECTOR3 m_vecRot; // rotation
float m_fScale;

void CalculateMatrix(); // works out the new matrix
}


well that''s the basic idea. It saves every model requiring it''s own mesh but will require a mesh manager that the model can access in order to load the mesh or retain a pointer to an already existing one, and you will know best when to use which function - if you only want to change the X rotation for example you''ll know what member to call - and don''t call SetYRotation(), SetXRotation() and SetZRotation() one after the other - call SetRotation() instead. That should be self explanatory.

Each one of those members will recalculate the entire local matrix by calling CalculateMatrix(), but not with matrix concatenation has you have been using.. instead we can calculate an entire matrix (rotation, translation and scaling) very easily, like this..


void CModel::CalculateMatrix()
{
float fA = cos(m_vecAngle.x);
float fB = sin(m_vecAngle.x);
float fC = cos(m_vecAngle.y);
float fD = sin(m_vecAngle.y);
float fE = cos(m_vecAngle.z);
float fF = sin(m_vecAngle.z);

float fAD = fA * fD;
float fBD = fB * fD;

m_matWorld._11 = fC * fE;
m_matWorld._12 = -fC * fF;
m_matWorld._13 = -fD;
m_matWorld._21 = -fBD * fE + fA * fF;
m_matWorld._22 = fBD * fF + fA * fE;
m_matWorld._23 = -fB * fC;
m_matWorld._31 = fAD * fE + fB * fF;
m_matWorld._32 = -fAD * fF + fB * fE;
m_matWorld._33 = fA * fC;

m_matWorld._14 = m_matWorld._24 = m_matWorld._34 = 0.0f;

m_matWorld._41 = m_vecPos.x;
m_matWorld._42 = m_vecPos.y;
m_matWorld._43 = m_vecPos.z;

m_matWorld._44 = m_fScale;
}


That''s the optimal method of creating a rotation/translation/scale matrix but don''t shoot me if; a) you suffer from gimble lock b) the scaling takes place from the world origin (I personally hate the need for scaling models in RT) c) it''s all screwed up because I just retyped it .

Cheers

Matt

Share this post


Link to post
Share on other sites
tok_junior... I do it this way because finding the orientation that an object must look at in order to face another model (e.g. the character facing the mouse-pointer, or an enemy facing the character), I can just do a very simple vector subtraction and normalise the result, instead of having to pythag the x1,y1,z1 and x2,y2,z2

3dmodelman, thanks for the alternative. It looks like it''s not going to be any cheaper than the method I''m currently using, but it does help to explain the maths a little better. Certainly something to bear in mind going forward. Thanks.

Share this post


Link to post
Share on other sites
Then make separate routines for billboarding.
Make one that returns the angles you need to rotate by, and one that does the actual rotation.
So you don''t need to do the billboard-calculation for each and every object every frame.


--
MFC is sorta like the swedish police... It''''s full of crap, and nothing can communicate with anything else.

Share this post


Link to post
Share on other sites
This isn''t for bill-boarding, it''s for the normal character-meets-world interaction. I''ve got the whole thing working perfectly just as you suggest, but it seems to me that there must be a faster and simpler way to do it through vectors, instead of messing about with angles.

Share this post


Link to post
Share on other sites
There is. A matrix is really 4 XYZW Axis Vectors stored in column major order. If vAt is the direction the character is facing, then:


  
class CModel
{
public:
D3DXVECTOR3 vPos,vAt,vScale;
D3DXMATRIX WorldMatrix();
};

D3DXMATRIX CModel::WorldMatrix()
{
//Declare and initialize vRight to the Identity X Axis.

D3DXVECTOR3 vRight = D3DXVECTOR3(1,0,0),vUp;
//Get Axis Vectors.

D3DXVec3Cross(&vUp,&vAt,&vRight);
D3DXVec3Cross(&vRight,&vAt,&vUp);
//Put them in a matrix with translation and scaling.

D3DXMATRIX m = D3DXMatrixIdentity(m);
m._11=vRight.x+vScale.x;m._12=vUp.x;m._13=vAt.x;
m._21=vRight.y;m._22=vUp.y+vScale.y;m._23=vAt.y;
m._31=vRight.z;m._32=vUp.z;m._33=vAt.z+vScale.z;
m._41=vPos.x;m._12=vPos.y;m._13=vPos.z;
return m;
}


One such function is D3DXMatrixLookAtLH, but you can''t use that because it performs negative translation and no scaling.

void Signature(void* Pointer)
{
PObject(Pointer)->ShowMessage("Why do we need so many pointers?");
};

Two guys walk into a bar. One''s an Isreali ambassador, one''s a Palestinian ambassador. They both get drunk. Then they start peace talks.

Share this post


Link to post
Share on other sites