实现效果

学习OpenGL也有一段时间了。今天使用三个批次类来完成一个球体世界的demo;
球体世界网格层面
网格地面的构建使用GLBatch floorBatch
定义的批次类
首先绘制网格层面
- 网格层面顶点构建
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();
- 绘制网格层面
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 网格层面颜色
static GLfloat vFloorColor[] = {0.0f,1.0f,0.0f,1.0f};
//网格层面绘制;
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vFloorColor);
floorBatch.Draw();
glutSwapBuffers();
绘制灰白的大球
- 我们使用
GLTriangleBatch torusBatch
定义的批次类来绘制大球
大球的构建我们使用GLTools
提供的构建函数gltMakeSphere(torusBatch, 0.4f, 40, 80)
,参数解释:
参数 | 解释 |
---|---|
GLTriangleBatch sphereBatch |
存放球体顶点数据的批次类 |
GLfloat fRadius |
球体半径 |
GLint iSlices |
片段数(越大越圆) |
GLint iStacks |
堆叠数 |
- 开始绘制大球
//大球颜色
static GLfloat vMaxBallColor[] = {0.85f, 0.85f, 0.85f, 1.0f};
//构建动画
static CStopWatch rotTimmer;
float yRot = rotTimmer.GetElapsedSeconds() * 60.0f;
// 压栈(在保留操作之后,push还原)
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
//5. 设置点光源位置
M3DVector4f vLightPos = {0,10,5,1};
// 使得整个大球往里平移3.0
modelViewMatrix.Translate(0.0f, 0.0f, -4.0f);
// 再次压栈,防止每次renderSence重复操作平移矩阵
modelViewMatrix.PushMatrix();
//自转
modelViewMatrix.Rotate(yRot, 0, 1, 0);
//绘制
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vMaxBallColor);
torusBatch.Draw();
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
//提交重新渲染
glutPostRedisplay();
零散的小球(处于同一平面)
- 使用
GLTriangleBatch sphereBatch
批次类来存放小球的顶点数据 - 构建小球顶点数据
gltMakeSphere(sphereBatch, 0.2f, 40, 80);
- 构建同一平面的50个随机点
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);
}
- 小球的绘制
for (int i = 0; i < NUM_SPHERES; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vMinBallColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
- 绘制围绕大球公转的小球
//小球的旋转方向为大球的自转的逆向
modelViewMatrix.Rotate(yRot * -2.5f, 0, 1, 0);
//大球的半径为0.4,小球的半径为0.2,所有小球需要从在x轴的方向做平移变换大于0.6
modelViewMatrix.Translate(0.7f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vMinBallColor);
sphereBatch.Draw();
特殊键位的处理
- 我们只需要对我们的观察者矩阵进行变换,就能模拟出前进,后退,旋转的效果,上代码:
//定义步长
float linear = 0.1f;
//定义每次旋转的角度
float angular = float(m3dDegToRad(6.0f));
if (key == GLUT_KEY_UP) {
cameraFrame.MoveForward(linear);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(-linear);
}
//只围绕y轴转,模拟人眼同一水平旋转效果
if (key == GLUT_KEY_LEFT) {
cameraFrame.RotateWorld(angular, 0, 1, 0);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0, 1, 0);
}
至此,已完成整个项目核心代码的构建。
最后附上完整demo:OpenGL球体世界案例
网友评论