我想写一个.bmp文件的法线贴图,所以我先实现了一个简单的.bmp编写器:
void BITMAPLOADER::writeHeader(std::ofstream& out, int width, int height)
{
BITMAPFILEHEADER tWBFH;
tWBFH.bfType = 0x4d42;
tWBFH.bfSize = 14 + 40 + (width*height*3);
tWBFH.bfReserved1 = 0;
tWBFH.bfReserved2 = 0;
tWBFH.bfOffBits = 14 + 40;
BITMAPINFOHEADER tW2BH;
memset(&tW2BH,0,40);
tW2BH.biSize = 40;
tW2BH.biWidth = width;
tW2BH.biHeight = height;
tW2BH.biPlanes = 1;
tW2BH.biBitCount = 24;
tW2BH.biCompression = 0;
out.write((char*)(&tWBFH),14);
out.write((char*)(&tW2BH),40);
}
bool TERRAINLOADER::makeNormalmap(unsigned int width, unsigned int height)
{
std::ofstream file;
file.open("terrainnormal.bmp");
if(!file)
{
file.close();
return false;
}
bitmaploader.writeHeader(file,width,height);
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
file << static_cast<unsigned char>(255*x/height); //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
file << static_cast<unsigned char>(0); //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
file << static_cast<unsigned char>(0); //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
};
};
file.close();
return true;
};
writeHeader(...)
函数来自SO,来自已解决的工作帖子。 (我已经忘记了它的名字)
getHeight(...)
使用双三次插值,因此我可以将其写入大分辨率图像,并保持平滑。它也将用于碰撞检测,现在用作剪贴图的LOD因子。
现在问题是这会输出扭曲的图像。这些图片将告诉我的一切:
预期/失真的结果:
file << static_cast<unsigned char>(255*(float)x/height)
应该是从黑到白的简单混合。
我使用的图像大小为256 x 256,因为我读过它应该是4的倍数。我可以使用库,但是我想在没有库的情况下解决这个问题。是什么导致了这种失真?
修改 在最后一张图片上,有些线条也是彩色的,但它们不应该是。这篇文章很相似,但我的高度图并没有像这篇帖子那样线性扭曲:Image Distortion with Lock Bits
修改 另一个奇怪的问题是,当我不能使所有颜色相同时,颜色也会变形。例如,将RED设置为高度,并留下G和B 0,它不仅变成了RED,而且变成了嘈杂的彩色高度图。
编辑/评论/ 如果我理解正确,那么标题的大小就是我的像素数据。在像素数据之前,必须有 4 * n 字节。所以填充意味着在标题之后我添加了更多填充该位置的数据。
例如假设(我会看起来很热得到它)我的标题是55个字节,然后我应该再添加1个字节,因为55 + 1 = 56和4 | 56。
所以
file << static_cast<unsigned char>('a');
for(int y = 1; y <= width; y++)
{
for(int x = 1; x <= height; x++)
{
file << static_cast<unsigned char>(x);
file << static_cast<unsigned char>(x);
file << static_cast<unsigned char>(x);
};
};
应该是正确的。
但我意识到了真正的问题(正如Jigsore评论的那样)。当我从int
投射到char
时,似乎 1位数字变为1字节,2位数字变为2,3位数字变为3字节。 将高度限制为3位数效果很好,但图像有些白皙,因为“最暗”。颜色变为(100,100,100)而不是(0,0,0)。此外,这也是非常规失真的原因,因为它取决于多少山丘和#39;或者&#39; mountains&#39;有一排。我怎么能解决这个问题,我希望最后一个问题呢?我不想将图像压缩到100-256范围。;)
答案 0 :(得分:1)
以二进制模式打开文件。
在Windows下,如果您以默认文本模式打开文件,它将在每次写出0x0d
(换行)后写入额外的0x0a
(返回)字符。第一次发生这种情况时,它将改变以下像素的颜色,因为RGB顺序不对齐。在它发生3次之后你会被一个完整的像素关闭。