Ogre紋理的匯出與儲存
開發過程中,有時需要瞭解紋理資料是否正確,特別是在使用render to texture或者MRT的時候,為了瞭解結果是否正確,最簡單的方式自然是把紋理資料匯出,然後以影像檔的形式儲存到本地。這裡介紹一下我在Ogre中採用的方法。
首先自然要獲得紋理對象,通常都是Ogre::Texture或者Ogre::TexturePtr對象;
紋理對象的資料由Ogre::HardwarePixelBuffer對象管理,但是真正的紋理資料儲存在其中的Ogre::PixelBox對象中;
這裡有兩點需要注意,第一是在讀取資料前要lock,讀完後unlock;第二是讀取資料是要採用Ogre::HardwarePixelBufferSharedPtr::blitToMemory函數,而不是readBuffer函數;
下面是讀取紋理資料的範例程式碼,在讀出紋理資料後,將其儲存到一個本地的24位的真彩色BMP檔案中。在儲存BMP檔案的時候,也許需要對像素資料的格式 進行轉換,這時可以利用Ogre::PixelUtil::unpackColour函數來實現,該函數可以將Ogre中像素格式的資料轉換成標準的 float格式資料。
void copyFrame(const char* pFile, Ogre::TexturePtr tex)
...{
Ogre::HardwarePixelBufferSharedPtr tmpTexBuf = tex->getBuffer();
char* tmpBuf = new char[tmpTexBuf->getSizeInBytes()];
Ogre::PixelBox tmpBox(tmpTexBuf->getWidth(),
tmpTexBuf->getHeight(),
tmpTexBuf->getDepth(),
tmpTexBuf->getFormat(),
tmpBuf);
tmpTexBuf->lock(HardwareBuffer::HBL_READ_ONLY);
tmpTexBuf->blitToMemory(tmpBox);
CBmp bmpImage;
bmpImage.PixelBoxToBMP(pFile, tmpBox);
tmpTexBuf->unlock();
}
void CBmp::PixelBoxToBMP(const char *pname, const Ogre::PixelBox& pb)
...{
m_nWidth = pb.getWidth();
m_nHeight = pb.getHeight();
m_nBitCount = 24;
m_nSizeImage = m_nWidth * m_nHeight * m_nBitCount/8;
const int nPixelCount = m_nWidth * m_nHeight;
const unsigned char *pPBData = (unsigned char *)pb.data;
GLubyte *pImage = new GLubyte[m_nSizeImage];
Ogre::uint8 r, g, b, a;
for (int i=0; i<nPixelCount; i++)
...{
Ogre::PixelUtil::unpackColour(&r, &g, &b, &a, pb.format, pPBData + i*8);
pImage[i*3] = r;
pImage[i*3+1] = g;
pImage[i*3+2] = b;
//pImage[i*3+3] = a;
}
WriteTrueColorBMP(pname, pImage);
}
void CBmp::WriteTrueColorBMP(const char *pname, unsigned char *pImage)
...{
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFOHEADER bmpInfoHeader;
bmpFileHeader.bfType = 0x4D42;
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_nSizeImage;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = m_nWidth;
bmpInfoHeader.biHeight = m_nHeight;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = m_nBitCount;
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biSizeImage = 0;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
ofstream bmpFile;
bmpFile.open(pname, ios::binary); // be careful, here must be binary written.
bmpFile.write((char*)&bmpFileHeader, sizeof(BITMAPFILEHEADER));
bmpFile.write((char*)&bmpInfoHeader, sizeof(BITMAPINFOHEADER));
bmpFile.write((char*)pImage, m_nSizeImage);
bmpFile.close();
}