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内存中后,数据看起来如下:
还记得之前讲过的 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";
修改上一章的代码,可以得出的最终效果:
可以看出左边的三角形变成了彩虹色,其中左上顶点颜色为绿色,左下顶点颜色为红色,右顶点颜色为蓝色,而中间的颜色则为其片段插值(Fragment Interpolation)的结果,当渲染一个三角形时,光栅化(Rasterization)阶段通常会造成比原指定顶点更多的片段,并根据每个片段在三角形形状上所处相对位置决定这些片段的位置
二、文件读取
其实就是画两个三角形,代码还是有点长,而且GLSL的代码用双引号包住也比较奇怪
所以可以整理一下,先将所有的GLSL单独写在一个文件中,如下,先建立3个.txt文件(后缀其实随意),分别对应着顶点着色器和两个片段着色器
#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);
}
输出结果就是上面的彩色三角形了