ICS
ICS

Reputation: 87

Drawing multiple objects with shaders (GLEW)

I want to draw different figures using triangle fans but I am not sure how to make the program draw the second figure. Do I need a second vertexShaderSource and a second fragmentShaderSource each time I want to change the color or draw a new figure?

Here is the code:

#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();
}

Upvotes: 2

Views: 1041

Answers (2)

Rabbid76
Rabbid76

Reputation: 210878

No is not necessary (or recommended) to use different shaders for the meshes. If you want to draw multiple objects, then you can put the vertex attributes of the meshes to separate 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);

Specify a Vertex Array Object for each mesh:

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

Bind the VAO, before the draw call:

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

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

Of course it is also possible to put all the vertex attributes of the different meshes consecutively in the data store of one VBO. If the vertex specification is identically, then it is event possible to use one single VAO.


Different locations of different meshes can be achieved by vertex transformation in the vertex shader. Use a Uniform of type mat4, to transform the vertices of a mesh:

#version 330 core

layout (location = 0) in vec3 aPos;

uniform mat4 u_model;

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

See further LearnOpenGL - Transformations.


If the 2 figures are identical, but have just a different location, then you can draw the same mesh twice, but you have to change the model transformation u_model.

Upvotes: 1

Ext3h
Ext3h

Reputation: 6283

You are looking for Uniform buffer objects.

If you have only a single value for a whole draw call, then your shader should be parametrized. The obvious thing you want to parametrize first is the color in the fragment shader, followed by adding a projection matrix to the vertex shader.

From that point onwards it's just alternating between setting new values to uniforms and draw-calls as long as it is the same 3D model.

For different models refer to @rabbid76's answer.

Upvotes: 0

Related Questions