• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
cozzie

Should a mesh always be centered around '0'?

8 posts in this topic

Hi,

While I was developing/ coding to make childs of a parent mesh have it's own orientation, I've found out that not all my meshes have 0, 0, 0 as it's center. This means having to add some transformation at loading the scene (parent: transform modelspace center with worldspace position and update worldspace position).

Now my question is, is this the way to go or is there an unwritten law that says the meshes/ objects should always be centered around 0, 0, 0 in their own (model)space?

I'm not sure if in the "real" world artists and modellers will keep to this principle / versus making flexible code in my engine so it works always. Another thing I don't know is if I should expect other issues when meshes are not centered around 0,0,0.

Any input is appreciated.
0

Share this post


Link to post
Share on other sites

is this the way to go or is there an unwritten law that says the meshes/ objects should always be centered around 0, 0, 0 in their own (model)space?

There's no unwritten law about centering meshes at 0,0,0. Actually, for many meshes, having an origin elsewhere is more convenient.

 

As Hodgman mentions, a box or crate may work better if the center of the bottom panel is at 0. For a character mesh, halfway between the feet and directly below the hip or spine may be more convenient. Similar for a tree - the bottom of the trunk is on the "ground."

 

 

 


making flexible code in my engine so it works always

Yep. I'd recommend that, for every mesh, you maintain base orientation data - a set of scale/rotation/translation vectors/quaternions, or a matrix - appropriate for the use of the mesh. If it most often sits on the ground or floor, the orientation should place it at the world origin appropriately oriented. If it, for instance, is a "flying" object, the orientation may move the center of gravity for the mesh to the world origin.

 

 

 


if I should expect other issues when meshes are not centered around 0,0,0.

Yep. Whether they are centered at 0,0,0 or not, you'll run across meshes modeled in a different reference frame (e.g., right-/left-handed axes system) with a different "up" vector, and much smaller or larger than you want. The mesh's orientation data can rotate/scale to your world, and translate it to an appropriate position.

 

Determining the orientation data appropriate for your use can be done by experimentation (which is painful), or by using a level or scene editor. You may want to think about a model/mesh format file, perhaps your own custom format, that provides the orientation data that you want when the model is loaded.

Edited by Buckeye
0

Share this post


Link to post
Share on other sites

Hi both. Thanks for the input.

For now I'm gonna make sure the all meshes I load get their own orientation around center 0,0,0. Giving me flexibility.

 

Moving to another/ DIY mesh/ level format is something I have to get into.
I currently model the base of the level in max, and export it twice (once with all blended objects hidden and once with opaque hidden). So the level consists of 'x' childs (objects in mesh), which now have their own orientation. For eithing, moving/rotating/scaling, but also for collisions and culling. Game objects I import in the max scene to position them. Not ideal, with for now it works.

 

To be sure I understand the math correctly, a use case.

The goal is to have 'world position' oriented at the center of the mesh:

 

A - world position in my scene: 10, 3, 2

B - center in modelspace is 3, 2, 1

 

1. create worldmatrix based on A

2. transform B using this worldmatrix

3. create new worldmatrix using the transformed world position

 

Would this be correct?

0

Share this post


Link to post
Share on other sites


The goal is to have 'world position' oriented at the center of the mesh:

A - world position in my scene: 10, 3, 2

B - center in modelspace is 3, 2, 1

1. create worldmatrix based on A
2. transform B using this worldmatrix
3. create new worldmatrix using the transformed world position

Would this be correct?

I'm not sure how you plan to do 2, but that sequence may not be what you want. Maybe it's a matter of semantics.

 

Just for clarity, if you're looking to keep a transform that you can use to render the mesh vertices, and you want the center of the mesh at (10,3,2), then the result of your step 3 would be (7, 1, 1). Is that what you intended?

 

That is, if you want the mesh center to be at (10, 3, 2), you'd translate by (7, 1, 1).

 

Hopefully I didn't misunderstand what you were saying.

0

Share this post


Link to post
Share on other sites
I think your right. I'm basically making sure that the world position of an object in the scene, is always the center of that object in worldspace.

