欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenGL基础7:彩色三角形

程序员文章站 2023-12-24 22:08:57
...

 

一、多顶点属性

前面顶点属性只用了位置属性,现在可以尝试给顶点加上颜色属性

GLfloat trangleY[] =
{
    -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
    -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};

这些属性更新到VBO内存中后,数据看起来如下:

OpenGL基础7:彩色三角形

还记得之前讲过的 glVertexAttribPointer 方法嘛,这里就需要调用2次,一次标准化位置属性,一次标准化颜色属性

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

最后一个参数就是图片中的 OFFEST,倒数第二个参数就是图片中的 STRIDE,应该非常好理解

再看看第一个参数:之前说过代表着顶点着色器中的位置值,其中位置属性的位置值为0,颜色属性的位置值为1,着色器部分代码如下:

const GLchar* VShader =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec4 color;\n"
"out vec4 colorIn;\n"
"void main()\n"
"{\n"
    "gl_Position = vec4(position, 1.0);\n"
    "colorIn = color;"
"}\n\0";

const GLchar* FShaderY =
"#version 330 core\n"
"out vec4 color;\n"
"in vec4 colorIn;\n"
"void main()\n"
"{\n"
    "color = colorIn;\n"
"}\n\0";

修改上一章的代码,可以得出的最终效果:

OpenGL基础7:彩色三角形

可以看出左边的三角形变成了彩虹色,其中左上顶点颜色为绿色,左下顶点颜色为红色,右顶点颜色为蓝色,而中间的颜色则为其片段插值(Fragment Interpolation)的结果,当渲染一个三角形时,光栅化(Rasterization)阶段通常会造成比原指定顶点更多的片段,并根据每个片段在三角形形状上所处相对位置决定这些片段的位置

 

二、文件读取

其实就是画两个三角形,代码还是有点长,而且GLSL的代码用双引号包住也比较奇怪

所以可以整理一下,先将所有的GLSL单独写在一个文件中,如下,先建立3个.txt文件(后缀其实随意),分别对应着顶点着色器和两个片段着色器

OpenGL基础7:彩色三角形

#version 330 core
out vec4 color;
void main()
{
    color = vec4(0.1f, 0.1f, 1.0f, 1.0f);
}
#version 330 core
out vec4 color;
in vec4 colorIn;
void main()
{
    color = colorIn;
}
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
out vec4 colorIn;
void main()
{
    gl_Position = vec4(position, 1.0);
    colorIn = color;
}

 

其次再看下代码的结构,你会发现可以将着色器编译链接的部分拉出来作为一个类如下:

#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <opengl/glew.h>

class Shader
{
    public:
        GLuint Program;
        Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
        {
            std::string vertexCode;
            std::string fragmentCode;
            std::ifstream vShaderFile;
            std::ifstream fShaderFile;
            vShaderFile.exceptions(std::ifstream::badbit);
            fShaderFile.exceptions(std::ifstream::badbit);
            try
            {
                vShaderFile.open(vertexPath);
                fShaderFile.open(fragmentPath);
                std::stringstream vShaderStream, fShaderStream;
                vShaderStream << vShaderFile.rdbuf();
                fShaderStream << fShaderFile.rdbuf();
                vShaderFile.close();
                fShaderFile.close();
                vertexCode = vShaderStream.str();
                fragmentCode = fShaderStream.str();
            }
            catch (std::ifstream::failure e)
            {
                std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
            }
            const GLchar* vShaderCode = vertexCode.c_str();
            const GLchar* fShaderCode = fragmentCode.c_str();

            GLuint vertex, fragment;
            GLint success;
            GLchar infoLog[512];

            vertex = glCreateShader(GL_VERTEX_SHADER);
            glShaderSource(vertex, 1, &vShaderCode, NULL);
            glCompileShader(vertex);
            glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
            if (!success)
            {
                glGetShaderInfoLog(vertex, 512, NULL, infoLog);
                std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
            }

            fragment = glCreateShader(GL_FRAGMENT_SHADER);
            glShaderSource(fragment, 1, &fShaderCode, NULL);
            glCompileShader(fragment);
            glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
            if (!success)
            {
                glGetShaderInfoLog(fragment, 512, NULL, infoLog);
                std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
            }

            this->Program = glCreateProgram();
            glAttachShader(this->Program, vertex);
            glAttachShader(this->Program, fragment);
            glLinkProgram(this->Program);
            glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
            if (!success)
            {
                glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
                std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
            }
            glDeleteShader(vertex);
            glDeleteShader(fragment);

        }
        void Use()
        {
            glUseProgram(this->Program);
        }
};
#endif

其中构造函数内容可以分为3部分:

  • 读写文件:读取对应的GLSL代码字符串
  • 编译:因为专门分出来了一个类,所以也可以多加一步检查编译/链接是否失败,如果失败则打印编译时错误,链接下同
  • 链接

注意如果读不到可能也不会抛出读取异常,当然后面链接必定失败

最后就是主程序了

#pragma comment(lib,"glew32.lib")
#include<iostream>
#include<opengl/glew.h>
#define GLEW_STATIC
#include<GLFW/glfw3.h>
#include"Shader.h"
#include<opengl/freeglut.h>

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
const GLuint WIDTH = 800, HEIGHT = 600;

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);
    glewExperimental = GL_TRUE;
    glewInit();

    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, width, height);

    Shader shaderYellow("VShader.txt", "FShaderY.txt");
    Shader shaderBlue("VShader.txt", "FShaderB.txt");

    GLfloat trangleY[] =
    {
        -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
    };
    GLfloat trangleB[] =
    {
        0.5f, -0.5f, 0.0f,
        0.5f, 0.5f, 0.0f,
        0.0f, 0.0f, 0.0f
    };
    GLuint VBO[2], VAO[2];
    glGenVertexArrays(2, VAO);
    glGenBuffers(2, VBO);

    glBindVertexArray(VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(trangleY), trangleY, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(trangleB), trangleB, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        shaderYellow.Use();
        glBindVertexArray(VAO[0]);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        shaderBlue.Use();
        glBindVertexArray(VAO[1]);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(2, VAO);
    glDeleteBuffers(2, VBO);
    glfwTerminate();
    return 0;
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

输出结果就是上面的彩色三角形了

相关标签: # openGL openGL

上一篇:

下一篇: