【问题标题】:Having problems using circular textures to draw AA lines使用圆形纹理绘制 A 线时遇到问题
【发布时间】:2011-05-19 03:27:11
【问题描述】:

我正在 Linux 中开发一个绘图应用程序(类似于 2d cad 应用程序),我在使用 OpenGL 时发现的第一件事是我的 Intel I5 Core HD GMA(内置)图形硬件不支持AA 线或 Multisample 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 用于包装,但这对于圆形结构来说根本不起作用。我也尝试使用 OpenGL 常见问题解答中所示的 GL_MODULATE 设置来执行这种类型的 AA,但这没有任何区别。

任何帮助将不胜感激。谢谢。

【问题讨论】:

    标签: opengl textures antialiasing


    【解决方案1】:

    您不必一次使用整个纹理。让我们假设您的圆形纹理在 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) 映射到整个矩形。

    【讨论】:

    • 这确实是我的问题的关键。不幸的是,在我看到的例子中,没有一个真正显示实际渲染部分的细节,只是粗略地提到了如何做到这一点。一旦我将圆圈的中心“拉伸”到线的非大写长度,效果就很好。
    【解决方案2】:

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

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

    更好的办法是画一个矩形,用线段的长度作为你的V坐标。

    在您的片段着色器中,

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

    【讨论】:

    • 有一段时间,我使用渐变来解决这个问题。具体来说,我将渲染线的“中心”部分,然后在每个边缘上渲染渐变,逐渐减小到 0 alpha。这产生了一些好的结果,但奇怪的是它似乎比使用纹理选项慢。这是你所期望的吗?我对此感到相当惊讶。这种方法似乎确实在较细的线条上做得更好,所以我可能会使用混合方法。
    • 如果我理解正确,您正在为线本身渲染 3 个四边形(=6 个三角形),不包括四肢?如果是这样,是的,它比只有 2 个三角形慢,即使有纹理。贴图很便宜,而且贴图这么小,几乎是免费的。
    • 没错,两条细(即:1 到 2 像素)的边缘在线条的每一侧,然后是线条的中间。通过使用这里的建议,我的工作效果很好,除了让细线(
    • 刚刚意识到我没有指出我当前的代码使用的是纹理着色算法而不是简单的 alpha 混合四边形。就性能而言,这似乎是最佳选择,但我需要找到细线的解决方案,因为我的应用程序将主要使用细线。
    • 尝试将纹理的 rgb 分量乘以 a 分量。这被称为“预乘 alpha”。如果你想让 alpha 根据深度/宽度变化,这在着色器中也是可能的。
    猜你喜欢
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    相关资源
    最近更新 更多