使用着色器GLEW绘制多个对象

问题描述

我想使用三角形风扇绘制不同的图形,但是我不确定如何使程序绘制第二个图形。每当我想要更改颜色或绘制新图形时,是否需要第二个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);\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,// Center.
    -0.8f,0.4f,-0.83f,0.44f,-0.87f,0.51f,-0.9f,0.57f,-0.93f,0.63f,-0.95f,0.69f,-0.97f,0.75f,-0.98f,0.8f,-0.91f,-0.85f,0.79f,-0.8f,0.77f,};

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

void display(void){
    // Background color.
    glClearColor(1.0f,1.0f,0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLE_FAN,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,&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();
}

解决方法

不需要(或不建议)为网格使用不同的着色器。如果要绘制多个对象,则可以将网格的顶点属性放在单独的Vertex Buffer Object s中:

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,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,(void*)0);
glEnableVertexAttribArray(0);

在抽奖之前绑定VAO:

glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLE_FAN,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

,

您正在寻找Uniform buffer objects

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

从那时起,只要是同一3D模型,就可以在将新值设置为制服和绘制调用之间交替进行。

对于不同的型号,请参考@ rabbid76的答案。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...