Skip to main content
GameDev.net gamedev.net
🔒 Locked

[SOLVED] Transformation matrices of individual subsets of an x file

Started by Asesh Nov 23, 2011 at 3:44 AM 8 replies 1.9k views
Original Post
Asesh
Asesh
Right now am stuck in collision detection. I have computed bounding boxes of all the subsets of an x file and want to display the bounding boxes of all the subsets along with them. But seems like D3DXComputeBoundingBox computes the bounding box in object space. I want to find out the translation vector or transformation matrices of all the subsets so that I can translate those bounding boxes along with their min and max points for collision detection of individual subsets. I have attached a screen shot, there are three subsets ie 3 boxes which is for testing purposes only. Actually, I will be implementing the same technique for a huge scene but first I have to get this right.

While the bounding box of one subset is bigger than it's corresponding subset in the middle, it's by design because it will be used for sliding
th_19708_SceneSimulation_122_516lo.jpg
Thanks
iedoc
iedoc
You just use the same transformation matrix for the bounding boxes that you used for the object. If the object only has one transformation matrix, you can use that matrix to transform each of the boxes, otherwise, if each subset has its own matrix, you can use that subset's matrix to transform the boxes. you can do the same for the min and max points
Asesh
Asesh

You just use the same transformation matrix for the bounding boxes that you used for the object. If the object only has one transformation matrix, you can use that matrix to transform each of the boxes, otherwise, if each subset has its own matrix, you can use that subset's matrix to transform the boxes. you can do the same for the min and max points


Actually, it's a single X file with 3 subsets and upon applying identity transformation, all the subsets will rendered in their actual position as I have had set when modeling in 3ds Max. So I don't have to manually set the transformation matrices for individual subsets. Now how do I find out the transformation matrices for individual subsets? As I said before D3DXComputeBoundingBox will compute the bounding box of subset in object space for example all the computed min and max points of subsets are in the range (-x, -y, -z) and (x, y, z). Thanks
programci_84
programci_84
If I understood correctly, you want to gather the transformation info of mesh's subset(s).

Here's what I do:

1) Compute bounding box via D3DXComputeBoundingBox() or something like it.

2) Compute box' center pt:
vCenter = (vMax + vMin) * .5f;

3) Transform that center point with model's world matrix:
D3DXVECTOR3 vCenter_transformed;
D3DXTransformCoord (&vCenter_transformed, &vCenter, &modelWorldMatrix);

4) All the subsets use the same transformation as your model's. So, the last work is translating the subset's bounding volume:
subsetWorldMatrix = modelWorldMatrix;
subsetWorldMatrix._41 = vCenter_transformed.x;
subsetWorldMatrix._42 = vCenter_transformed.y;
subsetWorldMatrix._43 = vCenter_transformed.z;

This work is for only one subset. You have to iterate these steps for all subsets.

hth.
-R
There's no "hard", and "the impossible" takes just a little time.
Asesh
Asesh

If I understood correctly, you want to gather the transformation info of mesh's subset(s).

Here's what I do:

1) Compute bounding box via D3DXComputeBoundingBox() or something like it.

2) Compute box' center pt:
vCenter = (vMax + vMin) * .5f;

3) Transform that center point with model's world matrix:
D3DXVECTOR3 vCenter_transformed;
D3DXTransformCoord (&vCenter_transformed, &vCenter, &modelWorldMatrix);

4) All the subsets use the same transformation as your model's. So, the last work is translating the subset's bounding volume:
subsetWorldMatrix = modelWorldMatrix;
subsetWorldMatrix._41 = vCenter_transformed.x;
subsetWorldMatrix._42 = vCenter_transformed.y;
subsetWorldMatrix._43 = vCenter_transformed.z;

This work is for only one subset. You have to iterate these steps for all subsets.

hth.
-R



Thanks for the reply but it didn't solve my problem. The min and max points of all three boxes returned by D3DXComputeBoundingBox are: (-10, -10, -10) and (10, 10, 10) and their center points: (0, 0, 0). I have just applied identity transformation (world matrix) to all the subsets and adjusted the camera accordingly so the transformed center is also (0, 0, 0). What could be wrong?
programci_84
programci_84
The problem comes from bounding box calculation, I think.

Can you post your subset bounding box calculation code?

Here's what I'm using for subset bounding volume calculation:

struct _BoundingBox
{
D3DXVECTOR3 vMax, vMin;
};

