Цифровой дифференциальный анализатор с алгоритмом Ву в OpenGL

Я пытаюсь создать алгоритм, который рисует линии, используя DDA (цифровой дифференциальный анализатор), который также использует алгоритм Ву в качестве сглаживания.

Проблема в том, что результат выглядит не очень хорошо. Особенно:

  • цвет, который я выбираю, он меняет (я знаю почему, но я хочу знать, должен ли он быть таким)
  • цвет пикселя ярче - ярче

Как я могу выбрать цвет, который я хочу для линии? Учитывая, что на это влияет алгоритм?

Вот код:

void dda(int x0, int y0, int x1, int y1, int z, float red, float green, float blue) {
    float dy = y1-y0;
    float dx = x1-x0;
    float m = dy/dx;

    if (m<=1) {
        int x;
        float y;
        y = y0;
        for (x=x0; x<x1; x++) {
            pixel(x, round(y), z, frame, rfpart(red), rfpart(green), rfpart(blue));
            pixel(x, round(y)+1, z, frame, fpart(red), fpart(green), fpart(blue));
            y = y+m;
        }
    }
}

int round(float d) {
  return floor(d + 0.5);
}

float fpart(float x) {
    if (x < 0)
        return 1 - (x - floor(x));
    return x - floor(x);
}

float rfpart(float x) {
    return 1 - fpart(x);
}

2 ответа

  1. ваш код работает только для первого октанта

    так что я надеюсь, что вы тестируете только там

  2. Вы забыли смешать цвет фона и цвет линий

    поэтому добавьте прозрачность или прочитайте фоновый пиксель напрямую и смешайте цвета самостоятельно. a,a0 Коэффициенты будут альфа для прозрачности смешения цветов. В этом случае вы не должны менять r,g,b значения, но альфа только вместо этого. Также, если вы знаете цвет фона, вы можете игнорировать считывание пикселей, но результат будет немного при пересечении чего-то уже визуализированного.

Я изменяю ваш код, чтобы он был совместим с моим кодированием в C++:

void DDA_line_antialiasing(int x0,int y0,int x1,int y1,int col) // DDA antialiasing
    {
    int   x,y,dx,dy,kx,ky,f,df;
    DWORD a,a0;
    union
        {
        DWORD dd;
        BYTE db[4];
        } c,c0;
    dx=x1-x0; kx=0; if (dx>0) kx=+1; else if (dx<0) { kx=-1; dx=-dx; }
    dy=y1-y0; ky=0; if (dy>0) ky=+1; else if (dy<0) { ky=-1; dy=-dy; }
    if (dx+dy==0)
        {
        pnt(x0,y0,col);
        pnt(x1,y1,col);
        return;
        }
    if (dx>=dy)
     for (df=(dy<<8)/dx,x=x0,y=y0,f=0;;f+=df,x+=kx)
        {
        // fixed point y step
        if (f>=256) { f-=256; y+=ky; }
        // line color + background color mixing
        c.dd=col; c0.dd=pnt(x,y); a=256-f; a0=f;
        c.db[0]=DWORD(((DWORD(c.db[0])*a)+(DWORD(c0.db[0])*a0))>>8);
        c.db[1]=DWORD(((DWORD(c.db[1])*a)+(DWORD(c0.db[1])*a0))>>8);
        c.db[2]=DWORD(((DWORD(c.db[2])*a)+(DWORD(c0.db[2])*a0))>>8);
        pnt(x,y   ,c.dd);
        // line color + background color mixing
        c.dd=col; c0.dd=pnt(x,y+ky); a=f; a0=256-f;
        c.db[0]=DWORD(((DWORD(c.db[0])*a)+(DWORD(c0.db[0])*a0))>>8);
        c.db[1]=DWORD(((DWORD(c.db[1])*a)+(DWORD(c0.db[1])*a0))>>8);
        c.db[2]=DWORD(((DWORD(c.db[2])*a)+(DWORD(c0.db[2])*a0))>>8);
        pnt(x,y+ky,c.dd);
        if (x==x1) break;
        }
    else
     for (df=(dx<<8)/dy,x=x0,y=y0,f=0;;f+=df,y+=ky)
        {
        // fixed point x step
        if (f>=256) { f-=256; x+=kx; }
        // line color + background color mixing
        c.dd=col; c0.dd=pnt(x,y); a=256-f; a0=f;
        c.db[0]=DWORD(((DWORD(c.db[0])*a)+(DWORD(c0.db[0])*a0))>>8);
        c.db[1]=DWORD(((DWORD(c.db[1])*a)+(DWORD(c0.db[1])*a0))>>8);
        c.db[2]=DWORD(((DWORD(c.db[2])*a)+(DWORD(c0.db[2])*a0))>>8);
        pnt(x,y   ,c.dd);
        // line color + background color mixing
        c.dd=col; c0.dd=pnt(x+kx,y); a=f; a0=256-f;
        c.db[0]=DWORD(((DWORD(c.db[0])*a)+(DWORD(c0.db[0])*a0))>>8);
        c.db[1]=DWORD(((DWORD(c.db[1])*a)+(DWORD(c0.db[1])*a0))>>8);
        c.db[2]=DWORD(((DWORD(c.db[2])*a)+(DWORD(c0.db[2])*a0))>>8);
        pnt(x+kx,y,c.dd);
        if (y==y1) break;
        }
    }


