// // MeshNode::VOnRestore - 3rd Edition, Chapter 14, page 506 // // This function loads the Mesh and ensures the Mesh has normals; it also optimizes the // Mesh for the graphics card's vertex cache, which improves performance by organizing // the internal triangle list for less cache misses. // HRESULT D3DMeshNode9::VOnRestore(Scene *pScene) { if (m_XFileName.empty()) { SetRadius(CalcBoundingSphere()); return D3DSceneNode9::VOnRestore(pScene); } // Change post press - release the Mesh only if we have a valid Mesh file name to load. // Otherwise we likely created it on our own, and needs to be kept. SAFE_RELEASE(m_pMesh); WCHAR str[MAX_PATH]; HRESULT hr; // Load the Mesh with D3DX and get back a ID3DXMesh*. For this // sample we'll ignore the X file's embedded materials since we know // exactly the model we're loading. See the Mesh samples such as // "OptimizedMesh" for a more generic Mesh loading example. V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, m_XFileName.c_str() ) ); V_RETURN( D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, DXUTGetD3D9Device(), NULL, NULL, NULL, NULL, &m_pMesh) ); DWORD *rgdwAdjacency = NULL; // Make sure there are normals which are required for lighting if( !(m_pMesh->GetFVF() & D3DFVF_NORMAL) ) { ID3DXMesh* pTempMesh; V( m_pMesh->CloneMeshFVF( m_pMesh->GetOptions(), m_pMesh->GetFVF() | D3DFVF_NORMAL, DXUTGetD3D9Device(), &pTempMesh ) ); V( D3DXComputeNormals( pTempMesh, NULL ) ); SAFE_RELEASE( m_pMesh ); m_pMesh = pTempMesh; } // Optimize the Mesh for this graphics card's vertex cache // so when rendering the Mesh's triangle list the vertices will // cache hit more often so it won't have to re-execute the vertex shader // on those vertices so it will improve perf. rgdwAdjacency = GCC_NEW DWORD[m_pMesh->GetNumFaces() * 3]; if( rgdwAdjacency == NULL ) return E_OUTOFMEMORY; V( m_pMesh->ConvertPointRepsToAdjacency(NULL, rgdwAdjacency) ); V( m_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) ); SAFE_DELETE_ARRAY(rgdwAdjacency); SetRadius(CalcBoundingSphere()); return D3DSceneNode9::VOnRestore(pScene); }
int32 GenerateSphereAsSimpleCollision(UStaticMesh* StaticMesh) { if (!PromptToRemoveExistingCollision(StaticMesh)) { return INDEX_NONE; } UBodySetup* bs = StaticMesh->BodySetup; // Calculate bounding sphere. FRawMesh RawMesh; FStaticMeshSourceModel& SrcModel = StaticMesh->SourceModels[0]; SrcModel.RawMeshBulkData->LoadRawMesh(RawMesh); FSphere bSphere, bSphere2, bestSphere; FVector unitVec = bs->BuildScale3D; CalcBoundingSphere(RawMesh, bSphere, unitVec); CalcBoundingSphere2(RawMesh, bSphere2, unitVec); if(bSphere.W < bSphere2.W) bestSphere = bSphere; else bestSphere = bSphere2; // Dont use if radius is zero. if(bestSphere.W <= 0.f) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Prompt_10", "Could not create geometry.") ); return INDEX_NONE; } bs->Modify(); // Create new GUID bs->InvalidatePhysicsData(); FKSphereElem SphereElem; SphereElem.Center = bestSphere.Center; SphereElem.Radius = bestSphere.W; bs->AggGeom.SphereElems.Add(SphereElem); // refresh collision change back to staticmesh components RefreshCollisionChange(StaticMesh); // Mark staticmesh as dirty, to help make sure it gets saved. StaticMesh->MarkPackageDirty(); StaticMesh->bCustomizedCollision = true; //mark the static mesh for collision customization return bs->AggGeom.SphereElems.Num() - 1; }
HRESULT D3DShaderMeshNode11::OnRestore(Scene* pScene) { HRESULT hr; V_RETURN(SceneNode::OnRestore(pScene)); V_RETURN(m_VertexShader.OnRestore(pScene)); V_RETURN(m_PixelShader.OnRestore(pScene)); // reload the mesh Resource resource(m_sdkMeshFileName); shared_ptr<ResHandle> pResourceHandle = g_pApp->m_ResCache->GetHandle(&resource); shared_ptr<D3DSdkMeshResourceExtraData11> extra = static_pointer_cast<D3DSdkMeshResourceExtraData11>(pResourceHandle->GetExtra()); SetRadius(CalcBoundingSphere(&extra->m_Mesh11)); return S_OK; }
void Exporter::CalcBoundingSphere(INode *node, Point3 center, float& radius, int all) { if (nullptr == node) return; Matrix3 tm = node->GetObjTMAfterWSM(0); Point3 pt = (tm.GetTrans() - center); float len = pt.Length(); if (node->IsBoneShowing()) { radius = max(len, radius); } else { if (Object *o = node->GetObjectRef()) { if (o->SuperClassID() == GEOMOBJECT_CLASS_ID) { if (o->ClassID() == BONE_OBJ_CLASSID || o->ClassID() == Class_ID(BONE_CLASS_ID, 0) || o->ClassID() == Class_ID(0x00009125, 0) /* Biped Twist Helpers */ ) { radius = max(len, radius); } else { radius = max(len, radius); } } else if (mExportCameras && o->SuperClassID() == CAMERA_CLASS_ID) { radius = max(len, radius); } } } if (all < 0) return; all = (all>0 ? all : -1); for (int i = 0; i < node->NumberOfChildren(); i++) { CalcBoundingSphere(node->GetChildNode(i), center, radius, all); } }
Bool MeshRoot::MRMGen( List<U16> * verts) // = NULL) { #ifndef DOMRMGEN verts; return FALSE; #else // Initialize COM: CoInitialize(NULL); // Ok, Now create the mrmgen COM object: IMRMGen2 * s_lpMRMGen = NULL; HRESULT hr = CoCreateInstance(CLSID_CMRMGEN, NULL, CLSCTX_INPROC_SERVER, IID_IMRMGEN2,(void ** ) &s_lpMRMGen); // Did we get a valid interface: if( (FAILED(hr)) || (!(s_lpMRMGen)) ) { LOG_DIAG( ("couldn't connect to mrmgen.dll; is it registered?") ); return FALSE; } IMESH *imesh = new IMESH; initIMESH( imesh); MeshRootToIMesh( *this, *imesh); //#define DOWRITEMRM #ifdef DOWRITEMRM MRMWrite( imesh, NULL, "in.mrm"); #endif Utils::Memset( ¶ms, 0, sizeof( params)); params.size = sizeof(MRMGenParams); params.flags = 0; // no parameters are valid params.flags |= MRMGP_MERGETHRESH | MRMGP_NORMALSMODE | MRMGP_CREASEANGLE; params.mergeThresh = Vid::Var::mrmMergeThresh; params.normalsCreaseAngle = Vid::Var::mrmNormalCrease; params.normalsMode = Vid::Var::mrmMultiNormals ? PerFacePerVertex : PerVertex; #define VERTTHRESH 0.1f // automatic shadow plane base verts // U32 baseCount = 0, heapSize = vertices.count << 2; U32 * baseIndices = (U32 *) Vid::Heap::Request( heapSize); if (shadowPlane) { Mesh *mesh = NULL; U32 i, j; for (i = 0; i < states.count; i++) { if (!strnicmp(states[i].GetMeshFromRoot()->name.str, "sp-", 3)) { mesh = states[i].GetMeshFromRoot(); break; } } if (mesh && mesh->local) { for (i = 0; i < mesh->local->vertices.count; i++) { Vector v0; mesh->WorldMatrix().Transform( v0, mesh->local->vertices[i]); for (j = 0; j < vertices.count; j++) { Vector &v1 = vertices[j]; if ((F32)fabs(v0.x - v1.x) < VERTTHRESH && (F32)fabs(v0.y - v1.y) < VERTTHRESH && (F32)fabs(v0.z - v1.z) < VERTTHRESH) { baseIndices[baseCount] = j; baseCount++; } } } } } // selected base verts // if (verts) { U32 startBaseCount = baseCount; List<U16>::Iterator vi( verts); U16 * index; while ((index = vi++) != NULL) { U32 i, hit = FALSE; for (i = 0; i < startBaseCount; i++) { if (*index == baseIndices[i]) { hit = TRUE; break; } } if (!hit) { baseIndices[baseCount] = *index; baseCount++; } } } if (baseCount) { params.flags |= MRMGP_NUMBASEVERTICES; params.numBaseVertices = baseCount; params.baseVertices = baseIndices; LOG_DIAG( ("MeshRoot::MRMGen: baseCount = %d", baseCount) ); } MRMResults *mrmResults; // Invoke the algorithm and collect the results: s_lpMRMGen->GenerateMRM(imesh, ¶ms, &mrmResults); // baseIndices Vid::Heap::Restore( heapSize); MRMUpdates *mrmUpdates = mrmResults->pMrmUpdates; if (!mrmUpdates) { // Free memory associated with the results: s_lpMRMGen->FreeMRMResults(mrmResults); // Release memory: freeIMESH( imesh); hr = s_lpMRMGen->Release(); // Shut down COM: CoUninitialize(); return FALSE; } IMESH *orderedImesh = mrmResults->pIMesh; // ASSERT( orderedImesh->numFaces == faces.count); #ifdef DOWRITEMRM MRMWrite (orderedImesh, mrmUpdates, "out.mrm"); #endif // copy ordered geometry data, if its not empty // if ((orderedImesh->numVertices == 0 || orderedImesh->numFaces == 0) || !IMeshToMeshRoot( *this, *orderedImesh, *mrmResults)) { // Free memory associated with the results: s_lpMRMGen->FreeMRMResults(mrmResults); // Release memory: freeIMESH( imesh); hr = s_lpMRMGen->Release(); // Shut down COM: CoUninitialize(); return FALSE; } if (verts) { List<U16>::Iterator vi( verts); U16 * index; while ((index = vi++) != NULL) { if (mrmResults->pVertexMap[*index] == mrmResults->undefIndexValue) { verts->Unlink( index); } else { *index = (U16) mrmResults->pVertexMap[*index]; } } } // allocate mrm data if (mrm) { delete mrm; mrm = NULL; } mrm = new MRM; ASSERT( mrm); mrm->vertCount = (U16)orderedImesh->numVertices; mrm->maxVertCount = mrm->vertCount; mrm->minMinVertCount = U16(baseCount > 7 ? baseCount : 7); if (mrm->minMinVertCount > mrm->vertCount) { mrm->minMinVertCount = mrm->vertCount; } mrm->minVertCount = mrm->minMinVertCount; mrm->vertex = new MRM::Vertex[mrm->vertCount]; ASSERT( mrm->vertex); //#define DOWRITEDATA #ifdef DOWRITEDATA FILE *fp; fp = fopen( "mrmdata.txt", "w"); #endif FaceUpdate *update; // count total number of faceupdates U32 i, j, l, k = 0; for (i = 0; i < mrm->vertCount; i++) { U16 numfu = mrmUpdates->vertexUpdates[i].numFaceUpdates; #ifdef DOWRITEDATA fprintf( fp, "\nverts %d : newfaces %d : faceupdates %d\n", i, mrmUpdates->vertexUpdates[i].numNewFaces, numfu); #endif for (j = l = 0; j < numfu; j++) { update = &mrmUpdates->vertexUpdates[i].faceUpdates[j]; // validate mrm data switch (update->attribToken) { case VertexA: #ifdef DOWRITEDATA fprintf( fp, "face %d : VertexA %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif l++; break; case VertexB: #ifdef DOWRITEDATA fprintf( fp, "face %d : VertexB %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif l++; break; case VertexC: #ifdef DOWRITEDATA fprintf( fp, "face %d : VertexC %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif l++; break; case NormalA: #ifdef DOWRITEDATA fprintf( fp, "face %d : NormalA %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif // if (!indexed) { l++; } break; case NormalB: #ifdef DOWRITEDATA fprintf( fp, "face %d : NormalB %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif // if (!indexed) { l++; } break; case NormalC: #ifdef DOWRITEDATA fprintf( fp, "face %d : NormalC %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif // if (!indexed) { l++; } break; case TexCoord1A: #ifdef DOWRITEDATA fprintf( fp, "face %d : TexCrdA %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif // if (!indexed) { l++; } break; case TexCoord1B: #ifdef DOWRITEDATA fprintf( fp, "face %d : TexCrdB %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif // if (!indexed) { l++; } break; case TexCoord1C: #ifdef DOWRITEDATA fprintf( fp, "face %d : TexCrdC %d : %d\n", update->faceIndex, update->value[0], update->value[1]); #endif // if (!indexed) { l++; } break; } } mrmUpdates->vertexUpdates[i].numFaceUpdates = (U16) l; k += l; } #ifdef DOWRITEDATA if (fp) { fclose(fp); } #endif if (k == 0) { // Free memory associated with the results: s_lpMRMGen->FreeMRMResults(mrmResults); // Release memory: freeIMESH( imesh); hr = s_lpMRMGen->Release(); // Shut down COM: CoUninitialize(); delete [] mrm->vertex; delete mrm; mrm = NULL; return FALSE; } mrm->faceCount = (U16)k; MRM::Face *mrmFace = new MRM::Face[k]; ASSERT( mrmFace); mrm->vertex[0].face = mrmFace; // copy mrm data for (i = 0; i < mrm->vertCount; i++) { U16 numfu = mrmUpdates->vertexUpdates[i].numFaceUpdates; mrm->vertex[i].faceCount = numfu; // mrmUpdates->vertexUpdates[i].numFaceUpdates = (U16) numfu; mrm->vertex[i].face = mrmFace; mrm->vertex[i].newFaceCount = mrmUpdates->vertexUpdates[i].numNewFaces; mrm->vertex[i].newNormCount = mrmUpdates->vertexUpdates[i].numNewNormals; mrm->vertex[i].newTextCount = mrmUpdates->vertexUpdates[i].numNewTexCoords; for (j = 0; j < numfu; j++) { // validate mrm data FaceUpdate &fupdate = mrmUpdates->vertexUpdates[i].faceUpdates[j]; switch (fupdate.attribToken) { case VertexA: case VertexB: case VertexC: ASSERT( fupdate.value[0] < vertices.count); ASSERT( fupdate.value[1] < vertices.count); mrmFace->token = (MRM::Face::Token) fupdate.attribToken; mrmFace->index[0] = (U16) fupdate.value[0]; mrmFace->index[1] = (U16) fupdate.value[1]; mrmFace->face = (U16) fupdate.faceIndex; mrmFace++; break; case NormalA: case NormalB: case NormalC: // if (!indexed) ASSERT( fupdate.value[0] < normals.count); ASSERT( fupdate.value[1] < normals.count); mrmFace->token = (MRM::Face::Token) fupdate.attribToken; mrmFace->index[0] = (U16) fupdate.value[0]; mrmFace->index[1] = (U16) fupdate.value[1]; mrmFace->face = (U16) fupdate.faceIndex; mrmFace++; break; case TexCoord1A: case TexCoord1B: case TexCoord1C: // if (!indexed) ASSERT( fupdate.value[0] < uvs.count); ASSERT( fupdate.value[1] < uvs.count); mrmFace->token = (MRM::Face::Token) fupdate.attribToken; mrmFace->index[0] = (U16) fupdate.value[0]; mrmFace->index[1] = (U16) fupdate.value[1]; mrmFace->face = (U16) fupdate.faceIndex; mrmFace++; break; } } } // Free memory associated with the results: s_lpMRMGen->FreeMRMResults(mrmResults); // Release memory: freeIMESH( imesh); hr = s_lpMRMGen->Release(); // Shut down COM: CoUninitialize(); Setup(); SetupPlanes(); CalcBoundingSphere(); SortFaces(); return TRUE; #endif }