//演示了OpenGL背面剔除,深度测试,和多边形模式
#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#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;
//渲染场景
//屏幕发生改变 都会掉RenderScene
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//根据设置iCull标记来判断是否开启背⾯面剔除
if (iCull) {
//开启
glEnable(GL_CULL_FACE);
//开启背后测试
glFrontFace(GL_CCW);
}else{
glDisable(GL_CULL_FACE);
}
//1. viewFrumpush 到 模型视图里面
modelViewMatix.PushMatrix(viewFrame);
//2 设置画笔颜色
GLfloat vRed[] = {1.0f,0.0,0.0,1};
//3. 使用着色器了
/**
让我们在OpenGL使用矩阵
绘制默认OpenGL坐标系(-1,1)下图形,图形所有片段都会以一种颜色填充。
@param GLT_SHADER_FLAT 平面着色器
@param transformPipeline 里面会计算 模型矩阵和视图矩阵 相乘的结果 是一个管理类
@return MVP
*/
// shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vRed);
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vRed);
torusBatch.Draw();
//pop
modelViewMatix.PopMatrix();
//提交渲染
glutSwapBuffers();
}
//负责图形相关的初始化
void SetupRC()
{
//设置背景颜色
glClearColor(0.3f, 0.3f, 0.3f, 1);
shaderManager.InitializeStockShaders();
//移动深度 移动Z值 往里移动负的, 往外移动正的,
viewFrame.MoveForward(7.0f);
//图片相关顶点
//顶点一般开发者不管,有设计师给你,甜甜圈模型有专门的API
//
/**
初始化花托的顶点批次
甜甜圈的API
@param torusBatch 批次类
@param majorRadius#> 内半径 description#>
@param minorRadius#> 外半径 description#>
@param numMajor#> 三角形个数 description#>
@param numMinor#> 细密成都 description#>
@return
*/
gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
//3 点 线 面的方式 d填充
//4 线的宽度
glPointSize(4.0f);
}
//键位设置,通过不同的键位对其进行设置
//控制Camera的移动,从而改变视口
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP) {
viewFrame.RotateWorld(m3dDegToRad(-5.0f), 1, 0, 0);
}
if (key == GLUT_KEY_DOWN) {
viewFrame.RotateWorld(m3dDegToRad(5.0f), 1, 0, 0);
}
if (key == GLUT_KEY_LEFT) {
viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0, 1, 0);
}
if (key == GLUT_KEY_RIGHT) {
viewFrame.RotateWorld(m3dDegToRad(5.0f), 0, 1, 0);
}
//重新渲染 GLTools 里面的函数
glutPostRedisplay();
}
//窗口改变
void ChangeSize(int w, int h)
{
//1.设置投影方式
glViewport(0, 0, w, h);
//2.设置投影方式 角度、纵横比 near flear 通过设置它来拿到投影矩阵
//拿到投影矩阵 viewFrustum.GetProjectionMatrix()
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
//3 加载到矩阵堆栈里面 矩阵堆栈只放一个元素的时候 跟数组里面放一个元素一样
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//4. 初始化模型矩阵 加载一个单元矩阵
/*
1,0,0
0,1,0
0,0,1
*/
modelViewMatix.LoadIdentity();
//5. 把 模型矩阵 和 视图矩阵 放进去 方便管理,可以拿到模型矩阵和视图矩阵
transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}
void ProcessMenu(int value){
switch (value) {
case 1:
//深度测试
iDepth = !iDepth;
break;
case 2:
//正背面剔除
iCull = !iCull;
break;
case 3:
//颜色填充
//填充方式
//GL_FRONT_AND_BACK 正背面完全填充(GL_FILL)
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();
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Geometry Test Program");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);
//注册 右键按钮回调
glutCreateMenu(ProcessMenu);
//添加几个按钮 相当于微信上面 + 下来的添加朋友等几个按钮 只不过这个是在pc端
glutAddMenuEntry("深度测试", 1);
glutAddMenuEntry("正背面剔除", 2);
glutAddMenuEntry("颜色填充", 3);
glutAddMenuEntry("线段填充", 4);
glutAddMenuEntry("点填充", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
在RenderScene里面if (iCull) 根据判断来开启或者关闭正背面剔除,效果
带来了新的问题,就是少一个缺口。
代码讲解
main函数里面的
glutAddMenuEntry("深度测试", 1);
效果图
ProcessMenu函数里面的case
3、4、5的效果,下面的效果图 命名是3.png、4.png、5.png;