我正在编写一个 2D 软件渲染器,当以某些角度旋转时,我的精灵像素会得到一种“棋盘”效果:
为了尝试获得正确的旋转,我尝试对旋转的像素进行舍入/下限/上限操作,但这并没有解决问题。
像素似乎设置到了错误的位置并且彼此重叠。不太清楚为什么会发生这种情况?我认为这可能是一个精度问题或其他问题,也许,真的不确定..
我的代码的相关部分:
uint width = image.width;
uint height = image.height;
uint originX = width / 2;
uint originY = height;
float radians = angleDegrees * PI / 180.0f;
float sine = sin(radians);
float cosine = cos(radians);
for (uint r = 0; r < height; r++)
{
for (uint p = 0; p < width; p++)
{
int translatedR = r - originY;
int translatedP = p - originX;
int rotatedR = round(translatedP * sine + translatedR * cosine) + originY;
int rotatedP = round(translatedP * cosine - translatedR * sine) + originX;
size_t index = (x + rotatedP + (frameBufferWidth * y)) + (frameBufferWidth * rotatedR);
size_t index2 = p + (image.width * r);
if (!image.pixels[index2].a)
continue;
frameBuffer[index].r = image.pixels[index2].r;
frameBuffer[index].g = image.pixels[index2].g;
frameBuffer[index].b = image.pixels[index2].b;
}
}
你的旋转算法从上到下、从左到右访问精灵上的像素,从而保证所有源像素都将被访问;对于每个像素,它计算帧缓冲区上相应像素的坐标,并将像素复制到那里。
不幸的是,这并不能保证必须在帧缓冲区上绘制的所有像素都将被绘制。
这是由于任何通过将整数乘以非整数来计算整数(像素坐标)的尝试都固有的不精确性:计算自然不会产生所有所需的目标坐标,而会产生一些目标坐标两次。
结果是,在渲染单个帧期间,帧缓冲区的某些像素未绘制,而某些像素已绘制,然后不必要地重新绘制。
所以,我恐怕会让你失望了:解决起来并不简单。
但是,只要有足够的工作(比您迄今为止所做的工作多得多),这是可能的。
粗略地说,这是您需要做的:
首先,您需要计算应用旋转后精灵的矩形如何映射到帧缓冲区上的矩形。除非旋转是 90 度的倍数,否则该帧缓冲区矩形将会倾斜。
您将逐个栅格线访问帧缓冲区矩形的像素,并在每个栅格线内逐个访问像素,如下图所示:
####
##########
###############
#####################
##########################
##########################
#####################
###############
##########
####
这保证了帧缓冲区中必须绘制的所有像素都将被绘制。
帧缓冲区上每个像素的值必须来自沿斜线访问精灵上的像素,其中线的斜率由所应用的旋转量决定。
要沿着斜线访问精灵上的像素,我建议您阅读 Bresenham 的直线算法。 (维基百科。)它比对每个像素执行多次乘法来计算每个坐标要快得多(疯狂快)。
这就是实际操作:https://www.youtube.com/watch?v=AApyC2a4KVw
这是我在 20 世纪 90 年代初用 C++ 和汇编完成的,使用 VGA 的 320x200 像素、256 色模式。