void CalculateBoundingBoxes (LPD3DXMESH pModelMesh, std::vector<_BoundingBox>& boxes)
{
LPD3DXATTRIBUTERANGE* pAttribTable = NULL;
DWORD numSubsets = 0;
pModelMesh->GetAttributeTable (NULL, &numSubsets);
pAttribTable = new LPD3DXATTRIBUTERANGE[numSubsets];
pModelMesh->GetAttributeTable (pAttribTable, &numSubsets);

DWORD sizeOfVertex = pModelMesh->GetFVFVertexSize( pModelMesh->GetFVF() );

//now we've all the subset data we need.

DWORD* pData = NULL;
pModelMesh->LockVertexBuffer (D3DLOCK_READONLY, (DWORD*)&pData);
for (UINT s = 0; s < numSubsets; s++)
{
_BoundingBox mBox;

BYTE* temp = (BYTE*)pData;
temp = pAttribTable.VertexStart * sizeOfVertex; //holds the address of the first vertex in i th subset

DWORD* dwFirstVertex = (DWORD*)temp;
D3DXVECTOR3* vFirstVertex = (D3DXVECTOR3*) &dwFirstVertex [0];

DWORD numVerticesInSubset = pAttribTable.VertexCount;

D3DXComputeBoundingBox (vFirstVertex, numVerticesInSubset, sizeOfVertex, &mBox.vMin, &mBox.vMax);

boxes.push_back (mBox);
}
pModelMesh->UnlockVertexBuffer ();
}


hth.
-R
There's no "hard", and "the impossible" takes just a little time.
Asesh
Asesh

The problem comes from bounding box calculation, I think.

Can you post your subset bounding box calculation code?

Here's what I'm using for subset bounding volume calculation:

struct _BoundingBox
{
D3DXVECTOR3 vMax, vMin;
};

void CalculateBoundingBoxes (LPD3DXMESH pModelMesh, std::vector<_BoundingBox>& boxes)
{
LPD3DXATTRIBUTERANGE* pAttribTable = NULL;
DWORD numSubsets = 0;
pModelMesh->GetAttributeTable (NULL, &numSubsets);
pAttribTable = new LPD3DXATTRIBUTERANGE[numSubsets];
pModelMesh->GetAttributeTable (pAttribTable, &numSubsets);

DWORD sizeOfVertex = pModelMesh->GetFVFVertexSize( pModelMesh->GetFVF() );

//now we've all the subset data we need.

DWORD* pData = NULL;
pModelMesh->LockVertexBuffer (D3DLOCK_READONLY, (DWORD*)&pData);
for (UINT s = 0; s < numSubsets; s++)
{
_BoundingBox mBox;

BYTE* temp = (BYTE*)pData;
temp = pAttribTable.VertexStart * sizeOfVertex; //holds the address of the first vertex in i th subset

DWORD* dwFirstVertex = (DWORD*)temp;
D3DXVECTOR3* vFirstVertex = (D3DXVECTOR3*) &dwFirstVertex [0];

DWORD numVerticesInSubset = pAttribTable.VertexCount;

D3DXComputeBoundingBox (vFirstVertex, numVerticesInSubset, sizeOfVertex, &mBox.vMin, &mBox.vMax);

boxes.push_back (mBox);
}
pModelMesh->UnlockVertexBuffer ();
}


hth.
-R


Here's the code:



DWORD dwAttributeTableSize, *pdwVertexData;

BYTE *pbVertexData;

