OpenGL 球体公转+自转案例
2020-07-23 本文已影响0人
_涼城
声明变量
声明一个着色器管理器实例,为模型视图矩阵和投影矩阵声明GLMatrixStack
实例,使用GLFrustum
类构造投影矩阵,最后用GLGeometryTransform
类声明一个管线实例管理矩阵堆栈。
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
初始化工程
绘制地板
绘制地板流程.png声明批次类容器实例
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();
平面着色器绘制地板
static GLfloat vFloorColor[] = { 0.0f,1.0f,0.0f,1.0f };
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
floorBatch.Draw();
绘制自转球
绘制自转球流程图.png声明批次类容器实例
GLTriangleBatch torusBatch;
//角度
GLfloat yRot;
设置大球模型
gltMakeSphere(torusBatch, 0.4f, 40, 80);
RenderScene
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
//2.基于时间动画
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
//** 压栈
modelViewMatrix.PushMatrix();
//4.获取光源位置
M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
//5.使得大球位置平移(3.0)向屏幕里面
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
//6.压栈(复制栈顶)
modelViewMatrix.PushMatrix();
//7.大球自转
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
//8.指定合适的着色器(点光源着色器)
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
torusBatch.Draw();
//9.绘制完毕则Pop
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
glutSwapBuffers();
//提交重新渲染
glutPostRedisplay();
绘制静态球
绘制静态球流程图.png声明批次类容器实例
GLTriangleBatch sphereBatch;
//随机球个数
#define NUM_SPHERES 50
//随机球顶点数组
GLFrame spheres[NUM_SPHERES];
初始化
//设置小球模型
gltMakeSphere(sphereBatch, 0.1f, 13, 26);
//绘制小球顶点坐标
for (int i = 0; i < NUM_SPHERES; i++) {
//y轴一致
GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
spheres[i].SetOrigin(x,0.0f,z);
}
RenderScene
/*
绘制小球
*/
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,vSmallSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
绘制公转球
绘制公转球流程图.pngRenderScene
/*
绘制运动的小球
*/
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot * -2, 0, 1, 0);
modelViewMatrix.Translate(0.8f, 0.0f,0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSmallSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
设置特殊键位调整观察者位置
调整观察者位置
//移动(移动只是计算了X,Y移动的距离,以及碰撞检测)
void SpecialKeys(int key, int x, int y)
{
float linear = 0.1f;
float angular = float(m3dDegToRad(5.0f));
if (key == GLUT_KEY_UP) {
cameraFrame.MoveForward(linear);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(-linear);
}
if (key == GLUT_KEY_LEFT) {
cameraFrame.RotateWorld(angular, 0, 1, 0);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0, 1, 0);
}
}
渲染
//在渲染前,调整观察者位置
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);
最后附上完整代码
#include "GLTools.h"
#include "GLShaderManager.h"
#include "math3d.h"
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <GLFrustum.h>
#include <StopWatch.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
GLTriangleBatch torusBatch;
GLTriangleBatch sphereBatch;
GLBatch floorBatch;
GLfloat yRot;
//观察者
GLFrame cameraFrame;
//随机球
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
void SetupRC()
{
//设置清屏颜色(背景颜色)
glClearColor(0.0f, 0.0f, 0.0f, 1);
//没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。
//在前面的课程,我们会采用固管线渲染,后面会学着用OpenGL着色语言来写着色器
shaderManager.InitializeStockShaders();
//投影变换矩阵 & 移动变换矩阵 > 变换管道 > 快速去矩阵相乘 > 遍历
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//绘制地板
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++) {
//y轴一致
GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
spheres[i].SetOrigin(x,0.0f,z);
}
}
//移动(移动只是计算了X,Y移动的距离,以及碰撞检测)
void SpecialKeys(int key, int x, int y)
{
float linear = 0.1f;
float angular = float(m3dDegToRad(5.0f));
if (key == GLUT_KEY_UP) {
cameraFrame.MoveForward(linear);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(-linear);
}
if (key == GLUT_KEY_LEFT) {
cameraFrame.RotateWorld(angular, 0, 1, 0);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0, 1, 0);
}
}
//进行调用以绘制场景
void RenderScene(void)
{
static GLfloat vFloorColor[] = { 0.0f,1.0f,0.0f,1.0f };
static GLfloat vBigSphereColor[] = {1.0f,0.0f,0.0f,1.0f};
static GLfloat vSmallSphereColor[] = {0.0f,0.0f,1.0f,1.0f};
//定时器
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// //颜色值
glEnable(GL_DEPTH_TEST);
M3DVector4f vLightPos = {
0.0,10.0,5.0,1.0
};
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);
// //基于时间的动画
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
floorBatch.Draw();
// //绘制旋转的
modelViewMatrix.Translate(0.0, 0.0, -3.0f);
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vBigSphereColor);
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(),vLightPos,vSmallSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
/*
绘制运动的小球
*/
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot * -2, 0, 1, 0);
modelViewMatrix.Translate(0.8f, 0.0f,0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSmallSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
//出栈
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
glDisable(GL_DEPTH_TEST);
glutSwapBuffers();
glutPostRedisplay();
}
// 屏幕改变大小或初始化
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//创建投影矩阵,并将它载入投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w) / (float)h, 1.0f, 100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//设置变换管线以使用两个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("Move Block with Arrow Keys");
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
SetupRC();
glutMainLoop();
return 0;
}