OpenGL 红宝书 反走样 雾 点参数 多边形偏移

6.1 混合
6.1.1 源因子和目标因子
假定源和目标混合因子分别为(Sr, Sg, Sb, Sa)和(Dr,Dg,Db,Da), 混合后的RGB值如下:
(RsSr + RdDr, GsSg + GdDg, BsSb + BdDb, AsSa + AdDa)
最后,将该四元组的各个分量截取到[0,1].
将源片元和目标象素合并起来的默认方式是,将它们的值相加.

选择源混合因子和目标混合因子的方式:
第一种方式是调用函数glBlendFunc(),并指定两个混合因子, 其中第一个参数为源RGBA的混合因子, 第二个参数为目标RGBA的混合因子.
第二种方法是调用glBlendFuncSeparate()并指定4个混合因子, 这样可以用不同的方式来混合RGB和alpha值.
void glBlendFunc(GLenum srcfactor, GLenum destfactor);
srcfactor指出如何计算源混合因子; destfactor指出如何计算目标混合因子.
void glBlendFuncSeparate(GLenum srcRGB, GLenum destRGB, GLenum srcalpha, GLenum destalpha);
源混合因子和目标混合因子
常量: RGB混合因子 alpha混合因子
GL_ZERO: (0, 0, 0) 0
GL_ONE: (1, 1, 1) 1
GL_DST_COLOR: (Rd, Gd, Bd)
GL_SRC_COLOR: (Rs, Gs, Bs) A
GL_ONE_MINUS_DST_COLOR: (1, 1, 1) - (Rd, Gd, Bd)
GL_ONE_MINUS_SRC_COLOR: (1, 1, 1) - (Rs, Gs, Bs) 1 - A
GL_SRC_ALPHA: (As,As,As,As)
GL_ONE_MINUS_SRC_ALPHA: (1, 1, 1, 1) - (As,As,As,As)
GL_DST_ALPHA: (Ad, Ad, Ad, Ad)
GL_ONE_MINUS_DST_ALPHA: (1, 1, 1, 1) - (Ad, Ad, Ad, Ad)
GL_SRC_ALPHA_STATURATE: (f, f, f, 1); f = min(As, 1 - Ad)

另将GL*CONSTANT*作为参数时, 需要使用glBlendColor()指定一个常量(constant)颜色
void glBlenColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
设置执行混合操作时使用的常量颜色的红,绿,蓝和alpha值(Rc, Gc, Bc, Ac)

6.1.2 启用混合操作
glEnable(GL_BLEND);

6.1.3 使用混合方程来合并像素
采用标准混合方式时, 将帧缓存中的颜色和输入片元的颜色合并起来, 得到新的帧缓存颜色.
void glBlendEquation(GLenum mode);
上面的函数用来指定其他数学运算,以计算帧缓存颜色和片元颜色的差, 它们中的最大值或最小值.
指定如何混合帧缓存中的颜色和片元颜色.
Cs和Cd表示源颜色和目标颜色, S和D表示函数glBlendFunc()或glBlendFuncSeparate()指定的源混合因子和目标混合因子.
GL_FUNC_ADD CsS + CdD
GL_FUNC_SUBTRACT CsS - CdD
GL_FUNC_REVERSE_SUBTRACT CdD - CsS
GL_MIN min(CsS, CdD)
GL_MAX max(CsS, CdD)

要使用OpenGL扩展代码
1. 增加头文件
#include
2. 定义函数指针
PFNGLBLENDEQUATIONPROC glBlendEquation = NULL; //定义函数指针
3. 在内存中找到函数地址
PFNGLBLENDEQUATIONPROC glBlendEquation = (PFNGLBLENDEQUATIONPROC)wglGetProcAddress("glBlendEquation");

使用深度透视,重绘的时候要注意清除深度缓存,否则会消失.


