1

我正在尝试在 OpenGL 中绘制这种模式:

在此处输入图像描述

为此,我创建了如下模式:

vector< vector<DataPoint> > datas;
float Intensitytemp=0;
float xPos=0, yPos=0, angleInRadians=0;
for (float theta = 0.0f; theta < 4096; theta += 1.f)
{
    vector<DataPoint> temp;
    angleInRadians = 2 * M_PI*theta / 4096;
    for (float r = 0; r < 4096; r += 1.f)
    {
        xPos = cos(angleInRadians)*r / 4096;
        yPos = sin(angleInRadians)*r / 4096;
        Intensitytemp = ((float)((int)r % 256)) / 255;
        DataPoint dt;
        dt.x = xPos;
        dt.y = yPos;
        dt.Int = Intensitytemp;
        temp.push_back(dt);
    }
    datas.push_back(temp);
}

我将模式绘制为:

glBegin(GL_POINTS);
    for (int x = 0; x < 4096; x++)
        for (int y = 0; y < 4096; y++)
        {
            xPos = datas[x][y].x;
            yPos = datas[x][y].y;
            Intensitytemp = datas[x][y].Int;
            glColor4f(0.0f, Intensitytemp, 0.0f, 1.0f);
            glVertex3f(xPos, yPos, 0.0f);
        }
glEnd();

如果我在glBegin()-glEnd()块中创建数据,它的工作速度会更快。但在这两种情况下,我相信更好的方法是在 GLSL 中完成所有工作。我不太了解现代 OpenGL 背后的逻辑。

我试图创建顶点缓冲区数组和颜色数组,但无法正常工作。问题不在于将阵列转移到显卡。我在阵列中得到了堆栈溢出。这是另一个主题的问题,但在这里我想知道是否可以在完全 GLSL 代码(.ver​​t 文件中的代码)中完成此任务,而无需将这些巨大的数组传输到显卡。

4

2 回答 2

3
  1. 渲染四边形覆盖屏幕

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    GLint id;
    glUseProgram(prog_id);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    
    glBegin(GL_QUADS);
    glColor3f(1,1,1);
    glVertex2f(-1.0,-1.0);
    glVertex2f(-1.0,+1.0);
    glVertex2f(+1.0,+1.0);
    glVertex2f(+1.0,-1.0);
    glEnd();
    
    glUseProgram(0);
    glFlush();
    SwapBuffers(hdc);
    

    另请参阅有关如何使GLSL工作的完整 GL+GLSL+VAO/VBO C++ 示例(甚至是新的东西)

    不要忘记将您的 GL 视图设置为方形区域!

  2. 在顶点着色器中将顶点坐标传递给片段

    不需要矩阵...在适合片段pos的范围内。<-1.0,1.0>

    // Vertex
    varying vec2 pos;
    void main()
        {
        pos=gl_Vertex.xy;
        gl_Position=gl_Vertex;
        }
    
  3. 在片段中计算与中间的距离(0,0)并从中计算最终颜色

    // Fragment
    varying vec2 pos;
    void main()
        {
        vec4 c=vec4(0.0,0.0,0.0,1.0);
        float r=length(pos);    // radius = distance to (0,0)
        if (r<=1.0)             // inside disc?
            {
            r=16.0*r;           // your range 16=4096/256
            c.g=r-floor(r);     // use only the fractional part ... %256
            }
        gl_FragColor=c;
        }
    

    结果如下:

    示例输出

  4. GLSL 的工作原理

    您可以将片段着色器用作多边形填充的颜色计算引擎。它是这样工作的:

    GL原语通过GL调用传递给顶点着色器,该着色器负责常量的转换和预计算。每次调用 oldstyle GL都会调用顶点着色器glVertex

    如果支持的原语(由旧式 GL 设置glBegin完全通过(如 TRIANGLE、QUAD、...),则 gfx 卡开始光栅化。这是通过硬件插值器为要填充的每个“像素”调用片段着色器来完成的。由于“像素”包含更多的数据,而不仅仅是颜色,也可以被丢弃......它被称为片段。它的唯一目的是计算它所代表的屏幕上像素的目标颜色。您不能仅更改其位置的颜色。这是旧GLGLSL方法之间的最大区别。您不能仅更改对象的形状或位置,它们是如何着色/着色的,因此命名为着色器. 因此,如果您需要生成特定的图案或效果,您通常会渲染一些覆盖GL所涉及区域的图元,并通过主要在片段着色器内部的计算来重新着色。

    显然,在大多数情况下,顶点着色器不像片段着色器那样经常被调用,因此将尽可能多的计算转移到顶点着色器以提高性能。

    较新的GLSL版本也支持几何和曲面细分着色器,但那是单独的一章,现在对您来说并不重要。(你需要先习惯 Vertex/Fragment)。

[笔记]

if在这样简单的shader中并不是什么大问题。主要的速度增加只是因为你通过了单四边形而不是4096x4096点。着色器代码直接由 gfx硬件完全并行化。这就是为什么架构是这样的原因......与标准CPU/MEM架构相比,限制了着色器内部可以有效完成的某些功能。

[编辑1]

您通常可以避免if像这样聪明的数学技巧:

// Fragment
varying vec2 pos;
void main()
    {
    vec4 c=vec4(0.0,0.0,0.0,1.0);
    float r=length(pos);            // radius = distance to (0,0)
    r*=max(1.0+floor(1.0-r),0.0);   // if (r>1.0) r=0.0;
    r*=16.0;                        // your range 16=4096/256
    c.g=r-floor(r);                 // use only the fractional part ... %256
    gl_FragColor=c;
    }
于 2016-03-11T12:23:11.310 回答
0

直接回答你的问题

不,这就是着色器的工作方式。着色器重新定义了渲染管道的一部分。在古老的 OpenGL 中,管道是固定的,GPU 使用内置的着色器例程来渲染您通过glBegin/glEnd相关调用上传到它的图元。但是,对于更高版本的 OpenGL,您可以编写自定义例程供 GPU 使用。在这两种情况下您都需要发送数据以供着色器使用。

让您更好地了解如何做到这一点

首先,顶点着色器提供顶点数据。它采用顶点并一次对它们进行操作,并应用各种变换(通过将顶点乘以模型-视图-投影矩阵)。一旦它为每个顶点完成此操作,通过连接顶点形成的区域将在称为rasterization的过程中分解为坐标值(除其他外,您可以从顶点着色器传递到片段着色器)。这些坐标,每个代表屏幕上一个像素的位置,然后被发送到片段着色器,片段着色器对其进行操作以设置颜色并应用任何照明计算。

现在,由于您要绘制的是一个背后有公式的图案,您可以通过仅发送 4 个顶点来为 4096x4096 正方形着色,因为您希望产生相同的结果。

顶点着色器:

#version 150

in vec2 vertexPos;
out vec2 interpolatedVertexPos;

void main()
{
  interpolatedVertexPos = vertexPos;
}

片段着色器:

#version 1.5

in vec2 interpolatedVertexPos;
out vec4 glFragColor;

void main()
{
  const vec2 center = vec2(2048, 2048);
  float distanceFromCenter = sqrt(pow((interpolatedVertexPos.x-center.x), 2) + pow((interpolatedVertexPos.y-center.y), 2));
  if (distanceFromCenter > 2048){
    discard;
  }
  float Intensitytemp = ((float)((int)distanceFromCenter % 256)) / 255;
  glFragColor = vec4(0, Intensitytemp , 0, 1);
}

编辑:我想你可能会觉得这个答案很有帮助: OpenGL big projects, VAO-s and more

于 2016-03-11T12:32:41.360 回答