A.1从顶点构建对象(绘制一个三角形)
我们想要绘制的不仅仅是一个单独的点,而是由很多顶点组成的对象。现在让我们先用三个顶点来绘制一个三角形。
如何绘制呢?
-
修改顶点着色器,以便让3个不同的点输出到后续的管线阶段
-
修改glDrawArrays(),指定绘制的图形为三角形
代码实现:
1.修改vertShader.glsl文件
//vertShader.glsl文件
#version 430
void main(void)
{
if(gl_VertexID == 0)//内置变量
gl_Position = vec4(0.25, -0.25, 0.0, 1.0);
else if(gl_VertexID == 1)
gl_Position = vec4(-0.25, -0.25, 0.0, 1.0);
else
gl_Position = vec4(0.25, 0.25, 0.0, 1.0);
}
2.修改fragShader.glsl文件
//fragShader.glsl文件
#version 430
out vec4 color;
void main(void)
{
color = vec4(1.0, 0.0, 0.0, 1.0);
}
3.修改.cpp文件
//Display函数修改
//glPointSize(430.0f);//设置点的大小
glDrawArrays(GL_TRIANGLES, 0, 3);
4.运行结果输出
5.cpp完整代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#define numVAOs 1
unsigned int renderingProgram;
unsigned int vao[numVAOs];//顶点数组,必须要有
unsigned int CreateShaderProgram();
//读取文件中的GLSL的源代码
std::string ReadShaderSource(const char* filePath)
{
std::string content;
std::ifstream fileStream(filePath, std::ios::in);
std::string line = "";
while (!fileStream.eof())
{
getline(fileStream, line);
content.append(line + '\n');
}
fileStream.close();
return content;
}
//捕获GLSL代码编译失败信息函数
void PrintShaderLog(unsigned int shader)
{
int len = 0;
int chWrittn = 0;
char* log;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len > 0)
{
log = (char*)malloc(len);
glGetShaderInfoLog(shader, len, &chWrittn, log);
std::cout << "Shader Info Log: " << log << std::endl;
free(log);
}
}
//捕获GLSL链接失败信息函数
void PrintProgramLog(int prog)
{
int len = 0;
int chWrittn = 0;
char* log;
glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &len);
if (len > 0)
{
log = (char*)malloc(len);
glGetProgramInfoLog(prog, len, &chWrittn, log);
std::cout << "Program Info Log: " << std::endl;
free(log);
}
}
//检查OpenGL错误函数
bool CheckOpenGLError()
{
bool foundError = false;
int glErr = glGetError();
while (glErr != GL_NO_ERROR)
{
std::cout << "glError: " << glErr << std::endl;
foundError = true;
glErr = glGetError();
}
return foundError;
}
void Init(GLFWwindow* window)
{
renderingProgram = CreateShaderProgram();
glGenVertexArrays(numVAOs, vao);//生成顶点数组对象名称,用numVAOs存储
glBindVertexArray(vao[0]);//绑定vao[0]
}
void Display(GLFWwindow* window, double currentTime)
{
glUseProgram(renderingProgram);//激活程序对象
//glPointSize(430.0f);//设置点的大小
glDrawArrays(GL_TRIANGLES, 0, 3);//绘制方式,绘制三角形
}
unsigned int CreateShaderProgram()
{
//从文件读取GLSL代码
std::string vertShaderStr = ReadShaderSource("./res/shaders/vertShader.glsl");
std::string fragShaderStr = ReadShaderSource("./res/shaders/fragShader.glsl");
const char* vertShaderSrc = vertShaderStr.c_str();
const char* fragShaderSrc = fragShaderStr.c_str();
//捕获编译着色器时的错误
int vertComplied;
int fragComplied;
int linked;
//创建顶点着色器和片段着色器
unsigned int vShader = glCreateShader(GL_VERTEX_SHADER);
unsigned int fShader = glCreateShader(GL_FRAGMENT_SHADER);
//替换vShader,fShader中的源代码,使用自定义的编码
glShaderSource(vShader, 1, &vertShaderSrc, NULL);
glShaderSource(fShader, 1, &fragShaderSrc, NULL);
//对着色器对象进行编译
glCompileShader(vShader);
CheckOpenGLError();
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertComplied);
if (vertComplied != 1)
{
std::cout << "vertex compilation faild" << std::endl;
PrintShaderLog(vShader);
}
glCompileShader(fShader);
CheckOpenGLError();
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragComplied);
if (fragComplied != 1)
{
std::cout << "fragment compilation faild" << std::endl;
PrintShaderLog(fShader);
}
//创建一个Program链接着色器对象,执行的就是链接有着色器对象的程序
unsigned int vfProgram = glCreateProgram();
//把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
glLinkProgram(vfProgram);
CheckOpenGLError();
glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
if (linked != 1)
{
std::cout << "linking faild" << std::endl;
PrintProgramLog(vfProgram);
}
//返回连接好的着色器程序
return vfProgram;
}
int main()
{
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow* window = glfwCreateWindow(600, 600, "Hello, world", nullptr, nullptr);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
exit(EXIT_FAILURE);
glfwSwapInterval(1);
Init(window);
while (!glfwWindowShouldClose(window))
{
Display(window, glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
A.2实现简单的场景动画
如何实现呢?
我们只需要定义一个变量,再定义一个变量增量,这样我们可以对那三个顶点的坐标的值加上变量的值,通过控制增量的变化来控制绘制出的三角形的移动。
代码实现:(沿X轴运动)
//vertShader.glsl文件
#version 430
uniform float offset;//声明一个全局的着色器变量
void main(void)
{
if(gl_VertexID == 0)
gl_Position = vec4(0.25+offset, -0.25, 0.0, 1.0);
else if(gl_VertexID == 1)
gl_Position = vec4(-0.25+offset, -0.25, 0.0, 1.0);
else
gl_Position = vec4(0.25+offset, 0.25, 0.0, 1.0);
}
//fragShader.glsl文件
#version 430
out vec4 color;
void main(void)
{
color = vec4(1.0, 0.0, 0.0, 1.0);
}
//.cpp文件新增全局变量
float x = 0.0f;//X轴范围判断
float inc = 0.01f;//X轴增量
//修改.cpp文件中的Display函数
void Display(GLFWwindow* window, double currentTime)
{
//不是必须的,我们在隐藏面消除需要同时用到颜色缓冲区和深度缓冲区
// 每帧初始化深度缓冲区是必要的
//确保深度对比不会受旧的深度的影响
glClear(GL_DEPTH_BUFFER_BIT);
glClearColor(0.0, 0.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);//相当于在设置显示区域的背景,比如此刻我将其设置为蓝色
glUseProgram(renderingProgram);//激活程序对象
x += inc;
if (x > 1.0) inc = -inc;
if (x < -1.0) inc = -inc;
//指定要查询的程序对象为renderingProgram,查询其位置的统一变量的名称为offset
unsigned int offsetLoc = glGetUniformLocation(renderingProgram, "offset");
//为指定的程序对象指定统一变量的值,当前只有一个为offsetLoc,指定新值为x
glProgramUniform1f(renderingProgram, offsetLoc, x);
//glPointSize(430.0f);//设置点的大小
glDrawArrays(GL_TRIANGLES, 0, 3);//绘制方式,绘制三角形
}
.cpp完整代码
//.cpp文件完整代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#define numVAOs 1
unsigned int renderingProgram;
unsigned int vao[numVAOs];//顶点数组,必须要有
unsigned int CreateShaderProgram();
float x = 0.0f;//X轴范围判断
float inc = 0.01f;//X轴增量
//读取文件中的GLSL的源代码
std::string ReadShaderSource(const char* filePath)
{
std::string content;
std::ifstream fileStream(filePath, std::ios::in);
std::string line = "";
while (!fileStream.eof())
{
getline(fileStream, line);
content.append(line + '\n');
}
fileStream.close();
return content;
}
//捕获GLSL代码编译失败信息函数
void PrintShaderLog(unsigned int shader)
{
int len = 0;
int chWrittn = 0;
char* log;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len > 0)
{
log = (char*)malloc(len);
glGetShaderInfoLog(shader, len, &chWrittn, log);
std::cout << "Shader Info Log: " << log << std::endl;
free(log);
}
}
//捕获GLSL链接失败信息函数
void PrintProgramLog(int prog)
{
int len = 0;
int chWrittn = 0;
char* log;
glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &len);
if (len > 0)
{
log = (char*)malloc(len);
glGetProgramInfoLog(prog, len, &chWrittn, log);
std::cout << "Program Info Log: " << std::endl;
free(log);
}
}
//检查OpenGL错误函数
bool CheckOpenGLError()
{
bool foundError = false;
int glErr = glGetError();
while (glErr != GL_NO_ERROR)
{
std::cout << "glError: " << glErr << std::endl;
foundError = true;
glErr = glGetError();
}
return foundError;
}
void Init(GLFWwindow* window)
{
renderingProgram = CreateShaderProgram();
glGenVertexArrays(numVAOs, vao);//生成顶点数组对象名称,用numVAOs存储
glBindVertexArray(vao[0]);//绑定vao[0]
}
void Display(GLFWwindow* window, double currentTime)
{
//不是必须的,我们在隐藏面消除需要同时用到颜色缓冲区和深度缓冲区
// 每帧初始化深度缓冲区是必要的
//确保深度对比不会受旧的深度的影响
glClear(GL_DEPTH_BUFFER_BIT);
glClearColor(0.0, 0.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);//相当于在设置显示区域的背景,比如此刻我将其设置为蓝色
glUseProgram(renderingProgram);//激活程序对象
x += inc;
if (x > 1.0) inc = -inc;
if (x < -1.0) inc = -inc;
//指定要查询的程序对象为renderingProgram,查询其位置的统一变量的名称为offset
unsigned int offsetLoc = glGetUniformLocation(renderingProgram, "offset");
//为指定的程序对象指定统一变量的值,当前只有一个为offsetLoc,指定新值为x
glProgramUniform1f(renderingProgram, offsetLoc, x);
//glPointSize(430.0f);//设置点的大小
glDrawArrays(GL_TRIANGLES, 0, 3);//绘制方式,绘制三角形
}
unsigned int CreateShaderProgram()
{
//从文件读取GLSL代码
std::string vertShaderStr = ReadShaderSource("./res/shaders/vertShader.glsl");
std::string fragShaderStr = ReadShaderSource("./res/shaders/fragShader.glsl");
const char* vertShaderSrc = vertShaderStr.c_str();
const char* fragShaderSrc = fragShaderStr.c_str();
//捕获编译着色器时的错误
int vertComplied;
int fragComplied;
int linked;
//创建顶点着色器和片段着色器
unsigned int vShader = glCreateShader(GL_VERTEX_SHADER);
unsigned int fShader = glCreateShader(GL_FRAGMENT_SHADER);
//替换vShader,fShader中的源代码,使用自定义的编码
glShaderSource(vShader, 1, &vertShaderSrc, NULL);
glShaderSource(fShader, 1, &fragShaderSrc, NULL);
//对着色器对象进行编译
glCompileShader(vShader);
CheckOpenGLError();
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertComplied);
if (vertComplied != 1)
{
std::cout << "vertex compilation faild" << std::endl;
PrintShaderLog(vShader);
}
glCompileShader(fShader);
CheckOpenGLError();
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragComplied);
if (fragComplied != 1)
{
std::cout << "fragment compilation faild" << std::endl;
PrintShaderLog(fShader);
}
//创建一个Program链接着色器对象,执行的就是链接有着色器对象的程序
unsigned int vfProgram = glCreateProgram();
//把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
glLinkProgram(vfProgram);
CheckOpenGLError();
glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
if (linked != 1)
{
std::cout << "linking faild" << std::endl;
PrintProgramLog(vfProgram);
}
//返回连接好的着色器程序
return vfProgram;
}
int main()
{
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow* window = glfwCreateWindow(600, 600, "Hello, world", nullptr, nullptr);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
exit(EXIT_FAILURE);
glfwSwapInterval(1);
Init(window);
while (!glfwWindowShouldClose(window))
{
Display(window, glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}