在软件渲染器中旋转精灵时出现“棋盘”效果?

问题描述 投票:0回答:1

我正在编写一个 2D 软件渲染器,当以某些角度旋转时,我的精灵像素会得到一种“棋盘”效果:

rotation issue

为了尝试获得正确的旋转,我尝试对旋转的像素进行舍入/下限/上限操作,但这并没有解决问题。

像素似乎设置到了错误的位置并且彼此重叠。不太清楚为什么会发生这种情况?我认为这可能是一个精度问题或其他问题,也许,真的不确定..

我的代码的相关部分:

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;
    }
}
c++ 2d rendering framebuffer image-rotation
1个回答
0
投票

你的旋转算法从上到下、从左到右访问精灵上的像素,从而保证所有源像素都将被访问;对于每个像素,它计算帧缓冲区上相应像素的坐标,并将像素复制到那里。

不幸的是,这并不能保证必须在帧缓冲区上绘制的所有像素都将被绘制。

这是由于任何通过将整数乘以非整数来计算整数(像素坐标)的尝试都固有的不精确性:计算自然不会产生所有所需的目标坐标,而会产生一些目标坐标两次。

结果是,在渲染单个帧期间,帧缓冲区的某些像素未绘制,而某些像素已绘制,然后不必要地重新绘制。

所以,我恐怕会让你失望了:解决起来并不简单。

但是,只要有足够的工作(比您迄今为止所做的工作多得多),这是可能的。

粗略地说,这是您需要做的:

首先,您需要计算应用旋转后精灵的矩形如何映射到帧缓冲区上的矩形。除非旋转是 90 度的倍数,否则该帧缓冲区矩形将会倾斜。

您将逐个栅格线访问帧缓冲区矩形的像素,并在每个栅格线内逐个访问像素,如下图所示:

                      ####
                     ##########
                     ###############
                    #####################
                    ##########################
                   ##########################
                        #####################
                             ###############
                                  ##########
                                       ####

这保证了帧缓冲区中必须绘制的所有像素都将被绘制。

帧缓冲区上每个像素的值必须来自沿斜线访问精灵上的像素,其中线的斜率由所应用的旋转量决定。

要沿着斜线访问精灵上的像素,我建议您阅读 Bresenham 的直线算法。 (维基百科。)它比对每个像素执行多次乘法来计算每个坐标要快得多(疯狂快)。

这就是实际操作:https://www.youtube.com/watch?v=AApyC2a4KVw

这是我在 20 世纪 90 年代初用 C++ 和汇编完成的,使用 VGA 的 320x200 像素、256 色模式。

© www.soinside.com 2019 - 2024. All rights reserved.