第一步:搭架子此处代码有详细的注解,不再画图分析
//包含了大部分GLTools中类似C语言的独立函数
#include "GLTools.h"
//矩阵工具类 加载单元矩阵/矩阵/矩阵相乘/压栈/出栈/平移/缩放/旋转
#include "GLMatrixStack.h"
//矩阵工具类,表示位置 通过设置vOrigin/vForward/vUp
#include "GLFrame.h"
//矩阵工具类,用来快速设置正/透视投影矩阵,完成坐标从3D->2D映射过程
#include "GLFrustum.h"
//变换管道类 传输视图矩阵/投影矩阵/视图投影变换矩阵
#include "GLGeometryTransform.h"
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
////设置角色帧,作为相机
GLFrame viewFrame;
//使用GLFrustum类来设置透视投影
GLFrustum viewFrustum;
//三角形批次类(容器类)
GLTriangleBatch torusBatch;
//模型试图矩阵
GLMatrixStack modelViewMatix;
//投影矩阵
GLMatrixStack projectionMatrix;
//变换管道
GLGeometryTransform transformPipeline;
//存储着色器管理工具
GLShaderManager shaderManager;
//标记:背面剔除、深度测试
int iCull = 0;
int iDepth = 0;
//渲染场景
void RenderScene()
{
}
void SetupRC()
{
}
//键位设置,通过不同的键位对其进行设置
//控制Camera的移动,从而改变视口
void SpecialKeys(int key, int x, int y)
{
}
//窗口改变
void ChangeSize(int w, int h)
{
}
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("Geometry Test Program");
//注册回调函数(改变尺寸)
glutReshapeFunc(ChangeSize);
//特殊键位函数(上下左右)
glutSpecialFunc(SpecialKeys);
//显示函数
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//绘制
SetupRC();
//开启runloop运行循环
glutMainLoop();
return 0;
}
第二步:完善必要的函数
1、ChangeSize()
窗口改变函数
void ChangeSize(int w, int h)
{
//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.把透视矩阵加载到透视矩阵堆栈中
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//5.初始化渲染管线
transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}
2、特殊键位功能设置函数
//控制Camera的移动,从而改变视口
void SpecialKeys(int key, int x, int y)
{
//1.判断方向
if(key == GLUT_KEY_UP)
//2.根据方向调整观察者位置
viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
if(key == GLUT_KEY_DOWN)
viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);
if(key == GLUT_KEY_LEFT)
viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);
if(key == GLUT_KEY_RIGHT)
viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);
//3.重新刷新
glutPostRedisplay();
}
第三步:画一个甜甜圈
1、在SetupRC()
函数中创建一个甜甜圈
//4.创建一个甜甜圈
//void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
//参数1:GLTriangleBatch 容器帮助类
//参数2:外边缘半径
//参数3:内边缘半径
//参数4、5:主半径和从半径的细分单元数量
gltMakeTorus(torusBatch, 1.0f, 0.3f, 50, 20);
//5.点的大小(方便点填充时,肉眼观察)
glPointSize(4.0f);
2、在RenderScene()
函数渲染
//渲染场景
void RenderScene()
{
//1.清除窗口 颜色缓冲区 和 深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//2.压栈 - 把摄像机矩阵压入模型矩阵中
modelViewMatix.PushMatrix(viewFrame);
//3.设置绘图颜色
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
//4.1
//使用平面着色器 --> 看不出问题
//参数1:平面着色器
//参数2:模型视图投影矩阵
//参数3:颜色
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
//5.绘制
torusBatch.Draw();
//6.出栈
modelViewMatix.PopMatrix();
//7.交换缓存区
glutSwapBuffers();
}
使用平面着色器
运行好像没什么问题,是因为使用的是
平面着色器
,没有光源,正背面都是一个色,所以看不出问题。下面的图是换成默认点光源着色器
后的运行效果,就发现了问题
使用默认光源着色器
//4.2
//使用默认光源着色器
//通过光源、阴影效果跟提现立体效果
//参数1:GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
//参数2:模型视图矩阵
//参数3:投影矩阵
//参数4:基本颜色值
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vGreen);
使用默认点光源着色器
3、添加一个右键菜单栏,看看线填充
,点填充
各自效果
3.1main()
开启一个右键菜单栏
glutCreateMenu(RightClickMenu);
glutAddMenuEntry("开启/关闭背面消除", 1);
glutAddMenuEntry("开启/关闭深度测试", 2);
glutAddMenuEntry("面填充", 3);
glutAddMenuEntry("线填充", 4);
glutAddMenuEntry("点填充", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);
3.2 右键菜单栏函数功能开关实现RightClickMenu()
.
void RightClickMenu(int key)
{
/*
glPolygonMode 控制多边形的正面和背面的绘图模式
GL_POINT表示显示顶点,多边形用点显示
GL_LINE表示显示线段,多边形用轮廓显示
GL_FILL表示显示面,多边形采用填充形式
*/
switch (key) {
case 1:
break;
case 2:
break;
case 3:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
case 4:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
case 5:
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
break;
default:
break;
}
glutPostRedisplay();
}
绘图模式 - 面、线、点
可以看到 不管使用面、线、还是点的绘图模式,渲染都会存在问题。解决这种问题,需要决定那部分是对观察者可见的,哪部分对观察者不可见,对不可见的部分,应该尽早丢弃(即看不见的部分不渲染,节省资源,提高效率)
4. 用正背面剔除(Face Culling)
解决渲染问题
4.1 右键菜单控制开启/关闭正背面剔除功能
iDepth = !iDepth;
4.2RenderScene()
中glEnable
, glDisable
//开启/关闭正背面剔除功能
if (iCull) {
glEnable(GL_CULL_FACE);
}else {
glDisable(GL_CULL_FACE);
}
4.3 效果
开启了正背面剔除但没开启深度测试5. 开启深度测试
5.1 同开启正背面剔除逻辑一样
//开启/关闭深度测试
if (iDepth) {
glEnable(GL_DEPTH_TEST);
}else {
glDisable(GL_DEPTH_TEST);
}
5.2效果
开启正背面剔除和深度测试
网友评论