- 本篇文章将通过两个案例来阐述渲染过程中产生的问题以及处理方法。我们先把第一个案例实现效果展示出来如下图:
案例一:
准备工作
准备空工程 第一篇环境搭建文章有网盘链接
main.cpp实现流程
- 引入头文件
#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.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 modelViewMatrix;//模型矩阵
GLMatrixStack projectionMatrix;//对象/角色矩阵
GLGeometryTransform transformPipeline;//渲染管线
GLShaderManager shaderManager;
//标记:背面剔除、深度测试
int iCull = 0;//正背面剔除
int iDepth = 0;//深度测试
int iScissor=0;// 裁剪
- main 函数
int main(int argc,char* argv[])
{
//设置当前工作目录,针对MAC OS X
gltSetWorkingDirectory(argv[0]);
//初始化GLUT库
glutInit(&argc, argv);
/*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小,标题窗口
glutInitWindowSize(800,600);
glutCreateWindow("甜甜圈");
//点击空格时,调用的的函数
glutDisplayFunc(RenderScene);
//驱动程序的初始化中没有出现任何问题。
//注册回调函数(改变尺寸)
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(KeyPressFunc);
glutSpecialFunc(SpecialKeys);
//添加右击菜单栏
glutCreateMenu(ProcessMenu);
glutAddMenuEntry("深度测试", 1);
glutAddMenuEntry("背面剔除", 2);
glutAddMenuEntry("面填充", 3);
glutAddMenuEntry("线段填充", 4);
glutAddMenuEntry("点填充", 5);
// glutAddMenuEntry("裁剪测试", 6);
glutAttachMenu(GLUT_RIGHT_BUTTON);
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
//调用SetupRC
SetupRC();
glutMainLoop();
return 0;
}
- 重要的函数
void changeSize(int w ,int h)
void RenderScene(void)
void setupRC()
int main(int argc ,char *argv[])
void ProcessMenu(int value)
void SpecialKeys(int key, int x, int y)
- 函数 SetupRC()
void SetupRC()
{
glClearColor(0.3f, 0.3f, 0.3f, 0.3f);//设置背景色
shaderManager.InitializeStockShaders();//初始化着色器
viewFrame.MoveForward(7.0);//将相机向后移动7个单元:肉眼到物体之间的距离
//创建一个甜甜圈 参数1:容器类 参数2 外半径 参数3 内半径 参数4、5 主半径和从半径的细分单元数量
gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
glPointSize(4.0f);
}
- 函数 RenderScene()
//开始渲染
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glClearColor(0.3f, 0.3f, 0.3f, 0.3f);//设置背景色
// if (iScissor) {
// //设置清屏颜色为蓝色
// glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
// glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//
// //1.现在剪成小红色分区
// //(1)设置裁剪区颜色为红色
// glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
// //(2)设置裁剪尺寸
// glScissor(100, 100, 600, 400);
// //(3)开启裁剪测试
// glEnable(GL_SCISSOR_TEST);
// //(4)开启清屏,执行裁剪
// glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//
// // 2.裁剪一个绿色的小矩形
// //(1).设置清屏颜色为绿色
// glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
// //(2).设置裁剪尺寸
// glScissor(200, 200, 400, 200);
// //(3).开始清屏执行裁剪
// glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//
// //关闭裁剪测试
// glDisable(GL_SCISSOR_TEST);
//
//// glutSwapBuffers();
//
// }else{
//
// glDisable(GL_SCISSOR_TEST);
//清除一个或一组特定的缓冲区 目的 防止上一次渲染数据残留对本次渲染产生影响
//开启 关闭正背面剔除
if(iCull){
glEnable(GL_CULL_FACE);
glCullFace(GL_CCW);
glCullFace(GL_BACK);
}else{
glDisable(GL_CULL_FACE);
}
//根据设置iDepth标记来判断是否开启深度测试
if(iDepth){
glEnable(GL_DEPTH_TEST);
}else{
glDisable(GL_DEPTH_TEST);
}
//2、把摄像机矩阵压入模型矩阵中
modelViewMatrix.PushMatrix(viewFrame);
//设置绘图颜色
GLfloat vRed[]={1.0f,0.0f,0.0f,1.0f};
// //使用平面着色器 参数1平面着色器 参数2 模型视图投影矩阵 参数3 颜色
// shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),transformPipeline.GetProjectionMatrix(),vRed);
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vRed);
//5.绘制
torusBatch.Draw();
//6.出栈 绘制完成恢复
modelViewMatrix.PopMatrix();
//7.交换缓存区
// }
glutSwapBuffers();
}
- 函数 ChangeSize()
//窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w,int h)
{
//1、 目的 :0不能作为被除数 防止崩溃
if(h==0){
h=1;
}
//2、设置视口
glViewport(0,0, w, h);
//3、设置投影方式 SetPerspective 函数的参数是一个从顶点方向看去的视界角度(用角度值表示)
//设置透视矩阵
viewFrustum.SetPerspective(35.0, float(w)/float(h), 1.0, 100.f);
//4、把透视矩阵加载到透视矩阵堆阵中(也就是对象矩阵)
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//5、初始化渲染管线
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
- 函数SpecialKeys()
//键位设置 通过上下左右控制camera的移动 从而改变视口
void SpecialKeys(int key,int x, int y)
{
//1、判断方向
if(key==GLUT_KEY_UP){
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.0f), 0.0f, 1.0f, 0.0f);
}
//刷新视图
glutPostRedisplay();
}
- 函数 ProcessMenu();
//右击菜单栏点击事件
void ProcessMenu(int value)
{
switch (value) {
case 1:
iDepth=!iDepth;
break;
case 2:
iCull=!iCull;
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;
case 6:
iScissor=!iScissor;
break;
default:
break;
}
glutPostRedisplay();
}
各种渲染技巧实现效果
案例二:
准备工作
准备空工程 第一篇环境搭建文章有网盘链接
头文件引用
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
设置常量
GLBatch squareBatch;
GLBatch greenBatch;
GLBatch redBatch;
GLBatch blueBatch;
GLBatch blackBatch;
GLShaderManager shaderManager;
GLfloat blockSize=0.2f;
GLfloat vVerts[]={
-blockSize,-blockSize,0.0f,
blockSize,-blockSize,0.0f,
blockSize,blockSize,0.0f,
-blockSize,blockSize,0.0f
};
重要的函数
- 函数SetupRC()
void SetupRC()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//设置背景色
shaderManager.InitializeStockShaders();//初始化着色器
//绘制一个移动矩形
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
//绘制4个固定矩形
//第一个
GLfloat vBlock[]={
0.25f,0.25f,0.0f,
0.75f,0.25f,0.0f,
0.75f,0.75f,0.0f,
0.25f,0.75f,0.0f
};
greenBatch.Begin(GL_TRIANGLE_FAN, 4);
greenBatch.CopyVertexData3f(vBlock);
greenBatch.End();
//第二个
GLfloat vBlock2[] = { -0.75f, 0.25f, 0.0f,
-0.25f, 0.25f, 0.0f,
-0.25f, 0.75f, 0.0f,
-0.75f, 0.75f, 0.0f};
redBatch.Begin(GL_TRIANGLE_FAN, 4);
redBatch.CopyVertexData3f(vBlock2);
redBatch.End();
//第三个
GLfloat vBlock3[] = { -0.75f, -0.75f, 0.0f,
-0.25f, -0.75f, 0.0f,
-0.25f, -0.25f, 0.0f,
-0.75f, -0.25f, 0.0f};
blueBatch.Begin(GL_TRIANGLE_FAN, 4);
blueBatch.CopyVertexData3f(vBlock3);
blueBatch.End();
//第四个
GLfloat vBlock4[] = { 0.25f, -0.75f, 0.0f,
0.75f, -0.75f, 0.0f,
0.75f, -0.25f, 0.0f,
0.25f, -0.25f, 0.0f};
blackBatch.Begin(GL_TRIANGLE_FAN, 4);
blackBatch.CopyVertexData3f(vBlock4);
blackBatch.End();
- 函数RenderScene()
//开始渲染
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT| GL_STENCIL_BUFFER_BIT);
//设置四种颜色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
//召唤场景的时候,将4个固定矩形绘制好
//使用 单位着色器
//参数1:简单的使用默认笛卡尔坐标系(-1,1),所有片段都应用一种颜色。GLT_SHADER_IDENTITY
//参数2:着色器颜色
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
greenBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
redBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
blueBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
blackBatch.Draw();
//组合核心代码
//1.开启混合
glEnable(GL_BLEND);
//2.开启组合函数 计算混合颜色因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//3.使用着色器管理器
//*使用 单位着色器
//参数1:简单的使用默认笛卡尔坐标系(-1,1),所有片段都应用一种颜色。GLT_SHADER_IDENTITY
//参数2:着色器颜色
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
//4.容器类开始绘制
squareBatch.Draw();
//5.关闭混合功能
// glDisable(GL_BLEND);
//同步绘制命令
glutSwapBuffers();
}
- 函数 ChangeSize()
//窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w,int h)
{
//1、 目的 :0不能作为被除数 防止崩溃
if(h==0){
h=1;
}
//2、设置视口
glViewport(0,0, w, h);
}
- 函数 SpecialKeys()
//键位设置 通过上下左右控制camera的移动 从而改变视口
void SpecialKeys(int key,int x, int y)
{
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[7];
if(key == GLUT_KEY_UP)
blockY += stepSize;
if(key == GLUT_KEY_DOWN)
blockY -= stepSize;
if(key == GLUT_KEY_LEFT)
blockX -= stepSize;
if(key == GLUT_KEY_RIGHT)
blockX += stepSize;
if(blockX < -1.0f) blockX = -1.0f;
if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;;
if(blockY < -1.0f + blockSize * 2) blockY = -1.0f + blockSize * 2;
if(blockY > 1.0f) blockY = 1.0f;
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize*2;
vVerts[3] = blockX + blockSize*2;
vVerts[4] = blockY - blockSize*2;
vVerts[6] = blockX + blockSize*2;
vVerts[7] = blockY;
vVerts[9] = blockX;
vVerts[10] = blockY;
squareBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
- 函数 main()
int main(int argc,char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("移动矩形,观察颜色");
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;
}