OpenGL:创建彩色三角形

OpenGL:创建彩色三角形,opengl,Opengl,我最近在学习OpenGL,我想在每个点上画一个红色、绿色、蓝色的三角形。但是,当我使用以下代码时,它只显示一个空白的白色窗口。我找不到错误在哪里。我关注这本书和红皮书 #include <GL/glew.h> #include <GL/freeglut.h> #include <iostream> using namespace std; const int WIDTH = 300; const int HEIGHT = 300; enum VAO_ID

我最近在学习OpenGL,我想在每个点上画一个红色、绿色、蓝色的三角形。但是,当我使用以下代码时,它只显示一个空白的白色窗口。我找不到错误在哪里。我关注这本书和红皮书

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>

using namespace std;

const int WIDTH = 300;
const int HEIGHT = 300;

enum VAO_IDs {Triangles,NumVAOs};
enum Buffer_IDs {ArrayBuffer,NumBuffers};
enum Attrib_IDs{vVertex,vColor};

GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
static const GLchar* vertexSource[] = {
    "#version 330\n"
    "in vec3 position;\n"
    "in vec3 color;\n"

    "out vec3 Color;\n"

    "void main()\n"
    "{\n"
    "   Color = color;\n"
    "   gl_Position = vec4(position, 1.0);\n"
    "}\n" };

static const GLchar* fragmentSource[] = {
    "#version 330\n"

    "in vec3 Color;\n"

    "out vec4 outColor;\n"

    "void main()\n"
    "{"
    "   outColor = vec4(Color, 1.0);\n"
    "}" };





void OnInit() {

    //Generate vertex objects 
    //Bind vertex objects
    glGenVertexArrays(NumVAOs, VAOs);
    glBindVertexArray(VAOs[Triangles]);

    //Input vertices information
    GLfloat vertices[] = {
         0.0f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // Vertex 1: Red
         0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,// Vertex 2: Green
        -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f// Vertex 3: Blue
    };

    //Generate Buffer object
    //Bind Buffer object
    //Bind Buffer data
    glGenBuffers(NumBuffers,Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //Generate vertexshader
    //Bind vertexshader source
    //Compile vertexshader
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, vertexSource, NULL);
    glCompileShader(vertexShader);
    //debug
    GLint vertexShader_status;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexShader_status);
    if (!vertexShader_status){
        GLsizei log_length = 0;
        GLchar message[1024];
        glGetShaderInfoLog(vertexShader, 1024, &log_length, message);
        std::cout << message << std::endl;
    }

    //Generate fragmentshader
    //Bind fragmentshader source
    //Compile fragmentshader
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, fragmentSource, NULL);
    GLint fragmentShader_status;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &fragmentShader_status);
    if (!fragmentShader_status){
        GLsizei log_length = 0;
        GLchar message[1024];
        glGetShaderInfoLog(vertexShader, 1024, &log_length, message);
        std::cout << message << std::endl;
    }

    //Generate program
    //Attach attributes to the program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    //Figure out position attributes information
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    cout << "vPosition: " << posAttrib << endl;
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE,
        6 * sizeof(GLfloat), 0);

    //Figure out color attributes information
    GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
    cout << "vColor: " << colAttrib << endl;
    glEnableVertexAttribArray(colAttrib);
    glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE,
        6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));

    cout << "Initialization successfull" << endl;
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBindVertexArray(VAOs[Triangles]);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glFlush();
    cout << "Display successfull" << endl;

}
void OnShutdown() {
    cout << "Shutdown successfull" << endl;
}
void OnResize(int nw, int nh) {
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE |
        GLUT_RGBA);
    glutInitContextVersion(3, 3);
    glutInitContextFlags(GLUT_CORE_PROFILE | GLUT_DEBUG);
    glutInitContextProfile(GLUT_FORWARD_COMPATIBLE);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitContextFlags(GLUT_CORE_PROFILE | GLUT_DEBUG);
    glutInitContextProfile(GLUT_FORWARD_COMPATIBLE);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutCreateWindow("Getting started with OpenGL 3.3");
    glewExperimental = GL_TRUE;
    GLenum err = glewInit();
    if (GLEW_OK != err){
        cerr << "Error: " << glewGetErrorString(err) << endl;
    }
    else {
        if (GLEW_VERSION_3_3)
        {
            cout << "Driver supports OpenGL 3.3\nDetails:" << endl;
        }
    }
    cout << "\tUsing glew " << glewGetString(GLEW_VERSION) << endl;
    cout << "\tVendor: " << glGetString(GL_VENDOR) << endl;
    cout << "\tRenderer: " << glGetString(GL_RENDERER) << endl;
    cout << "\tVersion: " << glGetString(GL_VERSION) << endl;
    cout << "\tGLSL:"<<glGetString(GL_SHADING_LANGUAGE_VERSION)<<endl;
    OnInit();
    glutDisplayFunc(display);
    glutReshapeFunc(OnResize);
    glutMainLoop();
    return 0;
}
#包括
#包括
#包括
使用名称空间std;
常数int宽度=300;
const int HEIGHT=300;
enum VAO_id{三角形,NumVAOs};
枚举缓冲区_id{ArrayBuffer,NumBuffers};
枚举属性ID{vVertex,vColor};
GLuint VAOs[NumVAOs];
胶合缓冲区[NumBuffers];
静态常量GLchar*顶点源[]={
“#版本330\n”
“处于vec3位置;\n”
“以vec3颜色显示;\n”
“输出vec3颜色;\n”
“void main()\n”
“{\n”
“颜色=颜色;\n”
gl_位置=vec4(位置,1.0);\n
“}\n”};
静态常量GLchar*碎片源[]={
“#版本330\n”
“以vec3颜色显示;\n”
“out vec4 OUTCLOR;\n”
“void main()\n”
"{"
outColor=vec4(颜色,1.0);\n
"}" };
void OnInit(){
//生成顶点对象
//绑定顶点对象
glGenVertexArrays(NumVAOs、VAOs);
glBindVertexArray(VAOs[三角形]);
//输入顶点信息
GLfloat顶点[]={
0.0f,0.5f,0.0f,1.0f,0.0f,0.0f,//顶点1:红色
0.5f,-0.5f,0.0f,0.0f,1.0f,0.0f,//顶点2:绿色
-0.5f、-0.5f、0.0f、0.0f、0.0f、1.0f//Vertex 3:蓝色
};
//生成缓冲区对象
//绑定缓冲区对象
//绑定缓冲区数据
glGenBuffers(NumBuffers,Buffers);
glBindBuffer(GL_ARRAY_BUFFER,Buffers[ArrayBuffer]);
glBufferData(GLU数组缓冲区、大小(顶点)、顶点、GLU静态图);
//生成顶点着色器
//绑定顶点着色器源
//编译顶点着色器
GLuint vertexShader=glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader,1,vertexSource,NULL);
glCompileShader(顶点着色器);
//调试
闪烁顶点状态;
glGetShaderiv(顶点着色器、GL_编译_状态和顶点着色器_状态);
如果(!vertexShader_状态){
GLsizei log_长度=0;
GLchar消息[1024];
glGetShaderInfoLog(顶点着色器,1024,&日志长度,消息);

std::cout您可以使用以下代码: 我现在不深入讨论细节,但您需要创建一个顶点数组对象并将其设置为当前对象 胶合垂直排列; glgenvertexarray(1和VertexArrayID); glBindVertexArray(VertexArrayID); 在创建窗口后(=在OpenGL上下文创建之后)和任何其他OpenGL调用之前执行此操作

三角形由三个点定义。在3D图形中谈论“点”时,我们通常使用“顶点”(复数形式为“顶点”)一词。顶点有三个坐标:X、Y和Z。您可以用以下方式来考虑这三个坐标:

X in on your right
Y is up
Z is towards your back (yes, behind, not in front of you)
但这里有一个更好的方法来形象化这一点:使用右手法则

X is your thumb
Y is your index
Z is your middle finger. If you put your thumb to the right and your index to the sky, it will point to your back, too.
让Z朝这个方向是很奇怪的,为什么会这样呢?简单回答:因为100年的右手法则数学会给你很多有用的工具。唯一的缺点是Z不直观

另一方面,请注意,您可以自由移动手:您的X、Y和Z也将移动。稍后将详细介绍

所以我们需要三个3D点才能形成一个三角形,让我们开始: //表示3个顶点的3个向量的数组 静态常量GLfloat g_顶点_缓冲区_数据[]={ -1.0f,-1.0f,0.0f, 1.0f,-1.0f,0.0f, 0.0f,1.0f,0.0f, }; 第一个顶点是(-1,-1,0)。这意味着除非我们以某种方式转换它,否则它会显示在屏幕上的(-1,-1)。这意味着什么?屏幕原点在中间,X在右边,像往常一样,Y是上升的。这是它在宽屏幕上给出的: 下一步是将此三角形交给OpenGL。我们通过创建缓冲区来实现:

// This will identify our vertex buffer
GLuint vertexbuffer;

// Generate 1 buffer, put the resulting identifier in vertexbuffer
glGenBuffers(1, &vertexbuffer);

// The following commands will talk about our 'vertexbuffer' buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);

// Give our vertices to OpenGL.
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data),
g_vertex_buffer_data, GL_STATIC_DRAW);
这只需要做一次

