来源:《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 )
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;
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 ;
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" ) ;
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) ;
glUseProgram ( renderingProgram) ;
x += inc;
if ( x > 0.6f ) inc = - 0.01f ;
if ( x < - 0.6f ) inc = 0.01f ;
GLuint offsetLoc = glGetUniformLocation ( renderingProgram, "offset" ) ;
glProgramUniform1f ( renderingProgram, offsetLoc, x) ;
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