使用圆形纹理绘制A线时遇到问题

时间:2011-05-19 03:27:12

标签: opengl textures antialiasing

我正在使用Linux中的绘图应用程序(类似于2d cad应用程序),我在使用OpenGL时发现的第一件事就是我的Intel I5 Core HD GMA(内置)图形硬件不支持AA线或多样本AA方法。所以,我花了大约一周时间研究如何使用纹理进行抗锯齿处理。我遇到了arekkusu Invariance Texture AA的文章,并从中获得了相当多的一点,但我遇到的问题是,当我使用混合圆时就像许多例子中那样,我的线条就像真正的宽椭圆一样。它确实正确混合,椭圆看起来很棒。 :)然而,这不是我正在寻找的。看起来纹理没有被水平“涂抹”,而是被拉伸而不是被拉伸。我最后得到一个椭圆,这个椭圆是我线条“宽度”的高度,而椭圆形宽度大约是我线条长度的1/2。

与此同时,我尝试了一些稍微不同的东西,并创建了1像素宽和X像素高的纹理。正如预期的那样,高度和变化的alpha值确实改变了我的线条的结果,但除了非常细的线条之外,我实际上得到了相当不错的结果。

我正在使用我正在使用的小型测试应用程序(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作为换行符,但这对于圆形tectures来说根本不起作用。我也尝试使用OpenGL常见问题解答中显示的GL_MODULATE设置来做这种类型的AA,但没有区别。

非常感谢任何帮助。感谢。

2 个答案:

答案 0 :(得分:0)

您不必一次使用整个纹理。让我们假设您的圆形纹理在x轴和y轴上具有从0到1.0的tex顶点。当您需要弯曲边缘或圆形盖子时,可以将(0,0)(0,0.5)(0.5,0.5)(0.5,0)纹理映射到顶点。或者当您只需要线条时,可以将(0.5,0)(0.5,0)(0,0.5)(0,0.5)映射到整个矩形。

答案 1 :(得分:0)

这个的基本实现是绘制1个矩形(你的线)和2个四边形(你的线末端)。

您将半圆纹理放在四边形中,并在矩形中放置一个简单的渐变。

更好的解决方案是绘制一个矩形,并使用段的长度作为V坐标。

在片段着色器中,

  • 当V€[0,0.5]时,使用正常的圆形纹理(左端)
  • 当V€[长度-0.5,长度]时,使用正常的圆形纹理,但v长+ 1(rightextremity)
  • else(v€[0.5,length-0.5])使用v = 0.5(实线段)