[demo5].不画甜甜圈的吃货不是好的程序猿
2020-07-09 本文已影响0人
NealDN
复习下基本流程
初始化glut模块
加载配置模块
设置窗口大小
给窗口取个名字
注册一个方法监测窗口改变
注册一个方法监测键盘输入
注册一个方法监测屏幕刷新
初始化glew模块并检测是否初始化成功
设置默认值(环境)
加载并启动MainLoop
实际上并不需要完全按照上面的步骤来做,像注册监测的那三个方法可以自由变换顺序。
具体代码:
//着色器管理类
GLShaderManager shaderManager;
//甜甜圈容器
GLTriangleBatch donutBatch;
//窗口改变
void ChangeSize(int w, int h) { }
//监测键盘输入信号
void SpecialKeys(int key, int x, int y) { }
//屏幕刷新
void RenderScene() { }
//初始化相关工作
void SetupRC() { }
int main( int argc, char *argv[]) {
gltSetWorkingDirectory(argv[0]);
//初始化glut模块
glutInit(&argc, argv);
//加载配置模块
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//设置窗口大小
glutInitWindowSize(400, 400);
//给窗口取个名字
glutCreateWindow("There is a donut here");
//注册一个方法监测窗口改变
glutReshapeFunc(ChangeSize);
//注册一个方法监测键盘输入
glutSpecialFunc(SpecialKeys);
注册一个方法监测屏幕刷新
glutDisplayFunc(RenderScene);
//初始化glew模块并检测是否初始化成功
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//设置默认值(环境)
SetupRC();
//加载并启动MainLoop
glutMainLoop();
return 0;
}
绘制甜甜圈的准备工作
1.因为这次是要画一个可以展览的甜甜圈(不然就没有灵魂了),所以我们需要有一个观察者,也就是摄影师(观察者坐标系)
,且观察者自身也有一个属性(物体坐标系)
GLMatrixStack cameraMatix;
GLFrame cameraFrame;
2.而甜甜圈自身也是有大小的,所以我们需要描绘甜甜圈的属性(物体坐标系)
GLMatrixStack donutMatrix;
3.在将甜甜圈转化为世界坐标系的时候,需要设置甜甜圈的投影规则(称之为管线
)
GLGeometryTransform donutTransform;
4.这次需要绘制的是立体的甜甜圈,所以为了有立体感,需要设置投影方式为透视投影
,为此,我们需要设置一个全局变量用于记录当前透视状态
GLFrustum viewFrustum;
初始化工作
在SetupRC
中需要设置背景颜色,初始化全局变量
glClearColor(240/255.0, 248/255.0, 255/255.0, 1.0f);
shaderManager.InitializeStockShaders();
//将相机向后移动7个单元:肉眼到物体之间的距离
cameraFrame.MoveForward(7.0);
//创建一个甜甜圈
//void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
//参数1:GLTriangleBatch 容器帮助类
//参数2:外边缘半径
//参数3:内边缘半径
//参数4、5:主半径和从半径的细分单元数量
gltMakeTorus(donutBatch, 1.0f, 0.3f, 52, 26);
窗口改变时
//1.防止h变为0
if(h == 0)
h = 1;
//2.设置视口窗口尺寸
glViewport(0, 0, w, h);
//3.setPerspective函数的参数是一个从顶点方向看去的视场角度(用角度值表示)
// 设置透视模式,初始化其透视矩阵
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
//4.把透视矩阵加载到透视矩阵对阵中
donutMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//5.初始化渲染管线
donutTransform.SetMatrixStacks(cameraMatix, donutMatrix);
屏幕刷新时
//1.清除窗口和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//2.把摄像机矩阵压入模型矩阵中
cameraMatix.PushMatrix(cameraFrame);
//3.设置绘图颜色
GLfloat colorDonut[] = { 255/255.0, 215/255.0, 0/255.0, 1.0f };
//4.
//使用平面着色器
//参数1:平面着色器
//参数2:模型视图投影矩阵
//参数3:颜色
// shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
//使用默认光源着色器
//通过光源、阴影效果跟提现立体效果
//参数1:GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
//参数2:模型视图矩阵
//参数3:投影矩阵
//参数4:基本颜色值
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, donutTransform.GetModelViewMatrix(), donutTransform.GetProjectionMatrix(), colorDonut);
//5.绘制
donutBatch.Draw();
//6.出栈 绘制完成恢复
cameraMatix.PopMatrix();
//7.交换缓存区
glutSwapBuffers();
不会动的甜甜圈
Run一下,发现甜甜圈出现了,开心~
但是,这是一个不会动的甜甜圈!!!
为了让他动起来,我们必须进行操作
在SpecialKey
中
//监测键盘输入信号
void SpecialKeys(int key, int x, int y) {
//w 设置为后空翻吧,就是围绕x轴向后旋转
if(key == 119)
cameraFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
//s 设置为前空翻吧,就是围绕x轴向前旋转
if(key == 115)
cameraFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);
//a 设置为直立顺时针转圈,就是围绕y轴顺时针旋转
if(key == 97)
cameraFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);
//d 设置为直立顺时针转圈,就是围绕y轴逆时针旋转
if(key == 100)
cameraFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);
//q 设置为正向中心顺时针转圈,就是围绕z轴逆时针旋转
if(key == 113)
cameraFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 0.0f, 1.0f);
//e 设置为正向中心逆时针转圈,就是围绕z轴逆时针旋转
if(key == 101)
cameraFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 0.0f, 1.0f);
//3.重新刷新
glutPostRedisplay();
}
再Run一下,棒~想要的效果出来了!👏👏👏👏👏
又又又又又但是!在旋转的时候,出现了很多黑色的东西,色香味色先挂了,哪里还有食欲?想要解决它,首先得了解它是什么。
在现实世界中,一个甜甜圈还没开始吃的时候,应该只能看到它脆脆的皮,而不可能看到它松松的肉,但是在我们绘制的甜甜圈中,我们看到了它松松的肉,这是不正常的。
在OpenGL的世界中,所描绘的每一个物体都是有它的正面和背面的,正面不会被遮挡,而背面会被遮挡住,用这样的方式来模拟现实世界中不透明的物体的成像。
因此现在的这种情况,我们只需要打开OpenGL自身的
背面剔除
功能就好了,所以在RenderScene
绘制的时候我们需要设置背面剔除
.
glEnable(GL_CULL_FACE);
再run一次,发现不再出现黑色了,👏👏👏👏👏
但是又来了,这次,黑色没有了,可旋转到某一个方向的时候,出现了透视的现象,这是为什么呢?
在这次的甜甜圈的世界里,因为采用的是油画的画法,即先画底下涂层的,再画上面涂层,因此,图形的正面与背面是已经设定好了的,所以在旋转的时候,由于正面位于背面的涂层下面,但是正面是不会被背面所遮挡的,所以便出现了透视的效果
该怎么做呢?先看一下下一篇OpenGL的深度测试把,深度测试可以帮我们定位很多问题!