在GLSL中获取旧式OpenGL代码

时间:2016-03-11 11:02:42

标签: c++ opengl glsl vertex-shader vertex-array-object

我试图在OpenGL中绘制这个模式:

enter image description here

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

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代码(那些在.vert文件中)中完成此任务而无需将这些巨大的数组转移到图形卡。

2 个答案:

答案 0 :(得分:2)

  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);
    

    另请参阅See complete GL+GLSL+VAO/VBO C++ example了解如何让 GLSL 正常工作(即使是新的东西)

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

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

    不需要矩阵...... pos<-1.0,1.0>范围内,这对片段来说很合适。

    // Vertex
    varying vec2 pos;
    void main()
        {
        pos=gl_Vertex.xy;
        gl_Position=gl_Vertex;
        }
    
  4. 片段计算距中间(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;
        }
    

    结果如下:

    example output

  5. GLSL如何运作

    您可以将片段着色器作为多边形填充的颜色计算引擎来处理。它的工作原理如下:

    GL 原语由 GL 调用传递给顶点着色器,后者负责常量的转换和预计算。来自oldstyle GL 的每个glVertex来电都会调用顶点着色器

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

    显然,顶点着色器在大多数情况下不会像片段着色器那样频繁调用,因此尽可能多地将计算移动到顶点着色器< / strong>提高绩效。

    较新的 GLSL 版本也支持几何体和 tesselation着色器,但这本身就是一章,现在对您来说并不重要。 (你需要先习惯Vertex / Fragment)。

  6. <强> [注释]

    这种简单着色器中的单if不是一个大问题。主要的速度增加只是你传递单个四边形而不是4096x4096点。 Shader代码直接由gfx HW 完全并行化。这就是为什么架构是如何...限制在着色器内部可以有效完成的一些功能,而不是标准的 CPU / MEM 架构。

    <强> [EDIT1]

    你可以经常通过这样聪明的数学技巧来避免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;
        }
    

答案 1 :(得分: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