【问题标题】:Drawing multiple objects with shaders (GLEW)使用着色器绘制多个对象 (GLEW)
【发布时间】:2021-01-01 17:57:34
【问题描述】:

我想用三角扇绘制不同的图形,但我不知道如何让程序绘制第二个图形。每次我想更改颜色或绘制新图形时,是否需要第二个 vertexShaderSource 和第二个 fragmentShaderSource?

代码如下:

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

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n""void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);\n" // To set the color.
"}\n\0";

// Set of vertices for the different figures that make up the drawing.
float vertices[] = {
    -0.8f, 0.6f, 0.0f, // Center.
    -0.8f, 0.4f, 0.0f,
    -0.83f, 0.44f, 0.0f,
    -0.87f, 0.51f, 0.0f,
    -0.9f, 0.57f, 0.0f,
    -0.93f, 0.63f, 0.0f,
    -0.95f, 0.69f, 0.0f,
    -0.97f, 0.75f, 0.0f,
    -0.98f, 0.8f, 0.0f,
    -0.91f, 0.8f, 0.0f,
    -0.85f, 0.79f, 0.0f,
    -0.8f, 0.77f, 0.0f,
};

unsigned int VBO, VAO;
GLuint vertexShader;
GLuint fragmentShader;
GLuint shaderProgram;

void display(void){
    // Background color.
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 12);
    glBindVertexArray(0);
    glFlush();
}

// Main.
int main(int argc, char** argv){
    glutInit(&argc, argv);
    // Color mode.
    glutInitDisplayMode(GLUT_RGBA);
    // Window size.
    glutInitWindowSize(500, 500);
    // Title.
    glutCreateWindow("Tarea 3: Figura con curvas");
    GLenum err = glewInit();
    if(err!=GLEW_OK) {
        printf("glewInit failed: %s",glewGetErrorString(err));   
    exit(1);  
    } 

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    glutDisplayFunc(display);
    glutMainLoop();
}

【问题讨论】:

  • “我是否需要第二个 vertexShaderSource 和第二个 fragmentShaderSource [...]” - 不需要。您需要的只是不同的 VAOVBO。见Vertex Specification

标签: c++ opengl glut glew vao


【解决方案1】:

没有必要(或推荐)为网格使用不同的着色器。如果要绘制多个物体,那么可以把网格的顶点属性分开Vertex Buffer Objects:

GLuint VBOs[2];
glGenBuffers(2, VBOs);

glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices_1, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices_2, GL_STATIC_DRAW);

为每个网格指定一个Vertex Array Object

GLuint VAOs[2];
glGenVertexArrays(2, VAOs);

glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

在draw call之前绑定VAO:

glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 12);

glBindVertexArray(VAOs[1]);
glDrawArrays(...);

当然,也可以将不同网格的所有顶点属性连续放入一个 VBO 的数据存储中。如果顶点规格相同,则可以使用单个 VAO。


可以通过顶点着色器中的顶点变换来实现不同网格的不同位置。使用mat4 类型的Uniform 来变换网格的顶点:

#version 330 core

layout (location = 0) in vec3 aPos;

uniform mat4 u_model;

void main()
{
    gl_Position = u_model * vec4(aPos.xyz, 1.0);
}

进一步查看LearnOpenGL - Transformations


如果两个图形相同,只是位置不同,那么可以画两次同一个网格,但是要改模型变换u_model

【讨论】:

    【解决方案2】:

    您正在寻找Uniform buffer objects

    如果整个绘制调用只有一个值,那么应该对着色器进行参数化。您首先要参数化的显而易见的事情是片段着色器中的颜色,然后将投影矩阵添加到顶点着色器。

    从那时起,只要是相同的 3D 模型,它就会在为制服和绘制调用设置新值之间交替。

    对于不同的模型,请参阅@rabbid76 的回答。

    【讨论】:

      猜你喜欢
      • 2021-07-17
      • 1970-01-01
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 2011-10-15
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多