изменено на фиксированную точку (8-битная дробная часть) f,df
изменил round в floor (мои пиксели уже сдвинуты вдвое)
добавлено смешение цветов с цветом фона
pnt(x,y,col); рисует пиксель x,y с цветом col
col=pnt(x,y); считывает пиксель с экрана / изображения в col
col это 32-битный цвет (0x00RRGGBB), что объединение есть просто r,g,b доступ

пример вывода

Вот полный исходный код, который у меня работает, с VCL (Embarcadero). Я помещаю изменения ниже, чтобы исправить проблему с длинными линиями, которые делали ошибки положения на чертеже x1,y1 (pb обнаружен путем сравнения со стандартной линией Брезенхема, MoveTo() и LineTo):

  • Измените тип переменных с «int» на «float»,
  • Приведение значения dy к int в циклах.

Также добавлены некоторые лямбда-выражения и используются типы C++ для 32 и 8 бит. Тесты скорости не проводились(doubleиногда быстрее, чемfloat).

Скорость меня устраивает, так как я работаю в растровом буфере; это необходимо сделать, потому что рисование непосредственно на компоненте слишком медленное, в отличие от рисования в памяти (pC ниже — указатель на растровое полотно). Затем все растровое изображение переносится в Paintbox. Спасибо участникам, @giogix и @Spektre.

      void aaLine(int x0, int y0, int x1, int y1, int col)
{
    auto pnt = [&](int x, int y, uint32_t c){
        pC->Pixels[x][y] = static_cast<TColor>(c);
    };//-----------------------------

    auto pix_color = [&](uint32_t x, uint32_t y){
        return pC->Pixels[x][y];
    };//-----------------------------

    float   x, y, dx, dy, kx, ky, f, df;//Changed 'int' into 'float' to avoid error on x1,y1 drawing
    uint32_t a,a0;
    union {
        uint32_t dd;
        BYTE db[4];
       } c,c0;

    auto mix_colors = [&](){
        c.db[0]= uint32_t(( uint32_t(c.db[0])*a + uint32_t(c0.db[0])*a0)>>8);
        c.db[1]= uint32_t(( uint32_t(c.db[1])*a + uint32_t(c0.db[1])*a0)>>8);
        c.db[2]= uint32_t(( uint32_t(c.db[2])*a + uint32_t(c0.db[2])*a0)>>8);
    };

    dx=x1-x0; kx=0; if (dx>0) kx=+1; else if (dx<0) { kx=-1; dx=-dx; }
    dy=y1-y0; ky=0; if (dy>0) ky=+1; else if (dy<0) { ky=-1; dy=-dy; }

    if (dx+dy==0) {
        pnt(x0,y0,col);
        pnt(x1,y1,col);
        return;
    }
    if (dx>=dy)
     for (df=(int(dy)<<8)/dx, x=x0, y=y0, f=0;  ; f+=df, x+=kx) //Put int(dy)
     {
        // fixed point y step
        if (f>=256) { f-=256; y+=ky; }
        // line color + background color mixing
        c.dd=col; c0.dd=pix_color(x,y); a=256-f; a0=f;
        mix_colors();
        pnt(x,y   ,c.dd);
        // line color + background color mixing
        c.dd=col; c0.dd=pix_color(x,y+ky); a=f; a0=256-f;
        mix_colors();
        pnt(x,y+ky,c.dd);
        if (x==x1) break;
     }
    else
     for (df=(int(dx)<<8)/dy, x=x0, y=y0, f=0;  ; f+=df, y+=ky) //Put int(dx)
     {
        // fixed point x step
        if (f>=256) { f-=256; x+=kx; }
        // line color + background color mixing
        c.dd=col; c0.dd=pix_color(x,y); a=256-f; a0=f;
        mix_colors();
        pnt(x,y   ,c.dd);
        // line color + background color mixing
        c.dd=col; c0.dd=pix_color(x+kx,y); a=f; a0=256-f;
        mix_colors();
        pnt(x+kx,y,c.dd);
        if (y==y1) break;
     }
}
Другие вопросы по тегам