bool MiniMapMaker::outputTextures(void) { // 如果需要(纹理大小改变了或第一次输出文件时),就重建render texture if (mNeedRecreate) { destroy(); init(); } mTempOutputFileNames.clear(); static const String TEMP_GROUP_NAME = "#TEMP#"; // 创建临时的资源组 Ogre::ResourceGroupManager& rgm = Ogre::ResourceGroupManager::getSingleton(); rgm.addResourceLocation(mPath, "FileSystem", TEMP_GROUP_NAME, false); // 合并所有物体的包围盒 Ogre::AxisAlignedBox aabb; Ogre::SceneManager::MovableObjectIterator itm = mManipulator->getSceneManager()->getMovableObjectIterator(Ogre::EntityFactory::FACTORY_TYPE_NAME); while (itm.hasMoreElements()) { Ogre::MovableObject* movable = itm.getNext(); aabb.merge(movable->getWorldBoundingBox(true)); } mCamera->setFarClipDistance(mCamera->getNearClipDistance() + 2 * (aabb.getMaximum().y - aabb.getMinimum().y )); mCamera->setNearClipDistance(mTileSize/2); // 设置摄像机的高度 Real yPos = mCamera->getNearClipDistance() + aabb.getMaximum().y; TerrainData* terrainData = mManipulator->getTerrainData(); assert (terrainData); float terrainHeight = terrainData->mMaxZ - terrainData->mMinZ; float terrainWidth = terrainData->mMaxX - terrainData->mMinX; // 投影的真正面积 Real projectSize = 0.0f; // 最终切割成小块纹理的块数 int xIndex = 0; int zIndex = 0; Ogre::Vector3 originPoint(Ogre::Vector3::ZERO); if (mUseRealCameraAngle) { float outerSquareWidth = 0.0f; float outerSquareHeight = 0.0f; Ogre::Radian alphaAngle = Ogre::Math::ATan( Ogre::Math::Abs(mMoveZDir.z / mMoveZDir.x) ); switch (mCameraDirQuadrant) { case WestNorth : { float leftWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight; float rightWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth; outerSquareWidth = leftWidth + rightWidth; float topHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight; float bottomHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth; outerSquareHeight = topHeight + bottomHeight; originPoint = Ogre::Vector3(terrainData->mMinX,0,terrainData->mMinZ) + (-mMoveZDir * leftWidth); float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle); originPoint.x += (mInvertCameraDir * projectOffset ).x; originPoint.z += (mInvertCameraDir * projectOffset ).z; break; } case EastNorth : { float leftWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth; float rightWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight; outerSquareWidth = leftWidth + rightWidth; float topHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight; float bottomHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth; outerSquareHeight = topHeight + bottomHeight; originPoint = Ogre::Vector3(terrainData->mMaxX,0,terrainData->mMinZ) + (-mMoveZDir * leftWidth); float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle); originPoint.x += (mInvertCameraDir * projectOffset ).x; originPoint.z += (mInvertCameraDir * projectOffset ).z; break; } case EastSouth : { float leftWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight; float rightWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth; outerSquareWidth = leftWidth + rightWidth; float topHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth; float bottomHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight; outerSquareHeight = topHeight + bottomHeight; originPoint = Ogre::Vector3(terrainData->mMaxX,0,terrainData->mMaxZ) + (-mMoveZDir * topHeight); float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle); originPoint.x += (mInvertCameraDir * projectOffset ).x; originPoint.z += (mInvertCameraDir * projectOffset ).z; break; } case WestSouth : { float leftWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight; float rightWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth; outerSquareWidth = leftWidth + rightWidth; float topHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth; float bottomHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight; outerSquareHeight = topHeight + bottomHeight; originPoint = Ogre::Vector3(terrainData->mMinX,0,terrainData->mMaxZ) + (-mMoveZDir * rightWidth); float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle); originPoint.x += (mInvertCameraDir * projectOffset ).x; originPoint.z += (mInvertCameraDir * projectOffset ).z; break; } default: { OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, " wrong camera dir " + Ogre::StringConverter::toString(mCameraDir), "MiniMapMaker::outputTextures"); break; } } // 计算投影的长度 Real factor = Ogre::Math::Sin(mCamDirAngle); if (factor > 0.0f && factor != 1.0f) projectSize = mTileSize / factor; // 根据当前场景的大小,计算需要的分块数 xIndex = Ogre::Math::Ceil( (outerSquareWidth) / mTileSize ) + 1; zIndex = Ogre::Math::Ceil( (outerSquareHeight) / projectSize ) + 1; } else { xIndex = Ogre::Math::Ceil( (terrainData->mMaxX - terrainData->mMinX) / mTileSize ) + 1; zIndex = Ogre::Math::Ceil( (terrainData->mMaxZ - terrainData->mMinZ) / mTileSize ) + 1; originPoint.x = terrainData->mMinX; originPoint.z = terrainData->mMinZ; } // 计算最终的mini map的大小 uint miniMapWidth = xIndex * mTexWidth; uint miniMapHeight = zIndex * mTexHeight; if ( miniMapWidth > 10000 || miniMapHeight > 10000 ) { mLastErrorString = "texture size is out of range!"; return false; } // 创建mini map所需的内存空间 uchar* miniMapData = new uchar[miniMapWidth * miniMapHeight * Ogre::PixelUtil::getNumElemBytes(mOutPutFormat)]; //// 初始的摄像机位置 Real xPos = originPoint.x; Real zPos = originPoint.z; for ( int i=0; i<xIndex; ++i ) { for ( int j=0; j<zIndex; ++j ) { // 设置摄像机位置,并更新render texture的内容 mCamera->setPosition(xPos, yPos, zPos); mRenderTexture->update(); String fileName = mPath + mSceneBaseName + Ogre::StringConverter::toString(i) + "_" + Ogre::StringConverter::toString(j) + "." + mTexExtension; // 输出小纹理文件 mRenderTexture->writeContentsToFile(fileName); mTempOutputFileNames.push_back(fileName); // 读取刚创建的纹理 Ogre::Image* tempImage = new Ogre::Image; tempImage->load(mSceneBaseName + Ogre::StringConverter::toString(i) + "_" + Ogre::StringConverter::toString(j) + "." + mTexExtension, TEMP_GROUP_NAME); // 获取render texture中的内容 uchar* tempImageData = tempImage->getData(); // 定位在mini map中的左上角 uint miniMapIndex = ( j * mTexHeight * miniMapWidth + i * mTexWidth ) * Ogre::PixelUtil::getNumElemBytes(mOutPutFormat); uchar* startData = miniMapData + miniMapIndex; for ( size_t height = 0; height < tempImage->getHeight(); ++height ) { for ( size_t width = 0; width < tempImage->getWidth(); ++width ) { memcpy(startData, tempImageData, Ogre::PixelUtil::getNumElemBytes(mOutPutFormat)); startData += Ogre::PixelUtil::getNumElemBytes(mOutPutFormat); tempImageData += Ogre::PixelUtil::getNumElemBytes( tempImage->getFormat() ); } startData += (miniMapWidth - tempImage->getWidth()) * Ogre::PixelUtil::getNumElemBytes(mOutPutFormat); } delete tempImage; // 移动摄像机的z坐标 if (mUseRealCameraAngle) { zPos += (mInvertCameraDir * (projectSize)).z; xPos += (mInvertCameraDir * (projectSize)).x; } else zPos += mTileSize; } if (mUseRealCameraAngle) { xPos = originPoint.x; zPos = originPoint.z; xPos += (mMoveZDir * (mTileSize) * (i+1)).x; zPos += (mMoveZDir * (mTileSize) * (i+1)).z; } else { // 操作完每一列之后,重置摄像机的z坐标 zPos = terrainData->mMinZ; // 移动摄像机的x坐标 xPos += mTileSize; } } // 保存mini map并输出 Ogre::Image* miniMapImage = new Ogre::Image; miniMapImage->loadDynamicImage(miniMapData, miniMapWidth, miniMapHeight, 1, mOutPutFormat, true); miniMapImage->save(mPath + mOutFileName + "." + mTexExtension); delete miniMapImage; rgm.destroyResourceGroup(TEMP_GROUP_NAME); return true; }
BoundingBox<real> getOgreWorldBoundingBox() const { return mOgreObject ? fromOgre<real>(mOgreObject->getWorldBoundingBox()) : BoundingBox<real>::null(); }