6.1.4 混合的用途
1. 均匀地混合两幅图像:
首先将源因子和目标因子分别设置为GL_ONE和GL_ZERO. 并绘制第一副图像.
然后将源因子设置为GL_SRC_ALPHA, 目标因子设置为GL_ONE_MINUS_SRC_ALPHA, 并在绘制第二幅图像时使用alpha值0.5. 这是最常用的混合方式.
如要设置第一副图像占75%, 第二幅图像占25%. 可以在绘制第二幅图像使用alpha值0.25.
2. 均匀地混合三幅图像, 目标因子设置为GL_SRC_ALPHA, 然后使用alpha值 0.3333333绘制这些图像.这样每幅图像的亮度只有原来的三分之一.
3. 逐渐加深图像的颜色: 源混合因子和目标混合因子分别设置为GL_SRC_ALPHA和GL_ONE_MINUS_SRC_ALPHA, 并将画笔的alpha值设置为0.1
4. 通过将源混合因子设置为GL_DST_COLOR或GL_ONE_MINUS_DST_COLOR.将目标混合因子设置为GL_SRC_COLOR或GL_ONE_MINUS_SRC_COLOR,可以分别调整各个颜色分量.
相当于使用一个简单的滤光器.
如红色分量乘以0.8,绿色分量乘以0.4,蓝色分量乘以0.72. 相当于滤光器滤掉20%的红光, 60%的绿光和28%的蓝光.
5. 纯色背景三个半透明面组成的图像.最远的透过其后80%的颜色, 接下来的面40%,最近的90%.
首先用默认的源混合因子和目标混合因子绘制背景
然后源混合因子和目标混合因子为GL_SRC_ALPHA和GL_ONE_MINUS_SRC_ALPHA, 并依次是哟个alpha值0.2绘制最远的面,0.6绘制中间面,0.1绘制最近的面.
6. 如果系统有alpha位面, 可以每次渲染一个物体, 然后将它们读取到内存中, 然后对渲染后的物体执行有趣的合成操作.
7. 通过给图像中的片元指定不同的alpha值,可以实现非矩形光栅图像的效果.
透明片元的alpha值设置为0, 不透明片元的alpha值设置为1.0.
8. 混合也可以用于实现反走样.

6.1.5 一个混合的例子


6.1.6 使用深度缓存的三维混合
方法: 启用深度缓存, 并在绘制半透明物体时, 将深度缓存设置为只读的.
首先, 将深度缓存设置为正常状态, 并绘制所有的不透明物体, 然后将深度缓存设置为只读的, 并使这些深度值保持不变. 绘制半透明物体时,将深度同不透明物体的深度值进行比较,这样, 如果他们位于不透明物体后面,不绘制他们, 如果它们离视点更近, 也不会消除不透明物体, 因为深度缓存的值是无法修改的,而是与不透明物体混合在一起.

函数glDepthMask()可以控制深度缓存的读写状态. 参数GL_FALSE将深度缓存设置为只读. 参数GL_TRUE设置为可写.


6.2 反走样
void glHint(GLenum target, GLenum hint); // 控制OpenGL的某些行为
参数target是要控制的行为
参数hint可以是GL_FASTEST, GL_NICEST, GL_DONT_CARE.(效率最高, 质量最好, 没有选择)
参数target的取值及其含义:
GL_POINT_SMOOTH_HINT, GL_LINE_SMOOTH_HINT, GL_POLYGON_SMOOTH_HINT----反走样操作中, 直线,点或多边形的采样质量.
GL_FOG_HINT----对每个像素(GL_NICEST)还是每个顶点(GL_FASTEST)执行雾效计算.
GL_PERSPECTIV_CORRECTION_HINT----颜色和纹理坐标插值的质量
GL_GENERATE_MIPMAP_HINT----自动生成的mipmap的质量和性能
GL_TEXTURE_COMPRESSION_HINT----纹理图案的压缩质量和性能.


6.2.1 点和直线的反走样
两种处理点和直线反走样的方法:
1) 使用参数GL_POINT_SMOOTH或GL_LINE_SMOOTH调用函数glEnable(), 以启用反走样功能.使用函数glHint()提出有关质量的建议.
2) 使用多重采样.

1. RGBA模式下的反走样
在RGBA模式中, 需要启用混合功能. 最常用的混合因子是GL_SRC_ALPHA(源)和GL_ONE_MINUS_SRC_ALPHA(目标)或GL_ONE(目标).
使用alpha的值越高, 反走样效果越明显.

2. 颜色索引模式下的反走样
由于颜色索引后的4位表示覆盖比率,因此需要加载16个相邻的索引(第1个必须是16的倍数), 对应的颜色从背景色渐变到物体的颜色.
使用第一个索引值对应的颜色清空颜色缓存, 然后使用你加载的颜色绘制点或直线.

使用颜色索引的时候,程序报错
pixel format with necessary capabilities not found.

