void MeshBuilder::end() { assert(!m_bIsSharedVertices && !m_currentSubMesh.strName.empty() && "You must call begin() before you call end()"); assert(!m_currentSubMesh.bUseSharedVertices || m_mesh->sharedVertexData); // Declarations std::map<unsigned short, std::vector<tElement> >::iterator iterSource, iterSourceEnd; std::vector<tVertex>::iterator iterVertex, iterVertexEnd; HardwareVertexBufferSharedPtr vbuffer; VertexData* pVertexData; // If a temporary vertex is pending, add it to the list if (m_bTempVertexPending) copyTempVertexToBuffer(); m_bFirstVertex = false; m_bAutomaticDeclaration = false; m_bIsSharedVertices = false; // Create the submesh SubMesh* pSubMesh = m_mesh->createSubMesh(m_currentSubMesh.strName); pSubMesh->setMaterialName(m_currentSubMesh.strMaterial); pSubMesh->useSharedVertices = m_currentSubMesh.bUseSharedVertices; pSubMesh->operationType = m_currentSubMesh.opType; // Initializes the vertex declaration if necessary if (!m_currentSubMesh.bUseSharedVertices) { pSubMesh->vertexData = createVertexData(); pVertexData = pSubMesh->vertexData; } else { pVertexData = m_mesh->sharedVertexData; } // Add the vertices into their buffers VertexBufferBinding::VertexBufferBindingMap bindings = pVertexData->vertexBufferBinding->getBindings(); for (iterSource = m_currentSubMesh.verticesElements.begin(), iterSourceEnd = m_currentSubMesh.verticesElements.end(); iterSource != iterSourceEnd; ++iterSource) { unsigned int vertexIndex = 0; for (iterVertex = m_currentSubMesh.vertices.begin(), iterVertexEnd = m_currentSubMesh.vertices.end(); iterVertex != iterVertexEnd; ++iterVertex) { if ((iterVertex->blendingDim > 0) && !m_mesh->getSkeletonName().empty()) { VertexBoneAssignment ass; ass.vertexIndex = vertexIndex; for (unsigned int i = 0; i < iterVertex->blendingDim; ++i) { ass.boneIndex = iterVertex->blendingIndices[i]; ass.weight = iterVertex->blendingWeights[i]; pSubMesh->addBoneAssignment(ass); } } ++vertexIndex; } } // Add the indices into their buffer pSubMesh->indexData->indexCount = m_currentSubMesh.indices.size(); pSubMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( HardwareIndexBuffer::IT_16BIT, m_currentSubMesh.indices.size(), m_currentSubMesh.indexBufferInfo.usage, m_currentSubMesh.indexBufferInfo.bUseShadowBuffer); pSubMesh->indexData->indexBuffer->writeData(0, m_currentSubMesh.indices.size() * sizeof(unsigned short), &m_currentSubMesh.indices[0]); // Update the AABB and the radius of the mesh m_mesh->_setBounds(toOgre(m_AABB)); m_mesh->_setBoundingSphereRadius(m_radius); // Reset the internal state m_currentSubMesh.strName = ""; m_currentSubMesh.strMaterial = ""; m_currentSubMesh.bUseSharedVertices = false; m_currentSubMesh.indexBufferInfo.usage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; m_currentSubMesh.indexBufferInfo.bUseShadowBuffer = false; m_currentSubMesh.verticesElements.clear(); m_currentSubMesh.vertexBufferInfos.clear(); m_currentSubMesh.vertices.clear(); m_currentSubMesh.indices.clear(); }
MeshPtr MeshMergeTool::merge(const Ogre::String& name, const Ogre::String& resourceGroupName) { print("Baking: New Mesh started", V_HIGH); MeshPtr mp = MeshManager::getSingleton().createManual(name, resourceGroupName); if (!mBaseSkeleton.isNull()) { mp->setSkeletonName(mBaseSkeleton->getName()); } AxisAlignedBox totalBounds = AxisAlignedBox(); for (std::vector<Ogre::MeshPtr>::iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) { print("Baking: adding submeshes for " + (*it)->getName(), V_HIGH); // insert all submeshes for (Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid) { SubMesh* sub = (*it)->getSubMesh(sid); const String name = findSubmeshName((*it), sid); // create submesh with correct name SubMesh* newsub; if (name.length() == 0) { newsub = mp->createSubMesh(); } else { /// @todo check if a submesh with this name has been created before newsub = mp->createSubMesh(name); } newsub->useSharedVertices = sub->useSharedVertices; // add index newsub->indexData = sub->indexData->clone(); // add geometry if (!newsub->useSharedVertices) { newsub->vertexData = sub->vertexData->clone(); if (!mBaseSkeleton.isNull()) { // build bone assignments SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); newsub->addBoneAssignment(vba); } } } newsub->setMaterialName(sub->getMaterialName()); // Add vertex animations for this submesh Animation *anim = 0; for (unsigned short i = 0; i < (*it)->getNumAnimations(); ++i) { anim = (*it)->getAnimation(i); // get or create the animation for the new mesh Animation *newanim; if (mp->hasAnimation(anim->getName())) { newanim = mp->getAnimation(anim->getName()); } else { newanim = mp->createAnimation(anim->getName(), anim->getLength()); } print("Baking: adding vertex animation " + anim->getName() + " for " + (*it)->getName(), V_HIGH); Animation::VertexTrackIterator vti=anim->getVertexTrackIterator(); while (vti.hasMoreElements()) { VertexAnimationTrack *vt = vti.getNext(); // handle=0 targets the main mesh, handle i (where i>0) targets submesh i-1. // In this case there are only submeshes so index 0 will not be used. unsigned short handle = mp->getNumSubMeshes(); VertexAnimationTrack* newvt = newanim->createVertexTrack( handle, vt->getAssociatedVertexData()->clone(), vt->getAnimationType()); for (int keyFrameIndex = 0; keyFrameIndex < vt->getNumKeyFrames(); ++keyFrameIndex) { switch (vt->getAnimationType()) { case VAT_MORPH: { // copy the keyframe vertex buffer VertexMorphKeyFrame *kf = vt->getVertexMorphKeyFrame(keyFrameIndex); VertexMorphKeyFrame *newkf = newvt->createVertexMorphKeyFrame(kf->getTime()); // This creates a ref to the buffer in the original model // so don't delete it until the export is completed. newkf->setVertexBuffer(kf->getVertexBuffer()); break; } case VAT_POSE: { /// @todo implement pose amination merge break; } case VAT_NONE: default: { break; } } } } } print("Baking: adding submesh '" + name + "' with material " + sub->getMaterialName(), V_HIGH); } // sharedvertices if ((*it)->sharedVertexData) { /// @todo merge with existing sharedVertexData if (!mp->sharedVertexData) { mp->sharedVertexData = (*it)->sharedVertexData->clone(); } if (!mBaseSkeleton.isNull()) { Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); mp->addBoneAssignment(vba); } } } print("Baking: adding bounds for " + (*it)->getName(), V_HIGH); // add bounds totalBounds.merge((*it)->getBounds()); } mp->_setBounds(totalBounds); /// @todo merge submeshes with same material /// @todo add parameters mp->buildEdgeList(); print("Baking: Finished", V_HIGH); reset(); return mp; }
MeshPtr MergeMesh::bake() { log( "Baking: New Mesh started" ); MeshPtr mp = MeshManager::getSingleton(). createManual( "mergedMesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); mp->setSkeletonName( m_BaseSkeleton->getName() ); AxisAlignedBox totalBounds = AxisAlignedBox(); for( std::vector< Ogre::MeshPtr >::iterator it = m_Meshes.begin(); it != m_Meshes.end(); ++it ) { log( "Baking: adding submeshes for " + (*it)->getName() ); // insert all submeshes for( Ogre::ushort sid = 0; sid < (*it)->getNumSubMeshes(); ++sid ) { SubMesh* sub = (*it)->getSubMesh( sid ); const String name = findSubmeshName( (*it), sid ); // create submesh with correct name SubMesh* newsub; if( name.length() == 0 ) newsub = mp->createSubMesh( ); else /// @todo check if a submesh with this name has been created before newsub = mp->createSubMesh( name ); newsub->useSharedVertices = sub->useSharedVertices; // add index newsub->indexData = sub->indexData->clone(); // add geometry if( !newsub->useSharedVertices ) { newsub->vertexData = sub->vertexData->clone(); // build bone assignments SubMesh::BoneAssignmentIterator bit = sub->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); newsub->addBoneAssignment(vba); } } newsub->setMaterialName( sub->getMaterialName() ); log("Baking: adding submesh '" + name + "' with material " + sub->getMaterialName()); } // sharedvertices if ((*it)->sharedVertexData) { /// @todo merge with existing sharedVertexData if (!mp->sharedVertexData) { mp->sharedVertexData = (*it)->sharedVertexData->clone(); } Mesh::BoneAssignmentIterator bit = (*it)->getBoneAssignmentIterator(); while (bit.hasMoreElements()) { VertexBoneAssignment vba = bit.getNext(); mp->addBoneAssignment(vba); } } log("Baking: adding bounds for " + (*it)->getName()); // add bounds totalBounds.merge((*it)->getBounds()); } mp->_setBounds( totalBounds ); /// @todo merge submeshes with same material /// @todo add parameters mp->buildEdgeList(); log( "Baking: Finished" ); return mp; }
//----------------------------------------------------------------------- void InstanceManager::unshareVertices(const Ogre::MeshPtr &mesh) { // Retrieve data to copy bone assignments const Mesh::VertexBoneAssignmentList& boneAssignments = mesh->getBoneAssignments(); Mesh::VertexBoneAssignmentList::const_iterator it = boneAssignments.begin(); Mesh::VertexBoneAssignmentList::const_iterator end = boneAssignments.end(); size_t curVertexOffset = 0; // Access shared vertices VertexData* sharedVertexData = mesh->sharedVertexData; for (size_t subMeshIdx = 0; subMeshIdx < mesh->getNumSubMeshes(); subMeshIdx++) { SubMesh *subMesh = mesh->getSubMesh(subMeshIdx); IndexData *indexData = subMesh->indexData; HardwareIndexBuffer::IndexType idxType = indexData->indexBuffer->getType(); IndicesMap indicesMap = (idxType == HardwareIndexBuffer::IT_16BIT) ? getUsedIndices<uint16>(indexData) : getUsedIndices<uint32>(indexData); VertexData *newVertexData = new VertexData(); newVertexData->vertexCount = indicesMap.size(); newVertexData->vertexDeclaration = sharedVertexData->vertexDeclaration->clone(); for (size_t bufIdx = 0; bufIdx < sharedVertexData->vertexBufferBinding->getBufferCount(); bufIdx++) { HardwareVertexBufferSharedPtr sharedVertexBuffer = sharedVertexData->vertexBufferBinding->getBuffer(bufIdx); size_t vertexSize = sharedVertexBuffer->getVertexSize(); HardwareVertexBufferSharedPtr newVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer (vertexSize, newVertexData->vertexCount, sharedVertexBuffer->getUsage(), sharedVertexBuffer->hasShadowBuffer()); uint8 *oldLock = (uint8*)sharedVertexBuffer->lock(0, sharedVertexData->vertexCount * vertexSize, HardwareBuffer::HBL_READ_ONLY); uint8 *newLock = (uint8*)newVertexBuffer->lock(0, newVertexData->vertexCount * vertexSize, HardwareBuffer::HBL_NORMAL); IndicesMap::iterator indIt = indicesMap.begin(); IndicesMap::iterator endIndIt = indicesMap.end(); for (; indIt != endIndIt; ++indIt) { memcpy(newLock + vertexSize * indIt->second, oldLock + vertexSize * indIt->first, vertexSize); } sharedVertexBuffer->unlock(); newVertexBuffer->unlock(); newVertexData->vertexBufferBinding->setBinding(bufIdx, newVertexBuffer); } if (idxType == HardwareIndexBuffer::IT_16BIT) { copyIndexBuffer<uint16>(indexData, indicesMap); } else { copyIndexBuffer<uint32>(indexData, indicesMap); } // Store new attributes subMesh->useSharedVertices = false; subMesh->vertexData = newVertexData; // Transfer bone assignments to the submesh size_t offset = curVertexOffset + newVertexData->vertexCount; for (; it != end; ++it) { size_t vertexIdx = (*it).first; if (vertexIdx > offset) break; VertexBoneAssignment boneAssignment = (*it).second; boneAssignment.vertexIndex = static_cast<unsigned int>(boneAssignment.vertexIndex - curVertexOffset); subMesh->addBoneAssignment(boneAssignment); } curVertexOffset = newVertexData->vertexCount + 1; } // Release shared vertex data delete mesh->sharedVertexData; mesh->sharedVertexData = NULL; mesh->clearBoneAssignments(); }
//--------------------------------------------------------------------- void OptimiseTool::processMesh(Ogre::MeshPtr mesh) { bool rebuildEdgeList = false; // Shared geometry if (mesh->sharedVertexData) { print("Optimising mesh shared vertex data..."); setTargetVertexData(mesh->sharedVertexData); for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i) { SubMesh* sm = mesh->getSubMesh(i); if (sm->useSharedVertices) { addIndexData(sm->indexData); } } if (optimiseGeometry()) { if (mesh->getSkeletonName() != StringUtil::BLANK) { print(" fixing bone assignments..."); Mesh::BoneAssignmentIterator currentIt = mesh->getBoneAssignmentIterator(); Mesh::VertexBoneAssignmentList newList = getAdjustedBoneAssignments(currentIt); mesh->clearBoneAssignments(); for (Mesh::VertexBoneAssignmentList::iterator bi = newList.begin(); bi != newList.end(); ++bi) { mesh->addBoneAssignment(bi->second); } } for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i) { SubMesh* sm = mesh->getSubMesh(i); if (mesh->getSkeletonName() != StringUtil::BLANK) { print(" fixing bone assignments..."); Mesh::BoneAssignmentIterator currentIt = sm->getBoneAssignmentIterator(); Mesh::VertexBoneAssignmentList newList = getAdjustedBoneAssignments(currentIt); sm->clearBoneAssignments(); for (Mesh::VertexBoneAssignmentList::iterator bi = newList.begin(); bi != newList.end(); ++bi) { sm->addBoneAssignment(bi->second); } } if (sm->useSharedVertices) { fixLOD(sm->mLodFaceList); } } rebuildEdgeList = true; } } // Dedicated geometry for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i) { SubMesh* sm = mesh->getSubMesh(i); if (!sm->useSharedVertices) { print("Optimising submesh " + StringConverter::toString(i) + " dedicated vertex data "); setTargetVertexData(sm->vertexData); addIndexData(sm->indexData); if (optimiseGeometry()) { if (mesh->getSkeletonName() != StringUtil::BLANK) { print(" fixing bone assignments..."); Mesh::BoneAssignmentIterator currentIt = sm->getBoneAssignmentIterator(); Mesh::VertexBoneAssignmentList newList = getAdjustedBoneAssignments(currentIt); sm->clearBoneAssignments(); for (Mesh::VertexBoneAssignmentList::iterator bi = newList.begin(); bi != newList.end(); ++bi) { sm->addBoneAssignment(bi->second); } } fixLOD(sm->mLodFaceList); rebuildEdgeList = true; } } } if (rebuildEdgeList && mesh->isEdgeListBuilt()) { // force rebuild of edge list mesh->freeEdgeList(); mesh->buildEdgeList(); } }
// Convert Nif::NiTriShape to Ogre::SubMesh, attached to the given // mesh. void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std::list<VertexBoneAssignment> &vertexBoneAssignments) { // cout << "s:" << shape << "\n"; NiTriShapeData *data = shape->data.getPtr(); SubMesh *sub = mesh->createSubMesh(shape->name.toString()); int nextBuf = 0; // This function is just one long stream of Ogre-barf, but it works // great. // Add vertices int numVerts = data->vertices.length / 3; sub->vertexData = new VertexData(); sub->vertexData->vertexCount = numVerts; sub->useSharedVertices = false; VertexDeclaration *decl = sub->vertexData->vertexDeclaration; decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_FLOAT3), numVerts, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false); if(flip) { float *datamod = new float[data->vertices.length]; //std::cout << "Shape" << shape->name.toString() << "\n"; for(int i = 0; i < numVerts; i++) { int index = i * 3; const float *pos = data->vertices.ptr + index; Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2)); original = mTransform * original; mBoundingBox.merge(original); datamod[index] = original.x; datamod[index+1] = original.y; datamod[index+2] = original.z; } vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); delete [] datamod; } else { vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, false); } VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; bind->setBinding(nextBuf++, vbuf); if (data->normals.length) { decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL); vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_FLOAT3), numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); if(flip) { Quaternion rotation = mTransform.extractQuaternion(); rotation.normalise(); float *datamod = new float[data->normals.length]; for(int i = 0; i < numVerts; i++) { int index = i * 3; const float *pos = data->normals.ptr + index; Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2)); original = rotation * original; if (mNormaliseNormals) { original.normalise(); } datamod[index] = original.x; datamod[index+1] = original.y; datamod[index+2] = original.z; } vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); delete [] datamod; } else { vbuf->writeData(0, vbuf->getSizeInBytes(), data->normals.ptr, false); } bind->setBinding(nextBuf++, vbuf); } // Vertex colors if (data->colors.length) { const float *colors = data->colors.ptr; RenderSystem* rs = Root::getSingleton().getRenderSystem(); std::vector<RGBA> colorsRGB(numVerts); RGBA *pColour = &colorsRGB.front(); for (int i=0; i<numVerts; i++) { rs->convertColourValue(ColourValue(colors[0],colors[1],colors[2], colors[3]),pColour++); colors += 4; } decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE); vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_COLOUR), numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB.front(), true); bind->setBinding(nextBuf++, vbuf); } if (data->uvlist.length) { decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_FLOAT2), numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY,false); if(flip) { float *datamod = new float[data->uvlist.length]; for(unsigned int i = 0; i < data->uvlist.length; i+=2){ float x = *(data->uvlist.ptr + i); float y = *(data->uvlist.ptr + i + 1); datamod[i] =x; datamod[i + 1] =y; } vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); delete [] datamod; } else vbuf->writeData(0, vbuf->getSizeInBytes(), data->uvlist.ptr, false); bind->setBinding(nextBuf++, vbuf); } // Triangle faces - The total number of triangle points int numFaces = data->triangles.length; if (numFaces) { sub->indexData->indexCount = numFaces; sub->indexData->indexStart = 0; HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). createIndexBuffer(HardwareIndexBuffer::IT_16BIT, numFaces, HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); if(flip && mFlipVertexWinding && sub->indexData->indexCount % 3 == 0){ sub->indexData->indexBuffer = ibuf; uint16 *datamod = new uint16[numFaces]; int index = 0; for (size_t i = 0; i < sub->indexData->indexCount; i+=3) { const short *pos = data->triangles.ptr + index; uint16 i0 = (uint16) *(pos+0); uint16 i1 = (uint16) *(pos+1); uint16 i2 = (uint16) *(pos+2); //std::cout << "i0: " << i0 << "i1: " << i1 << "i2: " << i2 << "\n"; datamod[index] = i2; datamod[index+1] = i1; datamod[index+2] = i0; index += 3; } ibuf->writeData(0, ibuf->getSizeInBytes(), datamod, false); delete [] datamod; } else ibuf->writeData(0, ibuf->getSizeInBytes(), data->triangles.ptr, false); sub->indexData->indexBuffer = ibuf; } // Set material if one was given if (!material.empty()) sub->setMaterialName(material); //add vertex bone assignments for (std::list<VertexBoneAssignment>::iterator it = vertexBoneAssignments.begin(); it != vertexBoneAssignments.end(); it++) { sub->addBoneAssignment(*it); } if(mSkel.isNull()) needBoneAssignments.push_back(sub); }