现在,在我们的主循环中,我们过去常在这里画“无”,我们可以画出一个宏伟的三角形: //1rst属性缓冲区:顶点 GlenableVertexAttributeArray(0); glBindBuffer(GL_数组_BUFFER,vertexbuffer); glvertexattributepointer( 0,//属性0。0没有特殊原因,但必须与着色器中的布局匹配。 3,//大小 GL\u FLOAT,//类型 GL_FALSE,//标准化? 0,//步幅 (void*)0//数组缓冲区偏移量 ))

着色器编译

在最简单的配置中,您将需要两个着色器:一个称为顶点着色器,将对每个顶点执行,另一个称为片段着色器,将对每个样本执行。由于我们使用4x反序列化,因此每个像素中有4个样本

着色器是用一种称为GLSL的语言编程的:GL着色器语言是OpenGL的一部分。与C或Java不同,GLSL必须在运行时编译,这意味着每次启动应用程序时,都会重新编译所有着色器

这两个着色器通常位于不同的文件中。在本例中,我们有SimpleFragmentShader.fragmentshader和SimpleVertexShader.vertexshader。扩展名不相关,可以是.txt或.glsl

下面是代码。完全理解它不是很重要,因为您通常在程序中只执行一次,所以注释就足够了。由于此函数将由所有其他教程使用,因此它被放置在一个单独的文件中:common/loadShader.cpp。请注意,正如缓冲区一样,着色器也不能直接访问:我们只有一个n ID。实际实现隐藏在驱动程序中。 GLuint加载着色器(常量字符*顶点文件路径,常量字符*片段文件路径){

为每个顶点调用的函数称为main,就像在C中一样: void main(){ 我们的主要功能只是将顶点的位置设置为缓冲区中的任何位置。因此,如果我们给出(1,1),三角形的一个顶点将位于屏幕的右上角。我们将
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices 

total -> 1 triangle

glDisableVertexAttribArray(0);
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open())
{
    std::string Line = "";
    while(getline(VertexShaderStream, Line))
        VertexShaderCode += "\n" + Line;
    VertexShaderStream.close();
}

// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
    std::string Line = "";
    while(getline(FragmentShaderStream, Line))
        FragmentShaderCode += "\n" + Line;
    FragmentShaderStream.close();
}

GLint Result = GL_FALSE;
int InfoLogLength;

// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);

// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);

// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);

// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);

// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);

// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);

glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);

return ProgramID;
“vec3″ is a vector of 3 components in GLSL. It is similar (but different) to the glm::vec3 we used to declare our triangle. The important thing is that if we use 3 components in C++, we use 3 components in GLSL too.
“layout(location = 0)” refers to the buffer we use to feed the vertexPosition_modelspace attribute. Each vertex can have numerous attributes : A position, one or several colours, one or several texture coordinates, lots of other things. OpenGL doesn’t know what a colour is : it just sees a vec3. So we have to tell him which buffer corresponds to which input. We do that by setting the layout to the same value as the first parameter to glVertexAttribPointer. The value “0″ is not important, it could be 12 (but no more than glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &v) ), the important thing is that it’s the same number on both sides.
“vertexPosition_modelspace” could be anything else. It will contain the position of the vertex for each run of the vertex shader.
“in” means that this is some input data. Soon we’ll see the “out” keyword.
void main(){
    color = vec3(1,0,0);
}
glShaderSource(fragmentShader, 1, fragmentSource, NULL);
GLint fragmentShader_status;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &fragmentShader_status);
glShaderSource(fragmentShader, 1, fragmentSource, NULL);
glCompileShader(fragmentShader);
GLint fragmentShader_status;
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShader_status);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutSwapBuffers();
cout << "Display successfull" << endl;