将经过反走样处理的点和直线同未经过反走样处理的存储在深度缓存中的多边形进行混合. 首先绘制多边形, 然后将深度缓存设置为只读, 并绘制点和直线.
6.2.2 使用多重采样对几何图元进行反走样处理
多重采样是一种使用更多的颜色,深度和模板信息(样本)对OpenGL图元(点,直线,多边形,位图和图像)进行反走样处理的技术.
每个片元都有多种颜色, 多个深度值和多组纹理坐标. 计算是分散在多个取样位置. 计算反走样覆盖比例时, 使用存储在多重取样缓存中的样本.
多重采样非常适合用于多边形的反走样处理,无需确定物体的绘制顺序.
如何使用多重采样:
(1) 打开一个支持多重采样的窗口. 如果有GLUT函数库, 则调用一下函数
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);
(2) 打开窗口后, 需要确定它是否支持多重采样.
查询变量GL_SAMPLE_BUFFERS返回1, 变量GL_SAMPLES返回的值大于1, 则可以使用多重采样.
GLint bufs, samples;
glGetIntegerv(GL_SAMPLE_BUFFERS, &bufs);
glGetIntegerv(GL_SAMPLES, &samples);
(3) 打开多重采样,可调用下述函数
glEnable(GL_MULTISAMPLE);

注: 要查询GL_SAMPLE_BUFFERS_ARB的话,需要用glew.h头文件.
我的电脑不支持多重采样....查询的值都为0

如果多重采样功能被启用,且有多重采样缓存, 点,直线和多边形将生成供反走样处理使用的片元.

alpha值和多重采样覆盖比例
默认多重采样在计算片元覆盖比例时不考虑alpha值, 除非启用了以下模式之一:
1) GL_SAMPLE_ALPHA_TO_COVERAGE: 使用片元的alpha来计算最终的覆盖比率
2) GL_SAMPLE_ALPHA_TO_ONE: 将片元的alpha值设置为最大值(1),然后使用这个值来计算覆盖比率
3) GL_SAMPLE_COVERAGE: 将函数glSampleCoverage()设置的值与计算得到的覆盖比例进行AND运算.
void glSampleCoverage(GLclampf value, GLboolean invert);
设置在计算多重采样覆盖比率时用于解释alpha值的参数
value: GL_SAMPLE_COVERAGE或GL_SAMPLE_ALPHA_TO_COVERAGE启用时使用的临时覆盖比例.
invert:对临时覆盖比例和片元覆盖比例执行AND运算之前,是否需要将临时覆盖比例执行按位反转.
6.2.3 多边形的反走样
使用参数GL_POINT或GL_LINE调用函数glPolygonMode()时, 将对点或直线进行反走样处理.

要对多个多边形进行反走样处理, 必须按从前到后的顺序排列多边形, 然后使用调用函数glBlendFunc()将源混合因子设置为GL_SRC_ALPHA_SATURATE, 目标为GL_ONE.
RGBA模式下, 多边形的反走样处理使用alpha值来表示多边形边的覆盖比例; 同时需要使用参数GL_POLYGON_SMOOTH来调用函数glEnable();
也可给GL_POLYGON_SMOOTH_HINT指定一个值.

对重叠的边进行混合:
首先,禁用深度缓存
然后将源混合因子设置为GL_SRC_ALPHA_SATURATE, 目标混合因子设置为GL_ONE;

最后,在绘制多边形之前, 需要按从前到后的顺序对场景中所有的多边形进行排序.
6.3 雾
将雾效用于点和直线也被称为深度提示(depth-cuing)
6.3.1 使用雾
使用参数GL_FOG调用函数glEnable()以启用雾效, 并使用函数glFog*()指定雾颜色和控制雾密度的方程.还可以使用参数GL_FOG_HINT调用glHint().
6.3.2 雾方程
void glFog(if)(GLenum pname, TYPE param);
void glFog(if)v(GLenum pname, TYPE* param);
pname: GL_FOG_MODE, GL_FOG_DENSITY, GL_FOG_START, GL_FOG_END
param: GL_FOG_MODE -- GL_EXP(默认), GL_EXP2, GL_LINEAR
GL_FOG_DENSITY -- density 默认值为1
GL_FOG_sTART , GL_FOG_END -- 默认值为0, 1
RGBA模式下, pname --- GL_FOG_COLOR, param则指向颜色值.
颜色索引模式下, pname --- GL_FOG_INDEX, param指定颜色索引.

