- 来源:《Computer Graphics Programming in OpenGL Using C++ 》by V Scott Gordon John L Clevenger
- 内容:程序2.6 Program 2.6: Simple Animation Example,书P29页,PDF48/403
- 生成三角形移动动画,如图



- 文件1: 2.6 fragShader.glsl (可用记事本写,更改后缀名)
#version 430
out vec4 color;
void main(void) {
if (gl_FragCoord.x < 500) // 这个是整个窗口的值,在对应cpp文件中设置窗口1000x400
// 所以500 是窗口的正中间位置
color = vec4(1.0, 0.0, 0.0, 1.0);
else
color = vec4(0.0, 0.0, 1.0, 1.0);
}
- 文件2: 2.6 verShader.glsl
#version 430
uniform float offset; // 注意,offset 的值,是由 cpp文件中 x 来赋值的
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);
}
- 文件3: 220202 2.6 animation.cpp
#include "include/GL/glew.h"
#include "include/GLFW/glfw3.h"
#include <iostream>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
#define numVAOs 1
GLuint renderingProgram;
GLuint vao[numVAOs];
float x = 0.0f; // x轴上三角形的位置
float inc = 0.01f; // 三角形运动的偏移量
void printShaderLog(GLuint 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);
cout << "Shader Info Log: " << log << endl;
free(log);
}
}
void printProgramLog(int prog) {
int len = 0;
int chWrittn = 0;
char *log;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
if (len > 0) {
log = (char *)malloc(len);
glGetProgramInfoLog(prog, len, &chWrittn, log);
cout << "Program Info Log: " << log << endl;
free(log);
}
}
bool checkOpenGLError() {
bool foundError = false;
int glErr = glGetError();
while (glErr != GL_NO_ERROR) {
cout << "glError: " << glErr << endl;
foundError = true;
glErr = glGetError();
}
return foundError;
}
string readShaderSource(const char *filePath) {
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
while (!fileStream.eof()) {
getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
GLuint createShaderProgram() {
GLint vertCompiled;
GLint fragCompiled;
GLint linked;
string vertShaderStr = readShaderSource("add/2.6 vertShader.glsl"); // 文件在add文件夹中
string fragShaderStr = readShaderSource("add/2.6 fragShader.glsl");
const char *vertShaderSrc = vertShaderStr.c_str();
const char *fragShaderSrc = fragShaderStr.c_str();
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vShader, 1, &vertShaderSrc, NULL);
glShaderSource(fShader, 1, &fragShaderSrc, NULL);
// 在编译着色器时,捕捉错误
glCompileShader(vShader);
checkOpenGLError();
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
if (vertCompiled != 1) {
cout << "vertex compilation failed" << endl;
printShaderLog(vShader);
}
glCompileShader(fShader);
checkOpenGLError();
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
if (fragCompiled != 1) {
cout << "fragment compilation failed" << endl;
printShaderLog(fShader);
}
GLuint vfProgram = glCreateProgram();
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
glLinkProgram(vfProgram);
checkOpenGLError();
glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
if (linked != 1) {
cout << "linking failed" << endl;
printProgramLog(vfProgram);
}
return vfProgram;
}
void init(GLFWwindow* window) {
renderingProgram = createShaderProgram();
glGenVertexArrays(numVAOs, vao);
glBindVertexArray(vao[0]);
}
void display(GLFWwindow* window, double currentTime) {
glClear(GL_DEPTH_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT); // 每一次都将背景清理(clear)为黑色
glUseProgram(renderingProgram);
x += inc; // 在x轴上移动三角形
if (x > 0.6f) inc = -0.01f; // 三角形改变移动方向,改变为向左移动
if (x < -0.6f) inc = 0.01f; // 三角形改变为向右移动方向
GLuint offsetLoc = glGetUniformLocation(renderingProgram, "offset"); // 设置一个指针ptr指向 offset
glProgramUniform1f(renderingProgram, offsetLoc, x); // 将x的值赋值给offset
glDrawArrays(GL_TRIANGLES, 0, 3);
}
int main(void) {
if (!glfwInit()) { exit(EXIT_FAILURE); }
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow* window = glfwCreateWindow(1000, 400, "Chapter2-program2", NULL, NULL);
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);
}
- 补充
main(): 函数需要重构来支持动画 animation,调用一次 init(), 然后重复调用 display()
frame 帧:场景每一次渲染,就叫做帧
frame rate 帧率: 调用display()的频率
x :
在display函数中,采用 x 来表示 X 坐标的偏移量,
每次调用display函数,x 的值就会不一样,当x = 1.0或者-1.0,就会反向移动。
X 的 值,赋值给 点着色器 (vertex shader)的 offset 变量
X 的值赋值给 offset 变量,称为 uniform variable 统一变量
glGetUniformLocation(): 给 offset 变量一个指针
glProgramUniform1f(): 然后再调用该函数复制x的值到 offset
版权声明:本文为weixin_44115959原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。