Meaning I could multiply a childs transform matrix with the parent world matrix, to get the child world matrix. I need to do the 'transform' first for meshes where 0,0,0 is not the center, because offset child to parent (child pos) is "center to center".

Ps: is it correct that I multiply child orientation matrix with parent world matrix? (and not the other way around)
It sounds logical that the vertices are first transformed in their own space and then "moved" to the parent. Otherwise a child would be for example rotating around the origin of the parent. Ps; I use d3d(x). Something strange though is that using child transform * parent world (to get child world matrix), gives me as a result that X/Y and Z rotation are switched, so rotating on Y axis makes the child rotate on the Z axis etc. Might be something completely different, but it made me doubt which of the 2 options would be correct (because when doing parentworld * child transform, X, Y and Z are not switched around but other things like positions are messed up).
0

Share this post


Link to post
Share on other sites

is it correct that I multiply child orientation matrix with parent world matrix? (and not the other way around)

If you're using the default settings for DX9, the multiplication order should be child * parent.

 

 

 


It sounds logical that the vertices are first transformed in their own space and then "moved" to the parent.

Absolutely.

 

 

 


Something strange though is that using child transform * parent world (to get child world matrix), gives me as a result that X/Y and Z rotation are switched

You haven't mentioned where you're getting your data. It sounds like you may be importing from a file modeled in a right-handed reference frame. E.g., modeled in Blender and exported without conversion to a left-hand system. Are you saying if you use Parent-world * child-local every renders correctly?

Edited by Buckeye
0

Share this post


Link to post
Share on other sites

Thanks. That means I shold stop switching between child world = local transfrom * world parent vs world parent * local transform.

Having one truth on this, enables me to focus on solving the left over issues.

 

Here's a screenshot of both:

http://www.sierracosworth.nl/gamedev/screen_transformXparent.jpg

http://www.sierracosworth.nl/gamedev/screen_parentXlocal.jpg

 

Note: don't mind the knife/ weapon, that's probably for another reason, that it's child are 'overlapping' (weapon mesh not going into the same code/ functions).

 

I've tried switching Y and Z values of the individual vertices, to check if that's the problem. But that just 'rotates' the whole scene 90 degrees. I'm quite sure this is tackled by the exporter I use to export max to X file (KwXPort).

 

So basically with the right approach on parent/child, I have these issues left:

- Movement of childs Z = Y, Y = Z (X = OK) => note that for parent movement Y = Y, Z = Z, is OK

- Rotation of childs is oriented fine to parent, but Axis'es for rotations are: Z = Y, Y = Z (X = OK)

 

When I switch to worldchild = parentworld * childtransform, the issues are:

- parent - child offsets are off

- rotations Y =Y, Z = Z is correct, but childs are rotated around origin of parent (not OK)

 

UPDATE: when I set the local transform matrix for a child a world matrix, obviously all objects and childs are centered in the worlds origin, BUT the Y and Z is not switched. So in the local transform matrix on itself, there's no issue with Y and Z. The same for the parent world matrix. But somehow both combined switches Y and Z and vice versa.

 

 

Here are some code snippets, any input on where I't goes wrong with Y/Z with childs would be great.

// after loading the mesh, transform child vertices to their 'own origin'

bool CD3dmesh::UpdateVtxBufferRenderables()
{
	mChildCenters.resize(GetSubMeshSize());

//	Allocate memory for the vertices of the full mesh
	TVERTEX *verticesPointer;
	TVERTEX *vertices = new TVERTEX[mMesh->GetNumVertices()];

//	Lock the vertexbuffer of the full mesh and copy data to pointer
	mVtxBuffer->Lock(0, 0, (void**)&verticesPointer, 0);		// ,0 = default
	memcpy(vertices, verticesPointer, mMesh->GetNumVertices()*D3DXGetDeclVertexSize(vtxdecl, 0)); 

//	Find the sphere center in modelspace of FULL MESH
	if(!SUCCEEDED(D3DXComputeBoundingSphere(&vertices[0].position, mMesh->GetNumVertices(), D3DXGetDeclVertexSize(vtxdecl, 0), &mParentCenter, &mParentRadius))) return false;	

//	Go through all renderables and transform their vertices
	for(DWORD obj=0;obj<GetSubMeshSize();++obj)
	{
		D3DXVECTOR3 childCenter;
		float sphereBoundingRadiusBase;
		if(!SUCCEEDED(D3DXComputeBoundingSphere(&vertices[mSubMeshTable[obj].VertexStart].position, (DWORD)mSubMeshTable[obj].VertexCount, D3DXGetDeclVertexSize(vtxdecl, 0), 
												&mChildCenters[obj], &sphereBoundingRadiusBase))) return false; 

		for(DWORD vtx=mSubMeshTable[obj].VertexStart;vtx<mSubMeshTable[obj].VertexStart + mSubMeshTable[obj].VertexCount;++vtx)
		{
			vertices[vtx].position += D3DXVECTOR3(mParentCenter.x - mChildCenters[obj].x, 
			 					   				  mParentCenter.y - mChildCenters[obj].y,
												  mParentCenter.z - mChildCenters[obj].z);
		}
	}

//	Copy the newly transformed vertices back into the vertexbuffer
	memcpy(verticesPointer, vertices, mMesh->GetNumVertices()*D3DXGetDeclVertexSize(Crealysm_dxmath::vtxdecl, 0)); 

//	Unlock the vertexbuffer and delete the vertices data
	mVtxBuffer->Unlock();
	delete[] vertices;

	return true;
}

// seting up orientation etc. for mesh instances, using 'mesh X'
// OBB / AABB etc. code removed for readability

bool CD3dmeshInst::SetupBVWorldSpace(const CD3dmesh &pMesh)
{
	// resize vectors for renderables
	mRenderables.resize(pMesh.mSubMeshSize);

	// RETRIEVE ORINGINAL BOUNDING SPHERE FROM MESH & CREATE BOUNDING VOLUMES
	mSphereCenterModel			= pMesh.GetParentCenter();
	mSphereBoundingRadiusBase	= pMesh.GetParentRadius();
	
	// CREATE BOUNDING VOLUMES (SPHERE & AABB) FOR RENDERABLES, MODEL SPACE
	for(size_t obj=0;obj<GetNrRenderables();++obj)
	{
		D3DXVECTOR3 parentToChild = pMesh.mChildCenters[obj] - pMesh.mParentCenter;		// both in the same space
		mRenderables[obj].Move(parentToChild.x, parentToChild.y, parentToChild.z);
	}

	// CREATE WORLD MATRIX AND TRANFORM BOUNDING VOLUMES TO WORLDSPACE (SPHERE, AABB/OBB): FULL MESH
	CreateWorldMatrix();

	D3DXVec3TransformCoord(&mSphereCenterWorld, &mSphereCenterModel, &mMatWorld);
	mSphereBoundingRadius = mSphereBoundingRadiusBase * mScale;

	// Move worldPos of parents to their center, for correct orientation to childs
	// Child pos = based on center parent and center child
	mWorldPos = mSphereCenterWorld;
	UpdateWorldMatrix();

	// RENDERABLES: SETUP (i.e. CREATE WORLD MATRIX + BOUNDING VOLUMES TO WORLDSPACE)
	for(size_t obj=0;obj<GetNrRenderables();++obj)
	{
		mRenderables[obj].CreateWorldMatrix(mMatWorld);			// pass parent world matrix
	}
	return true;
}

// RENDERABLE: creating and updating the world matrix

/**************************************************************************************/
/***								CREATE WORLDMATRIX 								***/
/*** ==> usage: at scene loading, initial for each renderable 						***/
/*** ==> create D3DXMATRIX for worldspace, translation, rotation, scaling			***/
/**************************************************************************************/

