![]() |
|
This example demonstrates how to populate the texture writer with all the faces found in a model, how to write all the appropriate texture files, and how to generate UV coordinates corrected for perspective distortions. This is one of the most common pitfalls when using the SkpReader API.
Objects implementing the ISkpTextureWriter interface support the abilities to determine which image files are associated with a particular face, write those image files, and correct for perspective distortion.
This example is an abridged form of the SkpToXML exporter example code that comes with the SDK. It does not show how to handle inheritance of textures from component instances or groups to faces they contain. To see how that is done, see the SkpToXML exporter example.
void CXMLExporter::LoadAndWriteTextureFiles() { HResult hr; // Get the ISkpApplication from the ISkpDocument CComPtr<ISkpApplication> pApp; hr = m_pDocument->get_Application(&pApp); // Get the ISkpTextureWriter2 interface from ISkpApplication. You // first have to get the ISkpTextureWriter, then get the ISkpTextureWriter2 // extension from that. CComPtr<ISkpTextureWriter> pTW; hr = pApp->CreateTextureWriter(&pTW); hr = pTW->QueryInterface(IID_ISkpTextureWriter2, (void**)&m_pTextureWriter); // Get the top-level ISkpEntityProvider interface from the ISkpDocument, // which is the root component in the model CComPtr<ISkpEntityProvider> pEntProvider; hr = m_pDocument->QueryInterface(IID_ISkpEntityProvider, (void**) &pEntProvider); // Start recursing down the component hierarchy, loading the textures into // the ISkpTextureWriter2 along the way LoadTexturesFromEntities(pEntProvider); // Write out all the textures to a folder std::string btextureDir = GetExportFolder(); _bstr_t textDirBstr(btextureDir.c_str()); hr = m_pTextureWriter->WriteAllTextures(textDirBstr, FALSE); } // This loads the textures for all the faces in the ISkpEntityProvider. It recursively // calls itself for all the component instances, groups and images in the entity set // so that we load textures for faces all the way down the component hierarchy. void CXMLExporter::LoadTexturesFromEntities(CComPtr<ISkpEntityProvider> pEntProvider) { HResult hr; long nElements, i; // Recurse through any component instances in this set of entities CComPtr<ISkpComponentInstances> pInstances = NULL; hr = pEntProvider->get_ComponentInstances(&pInstances); hr = pInstances->get_Count(&nElements); for(i=0; i<nElements; i++) { // Get the ISkpComponentInstance from the ISkpComponentInstances CComPtr<ISkpComponentInstance> pInstance; hr = pInstances->get_Item(i, &pInstance); // Get the instance's component definition (ISkpComponentDefinition) CComPtr<ISkpComponentDefinition> pDef; hr = pInstance->get_ComponentDefinition(&pDef); // Get the ISkpEntityProvider interface from the ISkpComponentDefinition CComPtr<ISkpEntityProvider> pEntProvider; hr = pDef->QueryInterface(IID_ISkpEntityProvider, (void**) &pEntProvider); // Recursively call this function LoadTexturesFromEntities(pEntProvider); } // Recurse through any groups in this set of entities CComPtr<ISkpGroups> pGroups = NULL; hr = pEntProvider->get_Groups(&pGroups); hr = pGroups->get_Count(&nElements); for(i=0; i<nElements; i++) { // Get the ISkpGroup from the ISkpGroups CComPtr<ISkpGroup> pGroup; hr = pGroups->get_Item(i, &pGroup); // Get the ISkpEntityProvider interface from the ISkpGroup CComPtr<ISkpEntityProvider> pEntProvider; hr = pGroup->QueryInterface(IID_ISkpEntityProvider, (void**) &pEntProvider); // Recursively call this function LoadTexturesFromEntities(pEntProvider); } // Recurse through any images in this set of entities CComPtr<ISkpImages> pImages = NULL; hr = pEntProvider->get_Images(&pImages); hr = pImages->get_Count(&nElements); for(i=0; i<nElements; i++) { // Get the ISkpImage from the ISkpImages CComPtr<ISkpImage> pImage; hr = pImages->get_Item(i, &pImage); // Get the ISkpEntityProvider interface from the ISkpImage CComPtr<ISkpEntityProvider> pEntProvider; hr = pImage->QueryInterface(IID_ISkpEntityProvider, (void**) &pEntProvider); // Recursively call this function LoadTexturesFromEntities(pEntProvider); } // Load all the textures applied to faces in this set of entities CComPtr<ISkpFaces> pFaces = NULL; hr = pEntProvider->get_Faces(&pFaces); hr = pFaces->get_Count(&nElements); for(i=0; i<nElements; i++) { // Get the ISkpFace from the ISkpFaces CComPtr<ISkpFace> pFace; hr = pFaces->get_Item(i, &pFace); // Load the texture on the FRONT side of the face into the texture writer long handle = 0; hr = m_pTextureWriter->LoadFace(pFace, /*bFront*/ true, &handle); // Load the texture on the BACK side of the face into the texture writer handle=0; hr = m_pTextureWriter->LoadFace(pFace, /*bFront*/ false, &handle); } } // Eventually, you'll be writing out the vertices of each face and will want the UV texture // coordinates associated with each vertex. This is an abridged version of the WriteFace() method // in the SkpToXML exporter example. void CXMLExporter::WriteFace(CComPtr<ISkpFace> pFace) { HResult hr; //------------------------------------------------------------------------------------------------ // Determine which sides of this face have textures applied to them BOOL bHasFrontTexture = false; BOOL bHasBackTexture = false; CComPtr<ISkpMaterial> pFrontMaterial = NULL; hr = pFace->get_FrontMaterial(pFrontMaterial); if (pFrontMaterial) { hr = pFrontMaterial->get_IsTexture(&bHasFrontTexture); } CComPtr<ISkpMaterial> pBackMaterial = NULL; hr = pFace->get_BackMaterial(pBackMaterial); if (pBackMaterial) { hr = pBackMaterial->get_IsTexture(&bHasBackTexture); } //------------------------------------------------------------------------------------------------ // Write out the texture file names for the front and back if (bHasFrontTexture) { // Get the name of the texture file and write it out long texture_handle = 0; hr = m_pTextureWriter->GetTextureHandleFromFace(pFace, /*bFront*/ TRUE, &texture_handle) if(texture_handle > 0) { BSTR bstrName; // from the handle, get the texture file name hr = m_pTextureWriter->GetTextureFile(texture_handle, &bstrName); // ***** Write out the name of the front texture file here... ****** ::SysFreeString(bstrName); } } if (bHasBackTexture) { // Get the name of the texture file and write it out long texture_handle = 0; hr = m_pTextureWriter->GetTextureHandleFromFace(pFace, /*bFront*/ FALSE, &texture_handle) if(texture_handle > 0) { BSTR bstrName; // from the handle, get the texture file name hr = m_pTextureWriter->GetTextureFile(texture_handle, &bstrName); // ***** Write out the name of the back texture file here... ****** ::SysFreeString(bstrName); } } //------------------------------------------------------------------------------------------------ // If the face has a texture(s) applied to it, then create a UVHelper class so we can output the uv // coordinates at each vertex. BOOL bHasTexture = bHasFrontTexture | bHasBackTexture; if (bHasTexture) { // You have to create this object from the ISkpTexureWriter to pass into the GetUVHelper method // later. Not creating it as passing in NULL to GetUVHelper will cause your to crash. CComPtr<ISkpCorrectPerspective> pCorrectPerspective; hr = m_pTextureWriter->QueryInterface(IID_ISkpCorrectPerspective, (void**)&pCorrectPerspective); // Get the ISkpUVHelper for this face CComPtr<ISkpUVHelper> pUVHelper = NULL; hr = pFace->GetUVHelper(bHasFrontTexture, bHasBackTexture, pCorrectPerspective, &pUVHelper); // We're going to output the UV's for the vertices around the face's perimeter (outer loop) // in this example. CComPtr<ISkpLoop> pLoop; hr = pFace->get_OuterLoop(&pLoop); // Get the vertices on the perimeter CComPtr<ISkpVertices> pVerts; hr = pLoop->get_Vertices(&pVerts); long nVerts; hr = pVerts->get_Count(&nVerts); // Loop through the vertices for (long i=0;i<nVerts;i++) { CComPtr<ISkpVertex> pVert; hr = pVerts->get_Item(i, &pVert); // Get the position of the vertex - not this in the local coordinate space (LCS) CComPtr<ISkpPoint3d> pSkpPoint; hr = pVert->get_Position(&pSkpPoint); // Transform the point into world coordinate space (WCS) CPoint3d point(pSkpPoint); CPoint3d worldPoint = m_InheritanceManager.GetCurrentTransform() * point; if (bHasFrontTexture) { // Get the uv coordinates of the front texture at this point double u, v, q; pUVHelper->GetFrontUVQ(worldPoint.X(), worldPoint.Y(), worldPoint.Z(), &u, &v, &q); // ***** Write out the UV coordinates for the front texture on this face at this vertex... ***** } if (bHasBackTexture) { // Get the uv coordinates of the back texture at this point double u, v, q; pUVHelper->GetBackUVQ(worldPoint.X(), worldPoint.Y(), worldPoint.Z(), &u, &v, &q); // ***** Write out the UV coordinates for the back texture on this face at this vertex... ***** } } } }
©2010 Google - Google Home - About Google |