效果
流程图
初始化
-
main()
中注册一系列回调和初始化方法
-
ChangeSize()
设置视图大小、投影矩阵、变换管道
绘制地板
-
setupRC()
背景色、固定着色器初始化、顶点数据
-
RenderScene()
清理颜色缓冲区、清理深度缓冲区、固定着色器绘制地板、交换缓冲区
绘制大球
-
setupRC()
背景色、固定着色器初始化、开启深度测试、设置顶点数据
-
RenderScene()
清理颜色缓冲区、清理深度缓冲区、定时器、大球自转、点光源着色器绘制大球、压栈-出栈、重新渲染
绘制小球
-
setupRC()
背景色、固定着色器初始化、开启深度测试、设置顶点数据
-
RenderScene()
清理颜色缓冲区、清理深度缓冲区、定时器、点光源着色器绘制小球、小球围绕大球公转、压栈-出栈、重新渲染
移动
-
SpeacialKeys()
键位监听并移动观察者
-
RenderScene()
加入观察者并将其压栈
代码
#include "GLGeometryTransform.h"
#include "GLShaderManager.h"
#include "GLMatrixStack.h"
#include "StopWatch.h"
#include "GLFrustum.h"
#include "GLFrame.h"
#include "GLBatch.h"
#include <math.h>
#include <stdio.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
/*
在Mac 系统下,`#include<glut/glut.h>`
在Windows 和 Linux上,我们使用freeglut的静态库版本并且需要添加一个宏
*/
// 各种需要的类
GLShaderManager shaderManager; //着色器
GLMatrixStack modelViewMatrix; //模型视图矩阵
GLMatrixStack projectionMatrix; //投影矩阵
GLFrame cameraFrame; //观察者
GLFrame objectFrame; //物体移动信息
GLGeometryTransform transformPipeline; // 几何图形变换管道
//投影矩阵
GLFrustum viewFrustum;
//
GLTriangleBatch torusBatch; //大球
GLTriangleBatch sphereBatch; //小球
GLBatch floorBatch; //地板
//**4、添加小球个数
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
/*
在窗口大小改变时,接收新的宽度&高度。
*/
void ChangeSize(int w,int h)
{
//设置视图大小
glViewport(0, 0, w, h);
//设置透视投影矩阵
viewFrustum.SetPerspective(35, float(w)/float(h), 1, 100);
//加载投影矩阵
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 设置变换管道以使用两个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
//初始化
void setupRC()
{
//清理背景颜色
glClearColor(0.0f, 0.0f, 0.0f, 1);
//初始化固定着色器
shaderManager.InitializeStockShaders();
//开启深度测试
glEnable(GL_DEPTH_TEST);
//设置地板顶点数据
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(torusBatch, 0.4f, 40, 80);
//设置小球顶点数据
gltMakeSphere(sphereBatch, 0.1f, 13, 26);
for (int i = 0; i < NUM_SPHERES; i++) {
//产生X、Z轴随机值
GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
//设置小球模型矩阵
spheres[i].SetOrigin(x,0.0f,z);
}
}
//调用绘制场景
void RenderScene(void)
{
//清理 颜色缓冲区 深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//设置地板颜色
static GLfloat vFloorColor[] = {0.0f,1.0f,0.0f,1.0f};
//设置大球颜色
static GLfloat vTorusColor[] = {1.0f,1.0f,0.0f,1.0f};
//设置小球颜色
static GLfloat vSphereColor[] = {0.0f,1.0f,1.0f,1.0f};
//压栈 --
modelViewMatrix.PushMatrix();
//加入观察者,压栈
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);
//使用平面着色器 绘制地板
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
//绘制
floorBatch.Draw();
//大球自转 定时器
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
//点光源 位置
M3DVector4f vLightPots = {0.0f,10.0f,5.0f,1.0f};
//大球往Z轴平移
modelViewMatrix.Translate(0, 0, -3.0f);
//压栈 --
modelViewMatrix.PushMatrix();
//大球 围绕Y轴 自转
modelViewMatrix.Rotate(yRot, 0, 1, 0);
//点光源着色器 绘制
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPots,vTorusColor);
torusBatch.Draw();
//出栈
modelViewMatrix.PopMatrix();
//绘制小球
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(),vLightPots,vTorusColor);
sphereBatch.Draw();
//出栈
modelViewMatrix.PopMatrix();
}
//这里不需要压栈 是因为这是最后一个绘制,不会再影响其他的绘制
//让一个小球围绕大球公转自转
modelViewMatrix.Rotate(yRot * -2, 0, 1, 0);
//小球平移
modelViewMatrix.Translate(0.8f, 0, 0);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPots,vSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
//执行交换缓冲区
glutSwapBuffers();
//重新渲染
glutPostRedisplay();
}
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);
}
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
//申请一个颜色缓存区、深度缓存区、双缓存区、模板缓存区
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//设置window 的尺寸
glutInitWindowSize(800, 600);
//创建window的名称
glutCreateWindow("GL_POINTS");
//注册回调函数(改变尺寸)
glutReshapeFunc(ChangeSize);
// //点击空格时,调用的函数
// glutKeyboardFunc(KeyPressFunc);
//特殊键位函数(上下左右)
glutSpecialFunc(SpeacialKeys);
//显示函数
glutDisplayFunc(RenderScene);
//判断一下是否能初始化glew库,确保项目能正常使用OpenGL 框架
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//绘制
setupRC();
//runloop运行循环
glutMainLoop();
return 0;
}
网友评论