| 
 
 
 The ID3DXMesh class provided in DX 8 allows you to divide a mesh into several parts, or subsets, that can be rendered independently of each other using the ID3DXMesh::DrawSubset() method. This allows you to apply different materials, textures, or renderstates to different portions of a mesh, or to selectively render only certain portions of a mesh. To do this, you must set the attribute ID for each face, to define which subset the face belongs to. First, call ID3DXMesh::LockAttributeBuffer() to get a pointer to the attribute buffer, which is an array of DWORDs that defines the subset number for each face. The subset numbers can be any 32 bit value you choose, though it is typical to use values 0 to n-1 to define n subsets. Once you have locked the attribute buffers, you can set the desired attribute values using the buffer pointer, then unlock the attribute buffer using ID3DXMesh::UnlockAttributeBuffer() when the changes are complete. At this point, you can use ID3DXMesh::DrawSubset() 
to render a subset, but you will 
  first want to perform one more step for the sake of performance.  If you were 
  to call ID3DXMesh::DrawSubset() at this point, it would have to scan through 
  the attribute buffer to determine which faces belong to the requested subset.  
  Instead, if you call ID3DXMesh::OptimizeInPlace() or 
ID3DXMesh::Optimize() 
  with the D3DXMESHOPT_ATTRSORT flag (see 
note below), the index and vertex buffers will be 
  sorted such that each subset represents a contiguous sequence of faces.  This 
  call will also generate an "attribute table", which is an array of one 
  D3DXATTRIBUTERANGE structure per subset defining the starting and ending face 
  numbers for each range, and the range of vertices used.  Once this is 
  performed, ID3DXMesh::DrawSubset() merely has to look up the range of faces 
  and vertices to draw from the attribute table, providing far greater 
  performance. Here is an example of a function that divides a mesh into a series of irregularly sized subsets, allowing subsets to consist of non-contiguous series of faces: 
  // define subset info we will assign 
  DWORD faceCount[] = {  50, 100,  50, 100, 200,   0}; 
  DWORD subsetNum[] = {   0,   1,   0,   2,   3 }; 
  // First 50 faces (0-49) belong to subset 0 
  // Next 100 faces (50-149) belong to subset 1 
  // Next 50 faces (150-199) also belong to subset 0 
  // Next 100 faces (200-299) belong to subset 2 
  // Next 200 faces (300-499) belong to subset 3 
  // 0 faces in final faceCount[] index denotes end of 
  list 
if (FAILED(SetSubsets(pMesh,faceCount,subsetNum)) { // handle error ... 
  } 
DWORD SetSubsets(ID3DXMesh *pMesh,DWORD *pFaceCount,DWORD *pSubsetNum) { 
      // Get face count, used to ensure we don't overrun 
  attribute buffer 
      DWORD numFaces=pMesh->GetFaceCount(); 
      // lock the attribute buffer 
      DWORD *attribBuf; 
      HRESULT hr; 
      if (SUCCEEDED(hr=pMesh->LockAttributeBuffer(D3DLOCK_DISCARD,&attribBuf))) 
  { 
// initialize face counter DWORD faceNum=0; // loop through the subsets for (int i=0;pFaceCount[i];i++) { // make sure there are enough faces for this subset if (faceNum+pFaceCount[i]>=numFaces) { // not enough faces, unlock the attribute buffer and return error code pMesh->UnlockAttributeBuffer(); 
                  return E_INVALIDARG; 
} 
              // loop through the faces for this range 
for (int j=0;j<pFaceCount[i];i++) { // set the subset number of each face in this range attribBuf[faceNum]=pSubsetNum[i]; // increment face counter faceNum++; } } // unlock the attribute buffer pMesh->UnlockAttributeBuffer(); // allocate storage and generate adjacency data DWORD *pAdj=new DWORD[numFaces*3]; if (!pAdj) return E_OUTOFMEMORY; if (FAILED(hr=pMesh->GenerateAdjacency(0.0f,pAdj) { delete pAdj; return hr; } // optimize the mesh with attribute sorting // D3DXMESHOPT_ATTRSORT if (FAILED(hr=pMesh->OptimizeInPlace(D3DXMESHOPT_VERTEXCACHE,pAdj,NULL,NULL,NULL)) { delete pAdj; 
              return hr; 
} // de-allocate adjacency data storage delete pAdj; } else // return error code on failure to lock attribute buffer return hr; // return success return S_OK; 
  } 
  Note that if you already have adjacency data for the mesh, you won't have to re-compute it in the function as I have here - I included that for simplicity. If you already have adjacency data you can pass it to the optimization function, and may also need to provide a pointer to an array to contain the new adjacency information, as a parameter to the optimization function, if you have further use for this data. For more information on using the D3DX Mesh interfaces, see Using the ID3DXMesh Class. 
  | 
 
 
 Visitors Since 1/1/2000: 
 
  |