// Lock the vertex buffer and obtain a pointer to the vertex data
if(SUCCEEDED((m_pD3DXSceneMesh->LockVertexBuffer(D3DLOCK_READONLY, reinterpret_cast<void **>(&pdwVertexData)))))
{
// Loop through all the subsets to compute their corresponding bounding box
for(DWORD dwAttributeID = 0; dwAttributeID < dwAttributeTableSize; dwAttributeID++)
{
pbVertexData = reinterpret_cast<BYTE *>(pdwVertexData);

pbVertexData += pD3DXAttributeRange[dwAttributeID].VertexStart * g_pD3DGraphics->getVertexDeclarationLength(); // Calculate offset to vertex data

D3DXVECTOR3 *pD3DXStartVertex = reinterpret_cast<D3DXVECTOR3 *>(&pbVertexData[0]); // Starting vertex

DWORD dwNumOfVertices = pD3DXAttributeRange[dwAttributeID].VertexCount; // Assign number of vertices of the current subset

// Loop through all the vertices and separate the vertices, normals and texture coordinates
for(DWORD dwVertex = 0; dwVertex < dwNumOfVertices; dwVertex++)
{
// Extract vertices, normals and texture coordinate data
const D3DXVECTOR3 *pD3DXVertex = reinterpret_cast<const D3DXVECTOR3 *>(pbVertexData); // Vertex
const D3DXVECTOR3 *pD3DXNormal = reinterpret_cast<const D3DXVECTOR3 *>(pbVertexData + sizeof(D3DXVECTOR3)); // Normal
const D3DXVECTOR2 *pD3DXTexture = reinterpret_cast<const D3DXVECTOR2 *>(pbVertexData + sizeof(D3DXVECTOR3) + sizeof(D3DXVECTOR3)); // Texture

pbVertexData += dwStride; // Next vertex data
}

// Compute the bounding box of the current subset
::D3DXComputeBoundingBox(pD3DXStartVertex,
dwNumOfVertices,
g_pD3DGraphics->getVertexDeclarationLength(),
&oBoundingBox.m_oD3DXLowerLeftCorner,
&oBoundingBox.m_oD3DXUpperRightCorner);

//
// Added this code as you told me to do so
//
oBoundingBox.m_oD3DXCenter = (oBoundingBox.m_oD3DXLowerLeftCorner + oBoundingBox.m_oD3DXUpperRightCorner) * 0.5f;

::D3DXVec3TransformCoord(&oBoundingBox.m_oD3DXTransformedCenter, &oBoundingBox.m_oD3DXCenter, ::D3DXMatrixIdentity(&g_pTransformMatrices->m_oD3DXWorldMatrix));

// Calculate the height, width and depth of the bounding box for rendering
oBoundingBox.m_fBoundingBoxHeight = oBoundingBox.m_oD3DXUpperRightCorner.y - oBoundingBox.m_oD3DXLowerLeftCorner.y; // Height
oBoundingBox.m_fBoundingBoxWidth = oBoundingBox.m_oD3DXUpperRightCorner.x - oBoundingBox.m_oD3DXLowerLeftCorner.x ; // Width
oBoundingBox.m_fBoundingBoxDepth = oBoundingBox.m_oD3DXUpperRightCorne.z - oBoundingBox.m_oD3DXLowerLeftCorner.z ; // Depth

::D3DXCreateBox(g_pD3DGraphics->getDevice(), oBoundingBox.m_fBoundingBoxWidth, oBoundingBox.m_fBoundingBoxHeight, oBoundingBox.m_fBoundingBoxDepth, &m_ppD3DXBoundingBoxesMesh[dwAttributeID], NULL);

}

CHECK_COM(m_pD3DXSceneMesh->UnlockVertexBuffer()); // Unlock vertex buffer
}



The second for loop is for iterating through all the vertices, normals and texture coordinates of a subset. After comparing, seems like code for computing bounding box is OK
It's been a couple of days am stuck in it And thanks for replying again

Edited: Removed some lines of code since they were not relevant
Asesh
Asesh
After loading the same x file on Frank Luna's Intro to 3D game programming with Dx 9.0c example, the min point's y coordinate differs from that of mine. My code sets the min point to (-10, -10, -10) while the example code sets the min point to (-10, 0, 10) on calling D3DXComputeBoundingBox. I will soon look into it and post updates. Anyways, thanks
Adaline
Adaline
Hi
I'll assume this :
the structure of a x mesh is a tree, each node called 'frame' contains :

- subset indices (which subsets must be drawn here ?)
- material indices (which material to use for each subset here ?)
- a transform
- children frames

My reply is irrelevant if it's not the case, so please let me know that, and I'll delete my reply.


When you parse the tree, you use a matrix stack (D3DX provides an implementation of matrix stack) to compute the complete local transform of a given node :
when entering in a node, push the local transform
when exiting a node, pop the last transform

If you use a static mesh (I mean that local transforms never change) you can flatten the structure and precompute the complete local transforms only once (at cooking).
You would just have to read an array containing all the frames with ready-to-use local transforms when rendering

More generally, it's possible to use a cache of complete local transforms that are recomputed only when needed.

There are 2 ways to compute your subset bounding boxes :
- compute the subset bounding box in the local frame, and transform it to get it in world space. ( but you'll lose accuracy when transforming the bounding box (because it's axis aligned bounding box). The advantage is that you'd compute your aabbs only once (at cooking)
- transform the subset into world space, and then compute its bounding box (more accurate but more expensive since it must be recomputed from scratch for each frame if the object rendered with this mesh isn't static or if the mesh itself isn't static)

It depends on your needs

(Concerning D3DXComputeBoundingBox : it computes the aabb with given vertex array, it nevers apply a transform on it)

I hope this will help, unless my assumptions on x meshes are wrong. Please let me know

wink.gif
Asesh
Asesh
Finally, found out what's wrong. The third parameter that I had passed to D3DXCreateBoundingBox was wrong. Rather than passing sizeof(SVertexFormat) which holds position, normal and texture data as I had modified the mesh to compute normals and so on; I had been passing the length of vertex declaration which I had computed as shown below:



// Vertex element with 3D position, normal and 2D texture coordinates
D3DVERTEXELEMENT9 oD3DVertexElement[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // Position
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // Normal
{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // Texture
D3DDECL_END()
};

m_uiVertexElementLength = sizeof(oD3DVertexElement) / sizeof(D3DVERTEXELEMENT9); // 4 bytes



Works on a mesh with a single subset now will have to do the same thing for meshes with multiple subsets. Thanks again guys

Edited: Now works on a mesh with multiple subsets. I had to fix calculation of vertex offset too and now it works. It's posted below.

Here's the final code after I got it right:




DWORD *pdwVertexData;

BYTE *pbVertexData;

// Lock the vertex buffer and obtain a pointer to the vertex data
if(SUCCEEDED((m_pD3DXSceneMesh->LockVertexBuffer(D3DLOCK_READONLY, reinterpret_cast<void **>(&pdwVertexData)))))
{
// Loop through all the subsets to compute their corresponding bounding box
for(DWORD dwAttributeID = 0; dwAttributeID < dwAttributeTableSize; dwAttributeID++)
{
pbVertexData = reinterpret_cast<BYTE *>(pdwVertexData);

pbVertexData += pD3DXAttributeRange[dwAttributeID].VertexStart * sizeof(SVertexFormat); // Calculate offset to vertex data

D3DXVECTOR3 *pD3DXStartVertex = reinterpret_cast<D3DXVECTOR3 *>(&pbVertexData[0]); // Starting vertex

DWORD dwNumOfVertices = pD3DXAttributeRange[dwAttributeID].VertexCount; // Assign number of vertices of the current subset

// Loop through all the vertices and separate the vertices, normals and texture coordinates
for(DWORD dwVertex = 0; dwVertex < dwNumOfVertices; dwVertex++)
{
// Extract vertices, normals and texture coordinate data
const D3DXVECTOR3 *pD3DXVertex = reinterpret_cast<const D3DXVECTOR3 *>(pbVertexData); // Vertex
const D3DXVECTOR3 *pD3DXNormal = reinterpret_cast<const D3DXVECTOR3 *>(pbVertexData + sizeof(D3DXVECTOR3)); // Normal
const D3DXVECTOR2 *pD3DXTexture = reinterpret_cast<const D3DXVECTOR2 *>(pbVertexData + sizeof(D3DXVECTOR3) + sizeof(D3DXVECTOR3)); // Texture

pbVertexData += dwStride; // Next vertex data
}

// Compute the bounding box of the current subset
::D3DXComputeBoundingBox(pD3DXStartVertex,
dwNumOfVertices,
sizeof(SVertexFormat),
&oBoundingBox.m_oD3DXLowerLeftCorner,
&oBoundingBox.m_oD3DXUpperRightCorner);

//
// Added this code as you told me to do so
//
oBoundingBox.m_oD3DXCenter = (oBoundingBox.m_oD3DXLowerLeftCorner + oBoundingBox.m_oD3DXUpperRightCorner) * 0.5f;

::D3DXVec3TransformCoord(&oBoundingBox.m_oD3DXTransformedCenter, &oBoundingBox.m_oD3DXCenter, ::D3DXMatrixIdentity(&g_pTransformMatrices->m_oD3DXWorldMatrix));

// Calculate the height, width and depth of the bounding box for rendering
oBoundingBox.m_fBoundingBoxHeight = oBoundingBox.m_oD3DXUpperRightCorner.y - oBoundingBox.m_oD3DXLowerLeftCorner.y; // Height
oBoundingBox.m_fBoundingBoxWidth = oBoundingBox.m_oD3DXUpperRightCorner.x - oBoundingBox.m_oD3DXLowerLeftCorner.x ; // Width
oBoundingBox.m_fBoundingBoxDepth = oBoundingBox.m_oD3DXUpperRightCorne.z - oBoundingBox.m_oD3DXLowerLeftCorner.z ; // Depth

::D3DXCreateBox(g_pD3DGraphics->getDevice(), oBoundingBox.m_fBoundingBoxWidth, oBoundingBox.m_fBoundingBoxHeight, oBoundingBox.m_fBoundingBoxDepth, &m_ppD3DXBoundingBoxesMesh[dwAttributeID], NULL);

}

CHECK_COM(m_pD3DXSceneMesh->UnlockVertexBuffer()); // Unlock vertex buffer
}


Output:

th_91432_SceneSimulation_122_450lo.jpg

Thanks guys

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.