Возникли проблемы с использованием круговых текстур для рисования линий АА - PullRequest
1 голос
/ 19 мая 2011

Я работаю над приложением для рисования (похожим на приложение 2d cad) в Linux, и одна из первых вещей, которые я обнаружил при работе с OpenGL, это то, что мое графическое оборудование Intel I5 Core HD GMA (встроенное) не поддерживает AA-линии или мультисэмплированные AA-методы. Итак, я провел последнюю неделю или около того, исследуя, как сделать сглаживание с помощью текстур. Я наткнулся на статью об арекусу Invariance Texture AA и довольно многое понял из нее, но проблема, с которой я столкнулся, заключается в том, что когда я использую смешанный круг, как во многих примерах, мои линии получаются очень широкими эллипсами. Это действительно смешивается, и эллипс выглядит великолепно. :) Однако, это не совсем то, что я ищу. Похоже, что текстура не «размывается» по горизонтали, а вместо этого растягивается. Я получаю эллипс, который является высотой «ширины» моей линии и эллиптической ширины примерно на 1/2 длины моей линии.

Тем временем я попробовал что-то немного другое и создал текстуру шириной 1 пиксель и высотой X пикселей. Как и ожидалось, высота и изменяющиеся значения альфа меняют результат моих линий, но на самом деле я получаю довольно хорошие результаты, за исключением очень тонких линий.

Я включаю код для небольшого тестового приложения, которое я использую (приложение GLUT), в надежде, что кто-то может указать на глупую ошибку, которую я делаю. Он использует вышеупомянутую текстуру шириной в 1 пиксель, но, очевидно, я хочу заменить ее круглой текстурой. Он не предназначен для того, чтобы быть самым эффективным кодом, но с ним легко играть, пока я не смогу все уладить.

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>

float centerX = 320.0;
float centerY = 240.0;


GLuint textureId = 0;

static GLuint createTexture(int width, int height)
{
    GLuint id;
glGenTextures( 1, &id );

glBindTexture( GL_TEXTURE_2D, id );
    int bpp = 4;  // Bytes per pixel

    GLubyte* bitmap = new GLubyte[width * height * bpp];
    for (int y = 0; y < height; y++) {
        printf("%03d: ",y);
        for (int x = 0; x < width; x++) {
            if ((y == 0) || (y == height - 1)) {
                bitmap[y * width * bpp + x + 3] = 21;
            } else if ((y == 1) || (y == height - 2)) {
                bitmap[y * width * bpp + x + 3] = 80;
            } else if ((y == 2) || (y == height - 3)) {
                bitmap[y * width * bpp + x + 3] = 166;
            } else {
                bitmap[y * width * bpp + x + 3] = 255;
            }
            printf("%03d ", bitmap[y * width * bpp + x + 3]);

            // Fill color with white so we can blend in our
            // own color when we draw the line.
            bitmap[y * width * bpp + x + 0] = 255;
            bitmap[y * width * bpp + x + 1] = 255;
            bitmap[y * width * bpp + x + 2] = 255;
        }
        printf("\n");
    }
    glTexImage2D(GL_TEXTURE_2D, 0, bpp, width, height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, bitmap);

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // Doesn't seem to make much difference for how this is currently  
    // working.
    // gluBuild2DMipmaps( GL_TEXTURE_2D, 4, width, height,
    //                    GL_RGBA, GL_UNSIGNED_BYTE, bitmap);

    delete [] bitmap;

    return id;
}

static void resize(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(0,width,height,0,1.0,-1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;

    centerX = (float)width / 2.0;
    centerY = (float)height / 2.0;

}

static void drawLine(float x0, float y0, float x1, float y1, float width)
{
    glBindTexture(GL_TEXTURE_2D, textureId);

    // Would be faster using arrays, but this is easier to tweak for now
    glBegin(GL_QUADS);
        glTexCoord2f(0.0, 0.0); glVertex2f( x0, y0);
        glTexCoord2f(0.0, 1.0); glVertex2f(x0, y0 + width);
        glTexCoord2f(1.0, 1.0); glVertex2f(x1, y1 + width);
        glTexCoord2f(1.0, 0.0); glVertex2f(x1, y1);
    glEnd();
}

static void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    for(float angle = 0.0; angle < 360.0; angle += 2.0) {
        glPushMatrix();
        glTranslatef(centerX, centerY, 0.0);
        glRotatef(angle, 0.0, 0.0, 1.0);
        glColor3f(0.0, 0.3, 0.9);
        drawLine(0.0, 0.0, centerY, 0.0, 5.0);
        glPopMatrix();
    }

    glFlush();

    glutSwapBuffers();
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Texture Antialiasing"); 

    glutReshapeFunc(resize);
    glutDisplayFunc(display);

    glClearColor(1,1,1,1);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_COLOR_MATERIAL);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    // Create a texture 1 pixel wide by 8 pixels high. This
    // texture will get stretched horizontally when we
    // draw the textured line. Ideally, we would want to use
    // a circlular texture here, but the code currently causes
    // the line to consist of a very wide ellipse with "width"
    // height and a elliptical width of about 1/2 our line length.
    textureId = createTexture(1,8);

    glutMainLoop();

    return EXIT_SUCCESS;
}

Я пробовал разные варианты вызовов glTexParameterf, например, пытался использовать GL_NEAREST для фильтров и GL_REPEAT для обтекания, но это не сработало совсем для круговых структур. Я также пытался использовать параметр GL_MODULATE, как показано в FAQ по OpenGL, для выполнения этого типа AA, но это не имело никакого значения.

Любая помощь будет высоко ценится. Благодаря.

Ответы [ 2 ]

0 голосов
/ 19 мая 2011

Основная реализация для этого состоит в том, чтобы нарисовать 1 прямоугольник (вашу линию) и 2 четырехугольника (вы строите конечности).

Вы помещаете полукруглые текстуры в квадраты, а простой прямоугольник в своем прямоугольнике.

Лучшее решение - нарисовать прямоугольник и использовать длину сегмента в качестве координаты V.

В вашем фрагментном шейдере,

  • когда V € [0,0,5], используйте обычную круглую текстуру (левая конечность)
  • когда V € [длина-0,5, длина], используйте обычную круглую текстуру, но с v-length + 1 (правильная длина)
  • else (v € [0.5, length-0.5]) используйте v = 0.5 (реальный отрезок)
0 голосов
/ 19 мая 2011

Нет необходимости использовать всю текстуру одновременно.Предположим, что у вашей текстуры круга есть вершины текс от 0 до 1.0 по оси x и по оси y.Когда вам нужен изогнутый край или круглая шапка, вы можете отобразить (0,0) (0,0,5) (0,5,0,5) (0,5,0) текстуры на вершины.Или когда вам нужна только линейная полоса, вы можете отобразить (0,5,0) (0,5,0) (0,0,5) (0,0,5) на весь прямоугольник.

...