1.混合知识
OpenGL渲染的时候会把颜色值放在颜色缓冲区当中。每个片段的深度值放在深度缓冲区中
打开了OpenGL的混合功能方法:
glEnable(GL_BLEND);
打开混合功能,新的颜色会与已经存在的颜色值在颜色缓冲区中进行组合。这些颜色的组合方式不同会导致很多不同的特殊效果。
(1)组合颜色术语
目标颜色:已经存储在颜色缓冲区中的颜色。这个颜色包含单独的红绿蓝以及一个可选的alpha值。
源颜色:作为当前渲染命令的结果进入颜色缓冲区。可能与目标颜色进行交互。也可以不与之进行交互。源颜色可以包含三种或者四种颜色成分。
混合方式启用的时候,默认情况下混合方程式:
Cf=(Cs*S)+(Cd*D)
Cf:最终产生的颜色,Cs是源颜色,Cd是目标颜色。
S、D为混合因子,并且都是枚举值。
调用下面的函数对其进行设置:
glBlendFunc(GLenum S, GLenum D);
(2)改变混合方程式
其中有五个混合方程式进行选择。
GL_FUNC_ADD:Cf=(Cs*S)+(Cd*D)
GL_FUNC_SUBTRACT:Cf=(Cs*S)-(Cd*D)
GL_FUNC_REVERSE_SUBTRACT:Cf=(Cd*D)-(Cs*S)
GL_MIN:MIN(Cs,Cd)
GL_MAX:MAX(Cs,Cd)
选择函数为:
void glBlendEquation(GLenum mode);
//使用上述枚举值对混合方程式进行选择。
void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
注意glBlendFuncSeparate函数则允许为RGB和alpha成分单独指定混合函数。
void glBlendColor(GLclampf red,GLclampf green, GLclampf blue, GLclampf alpha);
这个函数可以对常量混合函数颜色进行修改。
(3)抗锯齿
在绝大多数情况,一个独立的渲染片段会映射到计算机屏幕上的一个像素。这些像素是正方形,通常可以相当清楚地看到两种颜色的分界,他们常常被称为锯齿,会吸引眼睛的注意力,让人觉得图像非常不自然。
解决方法:OpenGL使用混合功能来混合片段的颜色,也就是把像素的目标颜色和周围的颜色进行混合。
步骤:
//首先开启抗锯齿功能,首先必须启动混合功能
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//并且把默认的混合方程式设置为GL_ADD。
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
//使用GL_POLYGON_SMOOTH的时候,需要很多其他规则:重叠的几何图形需要不同的混合模式、并可能对场景从前向后进行排序。
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
//对其渲染模式进行微调。并且根据需要选择GL_NICEST或者GL_FASTEST。
(4)多重采样
抗锯齿处理最大优点之一是能够使得多边形边缘能够更加平滑,使渲染效果显得更加自然和逼真。然而多边形的平滑处理并不方便。抗锯齿处理是基于混合操作的。
多重采样可以解决这个问题。所有图元在每个像素上都进行多次采样,结果就存储在这个缓冲区中,每次当这个像素进行更新的时候,这些采样值进行解析,以产生一个单独的值。
如下请求一个多重采样:
//请求一个帧缓冲区作为多重采样的缓冲区。
glutDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_MULTISAMPLE);
//打开或者关闭多重采样
glEnable(GL_MULTISAMPLE);
glDisable(GL_MULTISAMPLE);
注意:关于多重采样,当它被启用的时候,点、线、多边形平滑特性都将被忽略。二者不可兼得。一种策略是:绘制直线的时候,可以考虑关闭多重采样,绘制其他实心几何图形时再打开多重采样。
注意:状态排序:上面的一种策略,导致的状态改变可能会对渲染的性能造成影响,这样需要相同状态的几何图形就可以在一起绘制。这种状态排序是在游戏中常用的提高速度的方法之一。
多重采样缓冲区在默认情况下使用片段的RGB值,并不包括颜色的alpha成分。我们可以通过glEnable来修改这些行为。
GL_SAMPLE_ALPHA_TO_COVERAGE:使用alpha值。
GL_SAMPLE_ALPHA_TO_ON:将alpha值设置为1,并且使用它。
GL_SAMPLE_COVERAGE:使用glSampleCoverage。
当启用GL_SAMPLE_COVERAGE时,glSampleConverage函数允许指定一个特定的值,他是与片段覆盖值进行按位与操作的结果。
void glSampleCoverage(GLclampf value, GLclampf invert);
- 基础渲染代码分析
下面列出本章节所涉及到的代码分析
(1)环带渲染模式示例代码分析
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h> // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <math.h>
#include <GL/glut.h>
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
//面剔除选项,以及深度测试选项
int iCull = 0;
int iDepth = 0;
//右键可以打开相应的菜单对其渲染模式进行选择。
//注意main函数当中的glutCreateMenu回调函数
//就是调用这个函数创建相应的菜单。
//注意这个函数的格式。
//value值为菜单条目的索引值。
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();
}
//实际绘制函数
void RenderScene(void)
{
// 清除屏幕和缓冲区当中数据
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 决定是否开启相关的功能。
//是否开启表面剔除
if (iCull)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
// 是否开启深度测试
if (iDepth)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
//向矩阵堆栈中压栈
modelViewMatix.PushMatrix(viewFrame);
//红色
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
//shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT,
transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(),
vRed);
//绘制相应的批次序列
torusBatch.Draw();
//弹栈
modelViewMatix.PopMatrix();
//手动刷新
glutSwapBuffers();
}
// 渲染的基础环境设置
void SetupRC()
{
// 背景色设置
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
//初始化渲染器<