   [DirectX 10/Assimp] Subset of meshes problem
  How Assimp works:-If a mesh as more than 1 material, Assimp divides the mesh into n sub-meshes (n = nº different materials) so each sub-mesh as only one material.So lets see whay Ive done:First I created 3 buffers:-One for vertices with the size = nº of vertices;-One for indices (faces) with size = nº of faces * 3;-One attribute buffer with size = nº of faces;Then I saved each vertice, indice and material id into each buffer.So Assimp divides the meshes into n sub-meshes, then I add the number of vertices in each sub-mesh so I create the vertex buffer with size to contain the vertices of all sub-meshes.But something isnt working because only the first subset is being rendered correctly... This is how the mesh is being rendered (its suposed to be a dwarf with an axe):The axe (subset 0) is being rendered correctly:This is my loader code:Mesh MeshLoader::importMesh(ID3D10Device* d3dDevice, std::string &file, LPCSTR meshName, int actorType, int meshType){ID3DX10Mesh* dxMesh;Mesh mesh = Mesh();mesh.meshName = meshName;mesh.numSubsets = 0;Vertex* vertices;UINT numVertices = 0;UINT numTriangles = 0;DWORD* indices;UINT* attributeBuffer;scene = importer.ReadFile( file,    aiProcess_CalcTangentSpace  |   aiProcess_Triangulate |   aiProcess_MakeLeftHanded |   aiProcess_JoinIdenticalVertices |   aiProcess_SortByPType |   aiProcess_CalcTangentSpace |   aiProcess_JoinIdenticalVertices |   aiProcess_GenSmoothNormals |   aiProcess_LimitBoneWeights |   aiProcess_RemoveRedundantMaterials |   aiProcess_OptimizeMeshes |aiProcess_GenUVCoords |aiProcess_TransformUVCoords);if(!scene){MessageBox(NULL, "There is a mesh missing. Please try again or reeinstall the game.", "Mesh missing", MB_OK);PostQuitMessage(1);}D3D10_INPUT_ELEMENT_DESC vertexDesc[] ={{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},{"TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0},{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 36, D3D10_INPUT_PER_VERTEX_DATA, 0},};aiMesh** meshes = scene->mMeshes;aiMaterial** materials = scene->mMaterials;UINT* meshID;UINT materialID;aiNode* sceneRoot = scene->mRootNode;aiNode** children = sceneRoot->mChildren;aiNode* child;UINT i = 0;bool rootNode = true;while(i < sceneRoot->mNumChildren){if(rootNode){child = sceneRoot;rootNode = false;} else{child = children;//child = sceneRoot;i++;}if(!(child->mNumMeshes > 0))continue;meshID = child->mMeshes;mesh.numSubsets += child->mNumMeshes;for(UINT x = 0; x < child->mNumMeshes; x++){numVertices += meshes[meshID[x]]->mNumVertices;numTriangles += meshes[meshID[x]]->mNumFaces;}vertices = new Vertex[numVertices];indices = new DWORD[numTriangles*3];attributeBuffer = new UINT[numTriangles];for(UINT x = 0; x < child->mNumMeshes; x++){for(UINT  j = 0; j < meshes[meshID[x]]->mNumVertices; j++){UINT n = 0;if(x != 0){n = j + meshes[meshID[x-1]]->mNumVertices;} else{n = j;}vertices[n].pos = aiVec3ToAqVector3(meshes[meshID[x]]->mVertices[j]);vertices[n].tangent = aiVec3ToAqVector3(meshes[meshID[x]]->mTangents[j]);vertices[n].normal = aiVec3ToAqVector3(meshes[meshID[x]]->mNormals[j]);vertices[n].texC = aiVec3ToAqVector2(meshes[meshID[x]]->mTextureCoords[0][j]);}for(UINT j = 0; j < meshes[meshID[x]]->mNumFaces; j++){UINT n = 0;if(x != 0){n =  j + meshes[meshID[x-1]]->mNumFaces;} else{n = j;}indices[n*3+0] = meshes[meshID[x]]->mFaces[j].mIndices[0];indices[n*3+1] = meshes[meshID[x]]->mFaces[j].mIndices[1];indices[n*3+2] = meshes[meshID[x]]->mFaces[j].mIndices[2];attributeBuffer[n] = meshes[meshID[x]]->mMaterialIndex;}}}D3DX10CreateMesh(d3dDevice, vertexDesc, 4, vertexDesc[0].SemanticName, numVertices, numTriangles, D3DX10_MESH_32_BIT, &dxMesh);dxMesh->SetVertexData(0, vertices);dxMesh->SetIndexData(indices, numTriangles*3);dxMesh->SetAttributeData(attributeBuffer);dxMesh->GenerateAdjacencyAndPointReps(0.001f);dxMesh->Optimize(D3DX10_MESHOPT_ATTR_SORT|D3DX10_MESHOPT_VERTEX_CACHE,0,0);dxMesh->CommitToDevice();mesh.mesh = dxMesh;if(meshType == TRIANGLE_MESH){mesh.actor = Physics::createTriangleMesh(indices, numTriangles, vertices, numVertices, actorType, meshName);} else if(meshType == CONVEX_MESH)mesh.actor = Physics::createConvexMesh(vertices, numVertices, actorType, meshName);delete[] vertices;delete[] indices;delete[] attributeBuffer;return mesh;}AqVector3 MeshLoader::aiVec3ToAqVector3(const aiVector3D& source){AqVector3 vector;vector.x = 0;vector.y = 0;vector.z = 0;vector.x = source.x;vector.y = source.y;vector.z = source.z;return vector;}AqVector2 MeshLoader::aiVec3ToAqVector2(const aiVector3D& source){AqVector2 vector;vector.x = source.x;vector.y = source.y;return vector;}[Edited by - Aqua Costa on April 21, 2010 5:49:49 AM]
  Did you know that ID3DX10Mesh class has to split up the mesh for each material as well? Assimp does that Splitting-Up-By-Material for a reason. Your mesh setup might be easier if you create on ID3DX10Mesh for each aiMesh.[edit]When copying the vertices you need to set "n" to "j" at first. When copying the indices you need to multiply "n" by three, too. And this loop only works for two or less submeshes. As soon as the loop handles a third submesh, it overwrites part of the previous data. Put a breakpoint at the beginning of the loop and step through it.   ;Quote:Original post by SchrompfDid you know that ID3DX10Mesh class has to split up the mesh for each material as well? Assimp does that Splitting-Up-By-Material for a reason. Your mesh setup might be easier if you create on ID3DX10Mesh for each aiMesh..But if I create a ID3DX10 mesh for each aiMesh that assimp generates, for example, as I use PhysX the weapon wouldnt just fall of from the hands of the police? Because the weapon and the police would be separated meshes  ;  I found one bug and now the subset 0 is being rendered correctly but the second subset is still being rendered incorrectly.This is the updated code of the loader:Mesh MeshLoader::importMesh(ID3D10Device* d3dDevice, std::string &file, LPCSTR meshName, int actorType, int meshType){ID3DX10Mesh* dxMesh;Mesh mesh = Mesh();mesh.meshName = meshName;mesh.numSubsets = 0;Vertex* vertices;UINT numVertices = 0;UINT numTriangles = 0;DWORD* indices;UINT* attributeBuffer;scene = importer.ReadFile( file,    aiProcess_CalcTangentSpace  |   aiProcess_Triangulate |   aiProcess_MakeLeftHanded |   aiProcess_JoinIdenticalVertices |   aiProcess_SortByPType |   aiProcess_CalcTangentSpace |   aiProcess_JoinIdenticalVertices |   aiProcess_GenSmoothNormals |   aiProcess_LimitBoneWeights |   aiProcess_RemoveRedundantMaterials |   aiProcess_OptimizeMeshes |aiProcess_GenUVCoords |aiProcess_TransformUVCoords);if(!scene){MessageBox(NULL, "There is a mesh missing. Please try again or reeinstall the game.", "Mesh missing", MB_OK);PostQuitMessage(1);}D3D10_INPUT_ELEMENT_DESC vertexDesc[] ={{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},{"TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0},{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 36, D3D10_INPUT_PER_VERTEX_DATA, 0},};aiMesh** meshes = scene->mMeshes;aiMaterial** materials = scene->mMaterials;UINT* meshID;UINT materialID;aiNode* sceneRoot = scene->mRootNode;aiNode** children = sceneRoot->mChildren;aiNode* child;UINT i = 0;bool rootNode = true;while(i < sceneRoot->mNumChildren){if(rootNode){child = sceneRoot;rootNode = false;} else{child = children;//child = sceneRoot;i++;}if(!(child->mNumMeshes > 0))continue;meshID = child->mMeshes;mesh.numSubsets += child->mNumMeshes;for(UINT x = 0; x < child->mNumMeshes; x++){numVertices += meshes[meshID[x]]->mNumVertices;numTriangles += meshes[meshID[x]]->mNumFaces;}vertices = new Vertex[numVertices];indices = new DWORD[numTriangles*3];attributeBuffer = new UINT[numTriangles];for(UINT x = 0; x < child->mNumMeshes; x++){for(UINT  j = 0; j < meshes[meshID[x]]->mNumVertices; j++){UINT n = 0;if(x != 0){n = j + meshes[meshID[x-1]]->mNumVertices;} else{n = j;}vertices[n].pos = aiVec3ToAqVector3(meshes[meshID[x]]->mVertices[j]);vertices[n].tangent = aiVec3ToAqVector3(meshes[meshID[x]]->mTangents[j]);vertices[n].normal = aiVec3ToAqVector3(meshes[meshID[x]]->mNormals[j]);vertices[n].texC = aiVec3ToAqVector2(meshes[meshID[x]]->mTextureCoords[0][j]);}for(UINT j = 0; j < meshes[meshID[x]]->mNumFaces; j++){UINT n = 0;if(x != 0){n =  j + meshes[meshID[x-1]]->mNumFaces;} else{n = j;}indices[n*3+0] = meshes[meshID[x]]->mFaces[j].mIndices[0];indices[n*3+1] = meshes[meshID[x]]->mFaces[j].mIndices[1];indices[n*3+2] = meshes[meshID[x]]->mFaces[j].mIndices[2];attributeBuffer[n] = meshes[meshID[x]]->mMaterialIndex;}}}D3DX10CreateMesh(d3dDevice, vertexDesc, 4, vertexDesc[0].SemanticName, numVertices, numTriangles, D3DX10_MESH_32_BIT, &dxMesh);dxMesh->SetVertexData(0, vertices);dxMesh->SetIndexData(indices, numTriangles*3);dxMesh->SetAttributeData(attributeBuffer);dxMesh->GenerateAdjacencyAndPointReps(0.001f);dxMesh->Optimize(D3DX10_MESHOPT_ATTR_SORT|D3DX10_MESHOPT_VERTEX_CACHE,0,0);dxMesh->CommitToDevice();mesh.mesh = dxMesh;if(meshType == TRIANGLE_MESH){mesh.actor = Physics::createTriangleMesh(indices, numTriangles, vertices, numVertices, actorType, meshName);} else if(meshType == CONVEX_MESH)mesh.actor = Physics::createConvexMesh(vertices, numVertices, actorType, meshName);delete[] vertices;delete[] indices;delete[] attributeBuffer;return mesh;}AqVector3 MeshLoader::aiVec3ToAqVector3(const aiVector3D& source){AqVector3 vector;vector.x = 0;vector.y = 0;vector.z = 0;vector.x = source.x;vector.y = source.y;vector.z = source.z;return vector;}AqVector2 MeshLoader::aiVec3ToAqVector2(const aiVector3D& source){AqVector2 vector;vector.x = source.x;vector.y = source.y;return vector;};Quote:Original post by Schrompf[edit]When copying the vertices you need to set "n" to "j" at first. When copying the indices you need to multiply "n" by three, too. And this loop only works for two or less submeshes. As soon as the loop handles a third submesh, it overwrites part of the previous data. Put a breakpoint at the beginning of the loop and step through it.These are some of the errors. You might be better of just putting vertex after vertex and correcting the indices to fit. size_t numVertices = 0;size_t numFaces = 0;// count vertices and trianglesfor( size_t a = 0; a < node->mNumMeshes; ++a){  const aiMesh* mesh = scene->mMeshes[node->mMeshes[a]];  numVertices += mesh->mNumVertices;  numFaces += mesh->mNumFaces;}// allocate arrays to store all datastd::vector<Vertex> vertices( numVertices);std::vector<unsigned int> indices( numFaces * 3);std::vector<unsigned int> attributes( numFaces);// store all meshes, one after anothersize_t nextVertex = 0, nextIndex = 0;for( size_t a = 0; a < node->mNumMeshes; ++a){  const aiMesh* mesh = scene->mMeshes[node->mMeshes[a]];  size_t meshStartIndex = nextVertex;  // store vertices  for( size_t b = 0; b < mesh->mNumVertices; ++b)  {    vertices[nextVertex].pos = aiVec3ToAqVector3( mesh->mVertices);    // and so on    nextVertex++;  }  // store indices, corrected by startIndex, and attribute  for( size_t b = 0; b < mesh->mNumFaces; ++b)  {    indices[nextIndex++] = mesh->mFaces.mIndices[0] + meshStartVertex;    indices[nextIndex++] = mesh->mFaces.mIndices[1] + meshStartVertex;    indices[nextIndex++] = mesh->mFaces.mIndices[2] + meshStartVertex;    attributes = a;  }}// now assign datadxMesh->SetVertexData(0, &vertices[0]);dxMesh->SetIndexData(&indices[0], numFaces * 3);dxMesh->SetAttributeData( &attributes[0]);No guarentees given, I typed this out of my hat. I assumed that the D3DXMesh functions make a copy of the data. If not, you need to change the arrays back to dynamically allocated ones or you'll see crashes when leaving the function. Hope that helps.   ;  Erm... "easier"? Sorry to say it that bluntly, but the only error here is *your* code. Assimp's job is already done there, and it won't get any easier than those few lines. Of course my example code here will not work out of the box... it was an example of how you can put several meshes into a single buffer. You'll need to provide a better error report than "it doesn't work" to allow applying it to your specific needs.You can try the D3DXLoadMesh functions... I don't know if they're still around in DX10, but they were in DX9. They only load .x files though, and only a limited subset of what's out there.   ;Quote:Original post by SchrompfErm... "easier"? Sorry to say it that bluntly, but the only error here is *your* code. Assimp's job is already done there, and it won't get any easier than those few lines. Of course my example code here will not work out of the box... it was an example of how you can put several meshes into a single buffer. You'll need to provide a better error report than "it doesn't work" to allow applying it to your specific needs.You can try the D3DXLoadMesh functions... I don't know if they're still around in DX10, but they were in DX9. They only load .x files though, and only a limited subset of what's out there.I'm really sorry if I upset you...I've just read the first part of the code you written, because I didn't realized it had a scrollbar... So I just used the first part and implemented the rest myself so the mesh was being rendered exactly the same way...But now I realized you code has a scrollbar, so I used it again and It worked!!! So thanks a lot.I just didn't understood why you added meshStartIndex to each index because it was the only real difference between our code nad it made the difference:indices[nextIndex++] = mesh->mFaces.mIndices[0] + meshStartIndex;;  Ok, good to see it's working. And good to see it was just a misunderstanding. Please understand that this is a bit of a personal issue for me: It itches me when the thread title says "problem with Assimp" but Assimp is actually working fine and the real problem is the index math. It makes me feel as if our project is blamed for something it can't deliver.   ;Quote:Original post by SchrompfOk, good to see it's working. And good to see it was just a misunderstanding. Please understand that this is a bit of a personal issue for me: It itches me when the thread title says "problem with Assimp" but Assimp is actually working fine and the real problem is the index math. It makes me feel as if our project is blamed for something it can't deliver.I usually start my topics with names like [DirectX 10/ PhysX] so people know that my topic is related to diretcx 10 and physX, this time I didn't used brackets, but my intention was to let people know that topic is related to Assimp, and not to say that the problem in Assimp.   