本文致谢Brother Teeth.
下载库:链接: https://pan.baidu.com/s/1FJ3Na8vZTfdONeAqW4mjuw 提取码: 3rs2
环境配置参考上一篇博客:https://blog.csdn.net/uiop_uiop_uiop/article/details/102561062
时间紧,不多写了,直接看注释。
#include <windows.h>
#include <stdio.h>
#include<math.h>
#include<stdlib.h>
#include "GL\gl.h"
#include "GL\glu.h"
#include "GL\glaux.h"
#include "GL\glut.h"
bool pause;
bool light;
const float PI = 3.1415926;
int xAngle;//x轴向角度
int yAngle;//y轴向角度
float xRadian;//x轴向弧度
float yRadian;//y轴向弧度
float distance;//间距
int rotateSpeedSleep;//旋转速度
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // 环境光参数
GLfloat LightDiffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // 漫射光参数
GLfloat LightPosition[] = { 0.0f, 10.0f, 0.0f, 1.0f }; // 光源位置
GLuint filter; // 滤波类型
GLuint texture[3]; // 3种纹理的储存空间
GLfloat rx, ry, rz; // 物体 旋转
GLdouble size; // 物体尺寸
GLfloat ox = 0.0f, oy = 0.0f, oz = 0.0f; //物体位置
GLfloat cx = 0.0f, cy = 0.0f, cz = 5.0f;//摄像机位置
GLfloat cvx = 0.0f, cvy = 0.0f, cvz = -1.0f;//摄像机视线向量
GLfloat chx = 0.0f, chy = 1.0f, chz = 0.0f;//摄像机头顶朝向向量
GLfloat w_h_ratio;//长宽比
void variateInit() {
pause = true;
light = true;
rx = ry = rz = 0.0f;
size = 1.0f;
xAngle = 0;
yAngle = 30;
cz = distance = 15.0f;
rotateSpeedSleep = 20;
}
// 载入位图图象
AUX_RGBImageRec* LoadBMP(char* Filename)
{
FILE* File = NULL; // 文件句柄
if (!Filename) // 确保文件名已提供
{
return NULL; // 如果没提供,返回 NULL
}
int errNum = fopen_s(&File,Filename, "r"); // 尝试打开文件
if (File) // 文件存在么?
{
fclose(File); // 关闭句柄
return auxDIBImageLoad(Filename); // 载入位图并返回指针
}
return NULL; // 如果载入失败,返回 NULL
}
// 载入位图(调用上面的代码)并转换成纹理
int LoadGLTextures()
{
int Status = FALSE; // 状态指示器
AUX_RGBImageRec* TextureImage[1]; // 创建纹理的存储空间
memset(TextureImage, 0, sizeof(void*) * 1); // 将指针设为 NULL
// 载入位图,检查有错,或位图不存在的话退出
if (TextureImage[0] = LoadBMP((char*)"2.bmp")) //Both length and width of the image's pixels should be the times of 2.
{
Status = TRUE; // 状态设为 TRUE
glGenTextures(3, &texture[0]); // 创建纹理
// 创建 Nearest 滤波贴图
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// 创建线性滤波纹理
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// 创建 MipMapped 纹理
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
}
if (TextureImage[0]) // 纹理是否存在
{
if (TextureImage[0]->data) // 纹理图像是否存在
{
free(TextureImage[0]->data); // 释放纹理图像占用的内存
}
free(TextureImage[0]); // 释放图像结构
}
return Status; // 返回 Status
}
// 初始化OpenGL设置
int myInit(GLvoid)
{
variateInit();
if (!LoadGLTextures()) // 调用纹理载入子例程
{
return FALSE; // 如果未能载入,返回FALSE
}
glEnable(GL_TEXTURE_2D); // 启用纹理映射
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
glClearDepth(1.0f); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); // 设置环境光
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); // 设置漫射光
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition); // 设置光源位置
glEnable(GL_LIGHT0); // 启用0号光源
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glColor4f(1.0f, 1.0f, 1.0f, 0.5f); // 全亮度, 50% Alpha 混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // 基于源象素alpha通道值的半透明混合函数
return TRUE; // 初始化 OK
}
void drawTeapot(void)
{
glPushMatrix();
glutSolidTeapot(size);
glPopMatrix();
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
/*gluLookAt(cx, cy, cz,
0.0f, 0.0f, 0.0f,
chx, chy, chz);*/ //Camera follows the World's Zero.
gluLookAt(cx, cy, cz,
ox, oy, oz,
chx, chy, chz); //Set the camera follows the object
glBegin(GL_QUADS); //Draw the square.
glVertex3f(-5.0f, -5.0f, -5.0f);
glVertex3f(-5.0f, -5.0f, 5.0f);
glVertex3f(5.0f, -5.0f, 5.0f);
glVertex3f(5.0f, -5.0f, -5.0f);
glEnd();
glTranslatef(ox, oy, oz); // 移入/移出屏幕 z 个单位
glRotatef(rx, 1.0f, 0.0f, 0.0f); // 绕X轴旋转
glRotatef(ry, 0.0f, 1.0f, 0.0f); // 绕Y轴旋转
glRotatef(rz, 0.0f, 0.0f, 1.0f); // 绕Z轴旋转
glBindTexture(GL_TEXTURE_2D, texture[filter]); // 选择由filter决定的纹理
drawTeapot();
glutSwapBuffers();
}
void rotateCamera(int x, int y) {
cvx += x * 0.01;
cvy += y * 0.01;
}
void moveCamera(int x, int y, int z) {
cx += x * 0.1;
cy += y * 0.1;
cz += z * 0.1;
}
//灯光 控制
void lightControl() {
light = !light;
if (light)glEnable(GL_LIGHTING);
else glDisable(GL_LIGHTING);
}
void myKeyboard(unsigned char key, int x, int y) {
switch (key)
{
//控制移动
case 'a':ox -= 0.1f; break;
case 'd':ox += 0.1f; break;
case 'q':oy += 0.1f; break;
case 'z':oy -= 0.1f; break;
case 'w':oz -= 0.1f; break;
case 's':oz += 0.1f; break;
//控制旋转
case 'f':rx += -1; break;
case 'h':rx += 1; break;
case 'r':ry += 1; break;
case 'v':ry += -1; break;
case 't':rz += -1; break;
case 'g':rz += 1; break;
//控制大小
case 'j':size += -0.1; break;
case 'l':size += 0.1; break;
//控制摄像头
case '4':rotateSpeedSleep -= 1; break;
case '6':rotateSpeedSleep += 1; break;
case '7':yAngle += 1; break;
case '1':yAngle += -1; break;
case '8':distance -= 0.5f; break;
case '5':distance += 0.5f; break;
//灯光的开闭
case 'o':lightControl(); break;
//摄像头移动的暂停
case 'p':pause = !pause; break;
//退出程序
case 27:exit(0); break;
}
}
void myIdle(void)
{
Sleep(rotateSpeedSleep);
//摄像头x轴向旋转控制
if (!pause)xAngle++;
if (xAngle >= 360)xAngle = 0;
//if (xAngle < 0)xAngle = 359;
//radian = angle / 360.0f * 2 * PI;
xRadian = xAngle * PI / 180.0f;
//摄像头y轴向旋转控制
yRadian = yAngle * PI / 180.0f;
cx = distance * cos(yRadian) * sin(xRadian);
//cz = distance * cos(xRadian);
cy = distance /** cos(xRadian) */ * sin(yRadian);
cz = distance * cos(xRadian) * cos(yRadian);
myDisplay();
}
void myReshape(int w, int h) {
if (h == 1)h = 1;
w_h_ratio = 1.0f * w / h;
//修改前重置坐标系统
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//设置视口为整个窗口大小
glViewport(0, 0, w, h);
//设置可视空间
gluPerspective(45, w_h_ratio, 1, 1000);
glMatrixMode(GL_MODELVIEW);
/*glLoadIdentity();
gluLookAt(cx, cy, cz,
cx + cvx, cy + cvy, cz + cvz,
chx, chy, chz);*/
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv); //Library Init
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); //Dual Buf
glutInitWindowPosition(200, 200); //Locate window position
glutInitWindowSize(640, 480); //Set window size
glutCreateWindow("OpenGL Graphic Experiment");
myInit(); //Init
glutKeyboardFunc(&myKeyboard); //Bind keyboard function
glutDisplayFunc(&myDisplay); //Bind display loop function
glutIdleFunc(&myIdle); //Bind Idle loop function
glutReshapeFunc(&myReshape); //Bind, called when Window size changed
glutMainLoop(); //Fall into mainloop
return 0;
}