3.OpenGL渲染技巧
1.渲染过程产生的问题
看到了不透明墙壁后面的东西,不应该渲染墙壁后的东西(隐藏面消除)
2.油画渲染
距离观察者由远及近的绘制物体,可以解决。
但是这出现了新的问题,如果3个三角形互相叠加,油画算法将无法渲染。
3.正背面剔除
OpenGL可以检查朝向观察者的面并渲染它们,而丢弃背面。
OpenGL如何区分正背面?
通过分析顶点数据的顺序。
4.深度测试
深度:3D世界中像素点距离摄像机的距离。
深度缓冲区:一块内存区域、存储着每个像素点的深度值,值越大距离摄像机越远。
为何需要深度缓冲区?绘制顺序就不重要了。
深度测试:是否绘制物体表面,表面深度值和当前缓冲区深度值比较,大于则丢弃,否则更新像素颜色值和深度值。
5.多边形模型
6.多边形偏移
7.裁剪
8.颜色混合
1.谈谈图形图像渲染中的深度缓冲区?
一块内存区域、存储着每个像素点的深度值,值越大距离摄像机越远。
为何需要深度缓冲区?绘制顺序就不重要了。
2.阐述隐藏面消除解决方案?
正背面剔除、深度测试
3.阐述深度缓冲区带来的隐患、解决方案、预防方案?
原因:深度缓冲区的限制导致深度相差很小。
隐患:交错闪烁出现2个画面
解决方案:让深度值之间产生间隔,在执行深度测试前将立方体的深度值做一些细微的增加,区分重叠的2个图形深度值。
第一步:Polygon Offset方式解决。
glEnable(GL_POLYGON_OFFSET_FILL)
第二步:指定偏移量
void glPolygonOffset(Glfloat factor,Glfloat units);
第三步: 关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)
预防方案:
不要将2个物体靠的太近;将裁剪面设置的离观察者远一些;使用高位数的深度缓冲区。
1.深度测试
//演示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 viewFrustum; //使用此类设置透视投影
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
//标记背面剔除、深度测试
int iCull = 0;
int iDepth = 0;
//开始渲染
void renderScene(void) {
//1.清除窗口和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //可以注掉看看效果
//开启关闭正背面剔除功能
if (iCull) {
glEnable(GL_CULL_FACE);
glFrontFace(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);
//或者
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
viewFrame.GetMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame);
//3.设置绘图颜色
GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
/*4.使用默认光源着色器通过光源阴影效果体现立体效果
参数1 GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
参数2 模型视图矩阵
参数3 投影矩阵
参数4 基本颜色值
*/
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
//5.绘制
torusBatch.Draw();
//6.出栈 绘制完成恢复
modelViewMatrix.PopMatrix();
//7.交换缓冲区
glutSwapBuffers();
}
//为程序做一次性的设置
void setupRC() {
//1.设置背景色
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
//2.初始化着色器管理器
shaderManager.InitializeStockShaders();
//3.将相机后移7个单位
viewFrame.MoveForward(7.0);
//4.创建一个甜甜圈
/*
参数1:容器帮助类
参数2:外边缘半径
参数3:内边缘半径
参数4、5:主半径和从半径的细分单元数量
*/
gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
//5.点的大小(方便点填充时,肉眼观察)
glPointSize(4.0f);
}
//通过camera即viewFrame的移动从而改变视口
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.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_LEFT) {
viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
viewFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
}
//3.重新刷新
glutPostRedisplay();
}
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
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(modelViewMatrix, projectionMatrix);
}
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;
}
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);
glutAddMenuEntry("Toggle depth test", 1);
glutAddMenuEntry("Toggle cull backface", 2);
glutAddMenuEntry("Set Fill Mode", 3);
glutAddMenuEntry("Set Line Mode", 4);
glutAddMenuEntry("Set Point Mode", 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;
}
2.OpenGL 裁剪
#include "GLTools.h"
#ifdef __APPLE__
#include <GLUT/GLUT.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
//开始渲染
void renderScene(void) {
//设置清屏颜色为蓝色
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear(GL_COLOR_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);
// 2.裁剪一个绿色的小矩形
//(1)设置裁剪区颜色为绿色
glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
//(2)设置裁剪尺寸
glScissor(200, 200, 400, 200);
//(3)开启清屏,执行裁剪
glClear(GL_COLOR_BUFFER_BIT);
//关闭裁剪测试
glDisable(GL_SCISSOR_TEST);
//强制执行缓存区
glutSwapBuffers();
}
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
if (h == 0) {
h = 1;
}
glViewport(0, 0, w, h);
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(800, 800);
glutCreateWindow("OpenGL Scissor");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(renderScene);
glutMainLoop();
return 0;
}
3.OpenGL混合
#include "GLShaderManager.h"
#include "GLTools.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
};
//为程序做一次性的设置
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();
}
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();
}
//开始渲染
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个固定矩形绘制好
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();
//组合的核定代码 glEnable glBlendFunc glDisable注释掉后就就不会混合了,可以注释掉看效果
//1.开启混合
glEnable(GL_BLEND);
//2.开启组合函数,计算混合颜色因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//3.使用着色器管理
//参数1 使用单位着色器 参数2 着色器颜色
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
//4.容器类开始绘制
squareBatch.Draw();
//5.关闭混合
glDisable(GL_BLEND);
//同步绘制命令
glutSwapBuffers();
}
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
glViewport(0, 0, w, h);
}
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;
}