效果:
详细代码见githup:
MirrorSphere
实现思路:
这里讲几个主要的方法及注意点:
键盘命令监听:
这里监听键盘的上下左右几个操作,相应的改变观察者的位置.
void SpeacialKeys(int key,int x,int y)
{
float linear = 0.1f;
float angular = float(m3dDegToRad(5.0f));
if (key == GLUT_KEY_UP) {
//MoveForward 平移
cameraFrame.MoveForward(linear);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(-linear);
}
if (key == GLUT_KEY_LEFT) {
//RotateWorld 旋转
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}
}
设置顶点:
根据gif显示,需要展示的有:
1.自转的大球
2.围绕大球公转的小球
3.其它悬浮不动的小球
4.地板
5.地板之下的各种球(gif的镜面效果,实际上是在地板下把全部的球再画一遍,配合颜色混合,展示出镜面效果,这里可以直接复用球的顶点数据,再围绕y轴做翻转和平移即可,不需要额外设置顶点).
//设置大球顶点
void setBigSphereVertex(){
//60是径向的,80是横向的,都是越大球越圆
gltMakeSphere(bigSphereBatch, 0.5f, 60, 80);
}
//设置小球顶点
void setSmallSphereVertex(){
gltMakeSphere(smallSphereBatch, 0.2, 30, 40);
}
//设置龙套小球的顶点
void setOtherSphereVertex(){
gltMakeSphere(otherSphereBatch, 0.2, 20, 40);
//7.随机小球球顶点坐标数据
for (int i = 0; i < NUM_SPHERES; i++) {
//y轴不变,X,Z产生随机值
GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
GLfloat y = (GLfloat)((rand() % 4));
GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
//在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
//对spheres数组中的每一个顶点,设置顶点数据
spheres[i].SetOrigin(x, y, z);
}
}
//设置地板顶点
void setFloorVertex(){
GLfloat texSize = 10.0f;
floorBatch.Begin(GL_TRIANGLE_FAN, 4,1);
floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);
floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
floorBatch.Vertex3f(20.0f, -0.41f, 20.f);
floorBatch.MultiTexCoord2f(0, texSize, texSize);
floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
floorBatch.End();
}
场景渲染
注意点在代码注释中已经标明
//绘制场景
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//这次压栈是为了接收到键盘命令时,移动观察者
//ps:这个PushMatrix()函数会自动帮我们把栈顶的元素copy一份,然后压入栈中,配合PopMatrix()函数,能让变化只在push和pop之间有效,pop之后恢复原值;这样设计能把不同物体的渲染独立开,不会相互影响.
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
//从cameraFrame取值,然后赋值给矩阵mCamera
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);
//绘制镜面开始
modelViewMatrix.PushMatrix();
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
modelViewMatrix.Translate(0.0f, 1.0f, -1.0f);
//指定顺时针为正面,因为物体翻转了,否则看到的是背面
glFrontFace(GL_CW);
drawBigSphere();
drawSmallSphere();
drawOtherSphere();
//恢复为逆时针为正面
glFrontFace(GL_CCW);
//绘制镜面结束
modelViewMatrix.PopMatrix();
//开启混合
glEnable(GL_BLEND);
//指定glBlendFunc 颜色混合方程式
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawFloor();
//取消混合
glDisable(GL_BLEND);
//整体上移,否则大球会被地板挡住
modelViewMatrix.Translate(0.0f, 0.1f, -1.0f);
drawBigSphere();
drawSmallSphere();
drawOtherSphere();
//不能太早pop,这个观察者是针对所有的物体的
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}