OpenGL 基础知识
1. 主函数
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
//初始化OPENGL显示方式 双缓冲、RGBA颜色模式
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
//设定OPENGL窗口位置和大小
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
//打开窗口
glutCreateWindow ("OpenGL");
//调用初始化函数
myinit();
//设定窗口大小变化的回调函数,需要设定视区glViewport(0, 0, w,
h);、透视方式glMatrixMode(GL_PROJECTION)与透视参数gluPerspective(60.0,
1.0*(GLfloat)w/(GLfloat)h, 1.0, 30.0)(角度,视景体的宽高比,沿z轴方向的两裁面之间的距离的近处,远处)
glutReshapeFunc(myReshape);
//设定键盘控制的回调函数
//processSpecialKeys(int key, int x, int y)中key可以为GLUT_KEY_LEFT、GLUT_KEY_UP等
glutSpecialFunc(processSpecialKeys);
glutSpecialFunc(processSpecialKeys);
//processNormalKeys(unsigned char key,int x,int y)中key为ASCII
glutKeyboardFunc(processNormalKeys);
glutKeyboardFunc(processNormalKeys);
//10ms后执行回调function,回调中一般glutPostRedisplay()刷新页面,如果想重复执行再继续定义
glutTimerFunc(10, function, 0);
//开始OPENGL的循环
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
glutTimerFunc(10, function, 0);
//开始OPENGL的循环
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
2. 用户初始化函数
void myinit(void) {
void myinit(void) {
//打开深度检测
glEnable(GL_DEPTH_TEST);
//启用光照并打开默认的0号光
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//启用颜色材质并定义什么材料追踪颜色
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
glEnable(GL_DEPTH_TEST);
//启用光照并打开默认的0号光
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//启用颜色材质并定义什么材料追踪颜色
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
GLenum err = glewInit();
if (GLEW_OK != err) {
printf("glew initionlize error: %s\n", glewGetErrorString(err));
}
//设置矩阵模式
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (GLEW_OK != err) {
printf("glew initionlize error: %s\n", glewGetErrorString(err));
}
//设置矩阵模式
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//设置光源的位置、环境光、散射光、反射光的颜色
glLightfv(GL_LIGHT0, GL_POSITION, G_vLit0Position);
glLightfv(GL_LIGHT0, GL_AMBIENT, G_vLit0Ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, G_vLit0Diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, G_vLit0Specular);
//Setting the textures
loadTexImages();
//开启颜色混合(片元操作:裁剪测试、alpha测试、模板测试、深度测试、混合、抖动、逻辑操作),定义混合因子计算方法
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glLightfv(GL_LIGHT0, GL_POSITION, G_vLit0Position);
glLightfv(GL_LIGHT0, GL_AMBIENT, G_vLit0Ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, G_vLit0Diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, G_vLit0Specular);
//Setting the textures
loadTexImages();
//开启颜色混合(片元操作:裁剪测试、alpha测试、模板测试、深度测试、混合、抖动、逻辑操作),定义混合因子计算方法
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
3. 加载贴图函数
void loadTexImages(void) {
//生成2个贴图存入全局GLuint G_texNameArray[2]
glGenTextures(2, G_texNameArray);
//载入water.tga纹理
glGenTextures(2, G_texNameArray);
//载入water.tga纹理
int nWidth, nHeight, nComponents;
GLenum eFormat;
const char *szFileName = "Textures\\water2.tga";
// 读TGA文件的数据
GLbyte *pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
const char *szFileName = "Textures\\water2.tga";
// 读TGA文件的数据
GLbyte *pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
// 读BMP文件数据方法 AUX_RGBImageRec * pBits =auxDIBImageLoad(_T("tsIcon.bmp"));
if(pBits == NULL)
return;
//切换第二幅贴图为操作贴图,指定显存指针
glBindTexture(GL_TEXTURE_2D, G_texNameArray[1]);
if(pBits == NULL)
return;
//切换第二幅贴图为操作贴图,指定显存指针
glBindTexture(GL_TEXTURE_2D, G_texNameArray[1]);
//根据图像Byte数据生成纹理,根据指针加载到显存
gluBuild2DMipmaps(GL_TEXTURE_2D, nComponents, nWidth, nHeight, eFormat, GL_UNSIGNED_BYTE, pBits);
free(pBits);
}
gluBuild2DMipmaps(GL_TEXTURE_2D, nComponents, nWidth, nHeight, eFormat, GL_UNSIGNED_BYTE, pBits);
free(pBits);
}
/*
* GLubyte checkImage[Height 0xff][Width 0xff][4];
* 遍历像素,二进制某一位隔固定长度切换0/1,异或获得棋盘
* [0][1][2] = c = ( (i&0x8) ^ (j&0x8) ) * 255, alpha[3] = 255
* glBindTexture, glTexImage2D/gluBuild2DMipmaps
*/
4. 显示函数
void display(void) {
//设置清除屏幕的颜色,并清除屏幕和深度缓冲
glClearColor(0.9f,0.9f,0.9f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//设置清除屏幕的颜色,并清除屏幕和深度缓冲
glClearColor(0.9f,0.9f,0.9f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//设置平滑
glShadeModel(GL_FLAT/GL_SMOOTH);
//切换MODELVIEW矩阵堆栈并初始化模型变换矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//坐标中心向Z轴平移-G_fDistance (使坐标中心位于摄像机前方)
glTranslatef(0.0, 0.0, -G_fDistance);
glRotatef(G_fAngle_horizon, 0.0f, 1.0f, 0.0f);
glRotatef(G_fAngle_vertical, 1.0f, 0.0f, 0.0f);
//绘制物体
//设置物体材质参数(和光照glLightfv)类似
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, G_vMaterialSpecu);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 60.0f);
glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
//开启2D贴图并绑定Gen的贴图GLuint
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, G_texNameArray[1]);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, G_texNameArray[1]);
//纹理过滤函数,设置S与T方向的贴图次数、放大缩小的过滤方式(LINEAR4像素加权平均、NEAREST像素中心)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//纹理如何映射到每个像素上,纹理颜色如何影响片元颜色
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//切换TEXTURE矩阵堆栈是下一个矩阵操作的目标
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(G_fWaterTexOffset, 0.0f, 0.0f);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(G_fWaterTexOffset, 0.0f, 0.0f);
//切换MODELVIEW矩阵堆栈是下一个矩阵操作的目标
glMatrixMode(GL_MODELVIEW);
glMatrixMode(GL_MODELVIEW);
//绘制四边形同时绘制绑定的贴图,点坐标和贴图坐标
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, -1.0f, -2.0f);
glTexCoord2f(4.0f, 0.0f); glVertex3f(4.0f, -1.0f, -2.0f);
glTexCoord2f(4.0f, 1.0f); glVertex3f(4.0f, 1.0f, -2.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 1.0f, -2.0f);
glEnd();
//关闭贴图
glDisable(GL_TEXTURE_2D);
//交换前后缓冲区
glutSwapBuffers();
}
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, -1.0f, -2.0f);
glTexCoord2f(4.0f, 0.0f); glVertex3f(4.0f, -1.0f, -2.0f);
glTexCoord2f(4.0f, 1.0f); glVertex3f(4.0f, 1.0f, -2.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 1.0f, -2.0f);
glEnd();
//关闭贴图
glDisable(GL_TEXTURE_2D);
//交换前后缓冲区
glutSwapBuffers();
}
5. 初始化Shader 装载、编译、链接
获取GLuint类型的
点着色器对象G_vShader_simple;面着色器对象G_fShader_simple;着色器程序G_shaderProgram;
// 创建顶点与面片Shader着色器对象
G_vShader_simple = glCreateShader(GL_VERTEX_SHADER);
G_fShader_simple = glCreateShader(GL_FRAGMENT_SHADER);
G_fShader_simple = glCreateShader(GL_FRAGMENT_SHADER);
// 读两个shader命令
char *vs = textFileRead("Shader/simple.vert");
char *vs = textFileRead("Shader/simple.vert");
/* Shader程序直接获取修改全局变量如gl_Position, gl_Vertex等
uniform float time;
void main(void) {
vec4 v = gl_Vertex;
v.z = sin(5.0*v.x + time)*0.25;
gl_Position =gl_ModelViewProjectionMatrix * v;
}
void main(void) {
vec4 v = gl_Vertex;
v.z = sin(5.0*v.x + time)*0.25;
gl_Position =gl_ModelViewProjectionMatrix * v;
}
*/
char *fs = textFileRead("Shader/simple.frag");
const char *vv = vs;
const char *ff = fs;
// 绑定Shader命令
glShaderSource(G_vShader_simple, 1, &vv, NULL);
glShaderSource(G_fShader_simple, 1, &ff, NULL);
free(vs);
free(fs);
// 编译与获得编译结果
glCompileShader(G_vShader_simple);
glCompileShader(G_fShader_simple);
int checkResult;
glGetShaderiv(G_vShader_simple, GL_COMPILE_STATUS, &checkResult);
if(GL_FALSE == checkResult) {
printf("vertex shader compile error\n");
printShaderInfoLog(G_vShader_simple);
}
glGetShaderiv(G_fShader_simple, GL_COMPILE_STATUS, &checkResult);
if(GL_FALSE == checkResult) {
printf("fragment shader compile error\n");
printShaderInfoLog(G_fShader_simple);
}
char *fs = textFileRead("Shader/simple.frag");
const char *vv = vs;
const char *ff = fs;
// 绑定Shader命令
glShaderSource(G_vShader_simple, 1, &vv, NULL);
glShaderSource(G_fShader_simple, 1, &ff, NULL);
free(vs);
free(fs);
// 编译与获得编译结果
glCompileShader(G_vShader_simple);
glCompileShader(G_fShader_simple);
int checkResult;
glGetShaderiv(G_vShader_simple, GL_COMPILE_STATUS, &checkResult);
if(GL_FALSE == checkResult) {
printf("vertex shader compile error\n");
printShaderInfoLog(G_vShader_simple);
}
glGetShaderiv(G_fShader_simple, GL_COMPILE_STATUS, &checkResult);
if(GL_FALSE == checkResult) {
printf("fragment shader compile error\n");
printShaderInfoLog(G_fShader_simple);
}
// 创建一个着色器程序
G_shaderProgram = glCreateProgram();
// 装载着色器对象
glAttachShader(G_shaderProgram, G_vShader_simple);
glAttachShader(G_shaderProgram, G_fShader_simple);
// 链接着色器程序
glLinkProgram(G_shaderProgram);
glGetProgramiv(G_fShader_simple, GL_LINK_STATUS, &checkResult);
if(GL_FALSE == checkResult) {
printf("shader link error\n");
printProgramInfoLog(G_shaderProgram);
}
附获取着色器对象错误Log的程序
void printProgramInfoLog(GLuint programObject) {
GLint logLen = 0, writtenLen;
glGetShaderiv(programObject, GL_INFO_LOG_LENGTH , &logLen);
if (logLen > 0) {
GLchar* info_log = (GLchar*)malloc(logLen);
glGetProgramInfoLog(programObject, logLen, &writtenLen, info_log);
printf("%s\n", info_log);
free (info_log);
}
}
GLint logLen = 0, writtenLen;
glGetShaderiv(programObject, GL_INFO_LOG_LENGTH , &logLen);
if (logLen > 0) {
GLchar* info_log = (GLchar*)malloc(logLen);
glGetProgramInfoLog(programObject, logLen, &writtenLen, info_log);
printf("%s\n", info_log);
free (info_log);
}
}
6. display()函数中采用非固定管线Shader绘制
//用初始化的着色器程序G_shaderProgram画一个茶壶,传入Uniform参数time
static float shaderTime = 0.0f;
glUseProgram(G_shaderProgram);
static float shaderTime = 0.0f;
glUseProgram(G_shaderProgram);
GLint location =glGetUniformLocation(G_shaderProgram,"time");
glUniform1f(location, shaderTime);
glPushMatrix();
glTranslatef(-1.0f, 0.0f, 0.0f);
glutWireTeapot(1.0);
glPopMatrix();
shaderTime += 1.0f;
glUseProgram(0);