上一篇文章已经简单介绍了OpenGL的环境搭建、并且画出了一个三角形,今天这篇文章,就在三角形的基础上,把三角形变成金字塔吧。效果图如下
在这之前建议先看看这篇文章 《OpenGL / OpenGL ES 下专业名词解析》
了解一下。
搭出金字塔的需求
简单构思一下
- 我们要搭成这么一个金字塔,至少需要4面三角形。
- 我们需要让这个金字塔动起来,看他的效果,要不然运行起来就只是一个三角形而已。
属性声明
// 存储着色器管理工具类
GLShaderManager shaderManager;
// 投影矩阵堆栈
GLMatrixStack modelViewMatrix;
// 模型视图矩阵堆栈
GLMatrixStack projectionMatrix;
// 设置观察者坐标
GLFrame cameraFrame;
// 设置图形环绕时,视图坐标
GLFrame objectFrame;
//设置图片绘制时的投影方式
GLFrustum viewFrustum;
//容器类
GLBatch triangleBatch
//几何变换的管道
GLGeometryTransform transformPipeline;
//一个黑色 一个绿色
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
main方法
刚开始的时候,main方法基本上就都是这几个方法
(到后面会不会变我就不知道了 ^ _ ^)
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_TRIANGLES");
//注册回调函数(改变尺寸)
glutReshapeFunc(ChangeSize);
//特殊键位函数(上下左右)控制旋转
glutSpecialFunc(SpecialKeys);
//显示函数
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;
}
然后我们就按顺序一个一个的实现这些方法
ChangeSize
自定义函数,通过glutReshaperFunc
(函数名)注册为重塑函数。当屏幕⼤小发生变化或者第⼀次创建窗口时,会调用该函数调整窗口⼤小/视⼝大小。
// 窗口已更改大小,或刚刚创建。无论哪种情况,我们都需要
// 使用窗口维度设置视口和投影矩阵.
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//设置投影矩阵
viewFrustum.SetPerspective(35, float(w)/float(h), 1, 500);
//加载投影矩阵
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//加载单元矩阵
modelViewMatrix.LoadIdentity();
}
RenderScene
⾃定义函数,通过glutDisplayFunc
(函数名)注册为显示渲染函数。当屏幕发生变化或者开发者主动渲染会调用此函数。
// 召唤场景
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
modelViewMatrix.PushMatrix();
M3DMatrix44f camera;
cameraFrame.GetCameraMatrix(camera);
modelViewMatrix.MultMatrix(camera);
M3DMatrix44f obj;
objectFrame.GetMatrix(obj);
modelViewMatrix.MultMatrix(obj);
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vGreen);
triangleBatch.Draw();
//画黑色边框
glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
glEnable(GL_POLYGON_OFFSET_LINE);
// 画反锯齿,让黑边好看些
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//绘制线框几何黑色版 三种模式,实心,边框,点,可以作用在正面,背面,或者两面
//通过调用glPolygonMode将多边形正面或者背面设为线框模式,实现线框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//设置线条宽度
glLineWidth(2.5f);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
triangleBatch.Draw();
// 复原原本的设置
////通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
modelViewMatrix.PopMatrix();
glutSwapBuffers();
}
SpecialKeys
特殊键位处理(上、下、左、右移动),这里用来控制图形旋转。
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
//围绕一个指定的X,Y,Z轴旋转。
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
if(key == GLUT_KEY_DOWN)
objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
if(key == GLUT_KEY_LEFT)
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
if(key == GLUT_KEY_RIGHT)
objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
glutPostRedisplay();
}
setupRC
自定义函数,设置需要渲染的图形的相关顶点数据、颜色数据等等。
void SetupRC()
{
//设置背景颜色
glClearColor(0.9, 0.9, 0.9, 1);
//初始化shaderManager
shaderManager.InitializeStockShaders();
//开启深度测试(后面再说是干啥的)
glEnable(GL_DEPTH_TEST);
//设置变换管线以使用两个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//把相机往后移,要不然可能会看不到图,感兴趣的可以改改数值就懂了是啥意思了。
cameraFrame.MoveForward(-20);
GLfloat points[] = {
1,1,0,
0,1,0,
1,0,0,
};
//通过三角形创建金字塔
GLfloat vPyramid[12][3] = {
//背面的三角形的三个点坐标
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
//右边的三角形的三个点坐标
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
//正面的三角形的三个点坐标
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
//左边的三角形的三个点坐标
-2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
};
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
}
运行效果
image.png会发现,我们创建的4个三角形确确实实组成了一个金字塔,但是这个金字塔是露底的。那么如果想要把底封起来,就又需要另外两个三角形来组成底部的方形。
如果有想法可以自己搞一下,这里也提供一下另外两个三角形的顶点坐标。
只要改一下这些代码就行啦。
//通过三角形创建金字塔
GLfloat vPyramid[18][3] = {
//背面的三角形
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
-2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
-2.0f, 0.0f, 2.0f,
};
triangleBatch.Begin(GL_TRIANGLES, 18);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
再看看运行效果(这么看起来可能有点抽象,发挥想象力,哈哈)
image.png
同理,只要改一改顶点坐标,似乎就可以组成各种奇奇怪怪的形状了,有想法的同志可以发挥想象力。^ _ ^
好咯,这篇文章就先到这咯。
网友评论