void CD3drenderable::CreateWorldMatrix(const D3DXMATRIX &pMatWorldParent)
{
	ComposeD3DXWorldMatrix(&mMatTransform, D3DXVECTOR3(mScale, mScale, mScale), DEGTORAD(mRot.x), DEGTORAD(mRot.y), DEGTORAD(mRot.z), mPos);
//	D3DXMatrixMultiply(&mMatWorld, &pMatWorldParent, &mMatTransform);
	D3DXMatrixMultiply(&mMatWorld, &mMatTransform, &pMatWorldParent);
}

/**************************************************************************************/
/***								UPDATE WORLDMATRIX								***/
/*** ==> usage: before rendering, ONLY when object is moved, rotated or scaled		***/
/*** ==> updates WorldMatrix, local transform * parent world 						***/
/**************************************************************************************/

bool CD3drenderable::UpdateWorldMatrix(const D3DXMATRIX &pMatWorldParent)
{
	if(mDynamic)
	{
		if(mIsMoved || mIsRotated || mIsScaled)
		{
			ComposeD3DXWorldMatrix(&mMatTransform, D3DXVECTOR3(mScale, mScale, mScale), DEGTORAD(mRot.x), DEGTORAD(mRot.y), DEGTORAD(mRot.z), mPos);
		}
	}
	D3DXMatrixMultiply(&mMatWorld, &mMatTransform, &pMatWorldParent);
//	D3DXMatrixMultiply(&mMatWorld, &pMatWorldParent, &mMatTransform);
	return true;
}

// math function: creating a world matrix in 1 step

/**************************************************************************************/
/***							COMPOSE D3DX WORLD MATRIX							***/
/*** ==> usage: when a world matrix has to be created or updated 					***/
/*** ==> returns the newly created D3DXMATRIX										***/
/**************************************************************************************/

D3DXMATRIX* ComposeD3DXWorldMatrix(D3DXMATRIX *pOut, const D3DXVECTOR3 &pScale, const float pXrot, const float pYrot, const float pZrot, const D3DXVECTOR3 pTranslation)
{
    pOut->m[0][0] = std::cos(pYrot) * std::cos(pZrot) * pScale.x;
    pOut->m[0][1] = std::cos(pYrot) * std::sin(pZrot) * pScale.x;
    pOut->m[0][2] = -std::sin(pYrot) * pScale.x;
    pOut->m[0][3] = 0.0f;

    pOut->m[1][0] = (((std::sin(pXrot) * std::sin(pYrot)) * std::cos(pZrot)) + (std::cos(pXrot) * -std::sin(pZrot))) * pScale.y;
    pOut->m[1][1] = (((std::sin(pXrot) * std::sin(pYrot)) * std::sin(pZrot)) + (std::cos(pXrot) * std::cos(pZrot))) * pScale.y;
    pOut->m[1][2] = std::sin(pXrot) * std::cos(pYrot) * pScale.y;
    pOut->m[1][3] = 0.0f;

    pOut->m[2][0] = (((std::cos(pXrot) * std::sin(pYrot)) * std::cos(pZrot)) + (-std::sin(pXrot) * -std::sin(pZrot))) * pScale.z;
    pOut->m[2][1] = (((std::cos(pXrot) * std::sin(pYrot)) * std::sin(pZrot)) + (-std::sin(pXrot) * std::cos(pZrot))) * pScale.z;
    pOut->m[2][2] = std::cos(pXrot) * std::cos(pYrot) * pScale.z;
    pOut->m[2][3] = 0.0f;

    pOut->m[3][0] = pTranslation.x;
    pOut->m[3][1] = pTranslation.y;
    pOut->m[3][2] = pTranslation.z;
    pOut->m[3][3] = 1.0f;

    return pOut;
}

Edited by cozzie
0

Share this post


Link to post
Share on other sites

Found it!

The problem is likely to be in my head instead of the code :)

 

- parent is rotated -90 degrees on the X axis

- afterwards a child is rotated on the Y axis

- because of parent rotation Y becomes Z and Z becomes Y

 

If I don't rotate the parent then Y and Z are fine when I rotate the child. The same goes for 'moving'.

So basically (and logical when I think of it after hours of debugging....) the child is translated and rotated relative to it's parent, not to the world X/Y and Z axis.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0