OpenGL公转与自转的绘制
2020-07-20 本文已影响0人
ZAREMYDREAM
公转和自转是OpenGL中的一个经典案例,先来看看效果:
效果图
方法分析
1、对图形数据初始化,需要调用setupRC()方法
2、窗口大小变动时,需要调用changeSize(int,int)方法
3、每次绘制时,需要调用RenderScene()方法
4、按键盘移动,需要调用SpecialKey(int,int,int)方法
变量分析
1、地面容器 GLBatch floorBatch
2、红色球体 GLTriangleBatch redBatch
3、蓝色球体 GLTriangleBatch blueBatch
4、 观察者 GLFrame camera
5、远处球体坐标 GLFrame spheres[NUM_SPHERES]
运行流程:
1、main函数中先进行初始化设置
2、在SetupRC中初始化图形参数
3、设置视图尺寸触发changSize()
4、每次渲染时执行RenderScene()
5、键盘输入执行SpecialKey()后,会调用RenderSecene()
6、自转公转需要定时器,定时器每秒钟会触发重新渲染调用RenderSecene()
执行顺序
具体个方法实现
1、main函数
int main(int argc,char *argv[]) {
//初始化GLUT库
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL)
//设置GLUT窗口大小与标题
glutInitWindowSize(1920, 1080);
glutCreateWindow("Floor");
//指定窗口改变时调用的方法
glutReshapeFunc(changeSize);
//指定渲染时调用的方法
glutDisplayFunc(RenderScene);
//指定键盘输入时调用的方法
glutSpecialFunc(SpecialKey);
//判断驱动器有没有问题
GLenum status = glewInit();
if (GLEW_OK != status) {
return 0;
}
//初始化渲染环境
setupRC();
//执行loop循环
glutMainLoop();
return 0;
}
2、changsize函数
void changeSize(int w,int h) {
//设置窗口
glViewport(0, 0, w, h);
//设置投影矩阵,因为投影矩阵需要窗口长宽比,所以在changsize中设置
viewFrustum.SetPerspective(35, float(w)/float(h), 1, 100);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//模型矩阵,视图矩阵加入管道,便于取用
transform.SetMatrixStacks(modelMatrix, projectionMatrix);
}
3、setupRC函数
void setupRC() {
//清除遗留背景色并设置背景色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//初始化着色器
shaderManager.InitializeStockShaders();
//开启深度测试
glEnable(GL_DEPTH_TEST);
camera.RotateWorld(float(m3dDegToRad(180.0f)), 0, 1, 0);
//地面的坐标
floorBatch.Begin(GL_LINES, 324);
for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5) {
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();
//红球
gltMakeSphere(redBatch, 0.5f, 100, 100);
//蓝球
gltMakeSphere(blueBatch, 0.1f, 20, 20);
//随机位置放置蓝球
for (int i = 0; i < NUM_SPHERES; i++) {
//y轴不变,X,Z产生随机值
GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
//在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
//对spheres数组中的每一个顶点,设置顶点数据
spheres[i].SetOrigin(x, 0.0f, -z);
}
}
4、SpecialKey函数
void SpecialKey(int keys, int x, int y) {
//每次移动的距离
GLfloat line = 1;
//每次旋转的弧度
float angular = float(m3dDegToRad(5.0f));
if (keys == GLUT_KEY_UP) {
camera.MoveForward(line);
}
if (keys == GLUT_KEY_DOWN) {
camera.MoveForward(-line);
}
if (keys == GLUT_KEY_LEFT) {
camera.RotateWorld(angular, 0, 1, 0);
}
if (keys == GLUT_KEY_RIGHT) {
camera.RotateWorld(-angular, 0, 1, 0);
}
}
5、RenderScene函数
void RenderScene(void) {
//清空颜色缓存区和深度缓存区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//地板颜色
static GLfloat floorC[] = {0,1,0,1};
//红球颜色
static GLfloat redC[] = {1,0,0,1};
//篮球颜色
static GLfloat blueC[] = {0,0,1,1};
//定时器
static CStopWatch timer;
float yRot = timer.GetElapsedSeconds()*60;
//光源位置
M3DVector4f light = {0.0f,10.0f,5.0f,1.0f};
//拷贝一份栈顶的状态并放入栈顶
modelMatrix.PushMatrix();
//观察者移动
M3DMatrix44f mCamera;
camera.GetMatrix(mCamera);
modelMatrix.PushMatrix(mCamera);
//绘制地面
shaderManager.UseStockShader(GLT_SHADER_FLAT, transform.GetModelViewProjectionMatrix(),floorC);
floorBatch.Draw();
//红球
//红球向屏幕内移动
modelMatrix.Translate(0, 0, -3);
//红球自转需要保存自转前的状态,先进行拷贝入栈
modelMatrix.PushMatrix();
//红球自转
modelMatrix.Rotate(yRot, 0, 1, 0);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transform.GetModelViewMatrix(), transform.GetProjectionMatrix(), light, redC);
redBatch.Draw();
modelMatrix.PopMatrix();
//蓝色小球
for (int i = 0; i < NUM_SPHERES; i++) {
modelMatrix.PushMatrix();
modelMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transform.GetModelViewMatrix(), transform.GetProjectionMatrix(), light, blueC); blueBatch.Draw();
modelMatrix.PopMatrix();
}
//公转
modelMatrix.Rotate(yRot*-3.0, 0, 1, 0);
modelMatrix.Translate(0.8f, 0, 0);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transform.GetModelViewMatrix(), transform.GetProjectionMatrix(), light, blueC);
blueBatch.Draw();
modelMatrix.PopMatrix();
modelMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}