1. RGBA模式下的雾效
雾效因子f计算最终的颜色
C = fCi + (1-f)Cf
Ci是片元的RGBA值,Cf是使用参数GL_FOG_COLOR指定的雾颜色
2. 颜色索引模式下的雾效
I = Ii + (1-f)If
其中Ii是片元的颜色索引, If是使用参数GL_FOG_INDEX指定的雾的颜色索引.

程序不支持颜色索引模式...

3. 雾坐标
调用glFog(GL_FOG_COORDINATE_SOURCE, GL_FOG_COORDINATE),然后显式地指定每个顶点的z值.用函数glFogCoord*().
void glFogCoord(fd)(TYPE z);
void glFogCoord(fd)v(TYPE *z);
其中z必须大于0

书中的例子使用了扩展,解决方法:
1.定义下面两个宏定义,本来这两个宏在glew.h中定义的,不过包含了glew.h的话,就不能使用wglGetProcAddress函数,只好自己定义了.
#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450
#define GL_FOG_COORDINATE_EXT 0x8451
2. 要包含头文件
#include
3. 有以下语句
PFNGLFOGCOORDFEXTPROC glFogCoordfEXT = NULL;
glFogCoordfEXT = (PFNGLFOGCOORDFEXTPROC) wglGetProcAddress("glFogCoordfEXT");
glFogCoordfEXT(f1);



6.4 点参数
可使用glPointSize()和glEnable(GL_POINT_SMOOTH)来绘制大型的圆点, 并使用雾效来实现距离改变的效果. 但是, 不能在glBegin()和glEnd()之间调用函数glPointSize().
因此要改变不同点的大小很困难. 必须动态地重新计算点的大小, 并根据大小重新对点进行分组, 以最大限度地提高性能.
点参数能够根据图元距离视点的距离, 自动改变其大小和亮度. 要指定点图元的大小和alpha分量(用于控制亮度)的衰减系统, 可使用函数glPointParameterf*().
void glPointParameterf(GLenum pname, GLfloat param);
void glPointParameterfv(GLenum pname, GLfloat* param);
设置与渲染点图元相关的值
如果pname为GL_POINT_DISTANCE_ATTENUATION, param将是一个包含三个元素(a,b和c)的浮点数组.
这三个元素分别是根据眼坐标距离d对点的大小和亮度进行衰减的常量系统, 线性系数和二次系数:
derivedSize = clamp(size*(1/(a+b*d+c*d*d))的平方根)
如果pname为GL_POINT_SIZE_MIN或GL_POINT_SIZE_MAX, param为点大小截取范围的下限或上限.
如果多重采样被启用, 且pname为GL_FADE_THRESHOLD_SIZE, param降为另一种有关大小的下限(threshold). 如果derivedSize < threshold. 将按下述方式计算fade因子.
该因子用于调整点的alpha值,从而降低其亮度:
fade = (derivedSize / threshold)的平方
点大小的计算方式类似于定位光源的衰减计算方式

当用户选择线性或二次衰减方式时, 如果视点离点图元非常近, 除数将为小数, 导致计算得到的点大于实际大小, 为避免这种情况,可以增大常量衰减系数
或用参数GL_POINT_SIZE_MAX指定一个最大值.

由于希望点不是方形,可启用反走样:
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

6.5 多边形偏移
要突出实体的边, 可以先使用多边形模式GL_FILL来绘制物体, 然后使用多边形模式GL_LINE和不同的颜色再次绘制该物体.
缝合 --- 相同顶点之间的直线和多边形边, 其像素的深度值并不相同, 导致直线有时在相应多边形的前面,有时在后面.
启用多边形偏移的方式有3种: GL_FILL, GL_LINE和GL_POINT.
使用合适的参数来调用glEnable()---GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_LINE, GL_POLYGON_OFFSET_POINT
还必须函数调用glPolygonMode()来设置当前的多边形光栅化方法:
void glPolygonOffset(GLfloat factor, GLfloat units);
多边形偏移被启用时, 将每个片元的深度值加上一个计算得到的偏移值, 这种操作是在深度测试以及将深度值写入深度缓存之前完成的.偏移值的计算公式如下:
n = m*factor + r*units
其中m是多边形的最大深度斜率, r是确保窗口坐标深度值能够被区分开来的最小值. r是一个随OpenGL实现而异的常量.
深度斜率指的是,当你穿越多边形时, z值的变化量与x或y坐标的变化量之间的商.
m = max{|dV/ds|, |dV/dt|}

多边形偏移的图形

未偏移的图形

评论

此博客中的热门博文

《绿箭》——1x01

WordPress 安装记

Vim插件 - NERDTree