Я использую SDL2 версии 2.28.3 в Windows 11, проблема возникает на всех серверах (DirectX, opengl, программное обеспечение), я получаю разные результаты, когда рисую напрямую на экране, по сравнению с первым рисованием на текстуре.
Я написал следующий алгоритм сглаженного круга, сам алгоритм не важен, за исключением того, что он использует альфа-смешение, поэтому я подозреваю, что с этим есть проблема. Проблема также исчезает, когда я отключаю альфа-смешение и просто окрашиваю фон в белый цвет. , но для практического использования необходимо альфа-смешение.
звонок SDL_SetTextureBlendMode(stored_arc_texture, SDL_BLENDMODE_BLEND)
и SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND)
не помог.
#include <SDL2/SDL.h>
#include <array>
void DrawFilledArcAA3(SDL_Renderer* renderer, SDL_Point midpoint, int radius, const SDL_Color color)
{
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
int y = 0;
int max_y = radius + 1;
int raidus_squared = radius * radius;
while (y <= max_y)
{
double x = sqrt(raidus_squared - y * y);
{
int max_x = static_cast<int>(floor(x));
if (floor(x) + 2 < y)
{
break;
}
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
std::array<SDL_Point, 4> points{
SDL_Point{midpoint.x, midpoint.y + y}, SDL_Point{midpoint.x + max_x, midpoint.y + y},
SDL_Point{midpoint.x + y, midpoint.y}, SDL_Point{midpoint.x + y, midpoint.y + max_x},
};
SDL_RenderDrawLines(renderer, points.data(), points.size());
}
{
double overflow = x - floor(x);
int color_value = 255 * overflow;
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color_value);
int max_x = static_cast<int>(floor(x + 1));
std::array<SDL_Point, 2> points{
SDL_Point{midpoint.x + max_x, midpoint.y + y},
SDL_Point{midpoint.x + y, midpoint.y + max_x},
};
SDL_RenderDrawPoints(renderer, points.data(), points.size());
}
y++;
}
}
int main(int argc, char** argv)
{
SDL_Window* pWindow = NULL;
pWindow = SDL_CreateWindow("test AA circle", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
SDL_Renderer* renderer = SDL_CreateRenderer(pWindow, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
bool is_running = true;
while (is_running)
{
SDL_Event e;
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
{
is_running = false;
break;
}
}
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
{
// render directly to screen
DrawFilledArcAA3(renderer, SDL_Point{ 10,4 }, 100, SDL_Color{ 180,180,180,255 });
}
// render to texture first
{
int stored_radius = 100;
SDL_Texture* old_texture = SDL_GetRenderTarget(renderer);
SDL_Texture* stored_arc_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, stored_radius, stored_radius);
SDL_SetRenderTarget(renderer, stored_arc_texture);
SDL_SetTextureBlendMode(stored_arc_texture, SDL_BLENDMODE_BLEND);
DrawFilledArcAA3(renderer, { 0,0 }, stored_radius, SDL_Color{ 180,180,180,255 });
SDL_SetRenderTarget(renderer, old_texture);
SDL_Rect dst{ 120 + 10, 4, stored_radius, stored_radius};
SDL_RenderCopy(renderer, stored_arc_texture, 0, &dst);
SDL_DestroyTexture(stored_arc_texture);
}
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(pWindow);
SDL_Quit();
return 0;
}
Как это исправить, чтобы оба выглядели одинаково?
Проблема была решена, я в основном использовал Renderdoc для отладки и нашел проблему.
при рисовании непосредственно на экран с альфа-смешением SDL_BLENDMODE_BLEND
я перехожу от смешивания пикселя (1.0, 1.0, 1.0, 1.0)
к (0.7, 0.7, 0.7, 0.5)
, в результате получается пиксель (0.85, 0.85, 0.85, 1)
, что правильно для случая, когда я рисую прямо на экране.
но когда я рисую текстуру, которая начинается с (0.0, 0.0, 0.0, 0.0)
, и смешиваю ее с (0.7, 0.7, 0.7, 0.5)
, в результате получается пиксель с (0.35, 0.35, 0.35, 0.5)
.... который снова смешивается с (1.0, 1.0, 1.0, 1.0)
, что приводит к чему-то близкому к (0.7, 0.7, 0.7, 1)
, что неверно.
Исправление простое: отключить альфа-смешение при рисовании текстуры. пусть альфа-смешивание происходит только при отрисовке текстуры на экране при окончательном смешивании, т. е.: альфа-смешение происходит только один раз, а не дважды.
поэтому удаление SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND)
из версии, которая рисует текстуру, устраняет эту проблему, короче говоря, вы не можете использовать один и тот же код для обеих версий и ожидать, что они будут выглядеть одинаково, вам нужно спланировать, когда произойдет смешивание при рисовании. к текстуре.