博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenGL超级宝典笔记——累积缓冲区与其他颜色操作
阅读量:6940 次
发布时间:2019-06-27

本文共 4895 字,大约阅读时间需要 16 分钟。

hot3.png

累积缓冲区

OpenGL除了颜色缓冲区、深度缓冲区、模板缓冲区之外,还有累积缓冲区。累积缓冲区允许你把渲染到颜色缓冲区的值,拷贝到累积缓冲区。在多次拷贝操作到累积缓冲区时,可以用不同方式的把颜色缓冲区内容和当前累积缓冲区的内容进行重复混合。当在累积缓冲区完成一幅图像之后,可以拷回颜色缓冲区,然后通过SwapBuffers显示到屏幕上。

累积缓冲区的操作通过void glAccum(GLenum op, GLfloat value);控制。第一个参数表示对累积缓冲区所进行的操作。第二个参数是浮点数用于指定缩放因子。

OpenGL支持的累积缓冲区的操作如下表:

操作 描述
GL_ACCUM 把颜色缓冲区的颜色值进行缩放后,累加到累积缓冲区
GL_LOAD 把颜色缓冲区的颜色值进行缩放后,替换掉累积缓冲区的颜色值
GL_RETURN 把累积缓冲区的颜色值缩放后,拷贝回颜色缓冲区
GL_MULT 把累积缓冲区的颜色值缩放后,替换掉原累积缓冲区的颜色值
GL_ADD 把累积缓冲区的颜色值缩放后,累加到累积缓冲区

由于累积缓冲区会带来大内存的开销,所以在实时应用程序中比较少用。但在非实时的应用程序中,可以产生实时应用程序无法做到的效果。例如,你可以多次渲染场景,并在每次渲染时进行抖动零点几个像素,这样就可以产生整个场景的反走样的效果,比多重采样的效果还要好。还可以模糊前景或背景,然后清晰的渲染一个物体来模拟,照相机景深的效果。

下面的例子是一个球体在地板上滚动,运动模糊的效果。

#include "gltools.h" GLfloat fLightPos[4]   = { -100.0f, 100.0f, 50.0f, 1.0f }; GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 0.0f }; GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f }; GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f }; static GLfloat yRot; void DrawGround() {
GLfloat fExtent = 20.0f; GLfloat y = -0.0f; GLfloat step = 0.5f; GLfloat x, z; int iColor = 0; glShadeModel(GL_FLAT); for (x = -fExtent; x <= fExtent; x += step) {
glBegin(GL_TRIANGLE_STRIP); for (z = fExtent; z >= -fExtent; z -= step) {
if ((iColor % 2) == 0) {
glColor4f(0.0f, 0.0f, 0.0f, 0.5f); } else {
glColor4f(1.0f, 1.0f, 1.0f, 0.5f); } glVertex3f(x, y, z); glVertex3f(x + step, y, z); iColor++; } glEnd(); } glShadeModel(GL_SMOOTH); } void DrawGemometry() {
glPushMatrix(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); DrawGround(); glColor3f(1.0f, 0.0f, 0.0f); glTranslatef(0.0f, 0.3f, -3.5f); glRotatef(-yRot*2.0f, 0.0f, 1.0f, 0.0f); glTranslatef(1.0f, 0.0f, 0.0f); glutSolidSphere(0.1f, 17, 13); glPopMatrix(); } void RenderScene() {
yRot = 35.0f; GLfloat pass = 10.0f; for (int i = 0; i < 10; ++i) {
yRot += 0.75f; DrawGemometry(); //复制到累积缓冲区 if (i == 0) {
glAccum(GL_LOAD, 0.5f); } else {
//累加到累积缓冲区 glAccum(GL_ACCUM, (0.5f * 1 / pass)); } } glAccum(GL_RETURN, 1.0f); glutSwapBuffers(); } void ChangeSize(GLsizei w, GLsizei h) {
if (h == 0) h = 1; glViewport(0, 0, w, h); GLfloat faspect = (GLfloat)w/(GLfloat)h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(35.0f, faspect, 1.0f, 50.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, -0.4f, 0.0f); glutPostRedisplay(); } void SetupRC() {
glClearColor(0.25f, 0.25f, 0.25f, 1.0f); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); //设置光照 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fNoLight); glLightfv(GL_LIGHT0, GL_AMBIENT, fLowLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, fBrightLight); glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight); glLightfv(GL_LIGHT0, GL_POSITION, fLightPos); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); //开启颜色追踪 glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glMateriali(GL_FRONT, GL_SHININESS, 128); } int main(int args, char **argv) {
glutInit(&args, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_ACCUM); glutInitWindowSize(800, 600); glutCreateWindow("motion blur"); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); SetupRC(); glutMainLoop(); return 0; }

DrawGeometry函数绘制了场景中的所有几何图元。在RenderScene中反复调用这个函数,并把结果累积到累积缓冲区中。在最后,拷贝回到颜色缓冲区,然后glutSwapBuffers显示到屏幕上:

其他颜色操作

颜色掩码

在计算后的最终颜色将要写入到颜色缓冲区时,OpenGL允许你通过glColorMask函数来屏蔽掉其中的一个或多个通道值。

void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);

参数分别代表红、绿、蓝、alpha通道。当传的参数是GL_TRUE时,表示允许往这个通道的写值,如果为GL_FALSE则阻止往该通道写值。

颜色逻辑操作

许多2D的图形API允许源颜色和目的颜色进行逻辑操作。OpenGL也支持这种操作:

void glLogicOp(GLenum op);

还需要通过glEnable(GL_COLOR_LOGIC_OP);来开启。OpenGL在默认情况下是关闭的。关闭操作是相应的glDisable

op允许的操作如下表:

参数值 操作
GL_CLEAR 0
GL_AND s & d
GL_AND_REVERSE s & ~d
GL_COPY s
GL_AND_INVERTED ~s & d
NOOP d
XOR s xor d
OR s | d
NOR ~(s | d)
GL_EQUIV ~(s xor d)
GL_OR_REVERSE s | ~d
GL_COPY_INVERTED ~s
GL_OR_INVERTED ~s | d
GL_NAND ~(s & d)
SET all 1s

Alpha 测试

Alpha测试允许你告诉OpenGL那些在Alpha测试不通过的输入片段将被废弃。那些被废弃的片段不会写入到颜色缓冲区,深度缓冲区,模板缓冲区和累积缓冲区中。那些alpha值很低的片段可能是不可见的,因此我们可以过滤掉它,不写入到缓冲区中,可以提高性能。

alpha测试值和比较函数可以通过glAlphaFunc指定:

void glAlphaFunc(GLenum func, GLclampf ref);

ref的取值范围为[0.0, 1.0].可以指定的比较方式如下表:

比较方式 描述
GL_NEVER 永远不通过
GL_ALWAYS 一直通过
GL_LESS 小于ref
GL_LEQUAL 小于等于ref
GL_EQUAL 等于ref
GL_GEQUAL 大于等于ref
GL_GREATER 大于ref
GL_NOTEQUAL 不等于ref

行为与glDepthFunc函数相似。可以通过glEnable/glDisable来开启和关闭alpha测试,参数值是GL_ALPHA_TEST。

抖动

抖动允许只有少量离散颜色的显示系统来模拟更宽范围的颜色。例如,灰色可以通过白点和黑点的混合来模拟。白点多于黑点呈现浅灰色,黑点多于白点呈现深灰色。这种技巧对于只支持8位和16位的显示系统非常有用。抖动的效果可以大幅度地改善低端颜色系统的图像质量。在默认情况下,抖动是打开的。可以通过glEnable(GL_DITHER)/glDisable(GL_DITHER)来打开或关闭它。在高颜色分辨率的显示系统中,OpenGL的实现可能不需要抖动,会禁用抖动来避免性能的开销。

转载于:https://my.oschina.net/sweetdark/blog/172316

你可能感兴趣的文章
Golang安装配置
查看>>
详细地演示gb18030到unicode|utf8的转码过程(RUST语言)
查看>>
KVM 虚拟机在物理主机之间迁移的实现 - IBM
查看>>
Android 4.2 系统编译 找不到添加的内部资源 com.android.internal.R
查看>>
Spring Boot WebFlux + Server-sent事件示例
查看>>
Git for windows 中文乱码解决方案
查看>>
python 爬虫
查看>>
OpenGL超级宝典笔记——雾
查看>>
javaScript元素选择器
查看>>
核心交易链路架构设计与演进
查看>>
websocket-bench压力测试
查看>>
http://91.213.30.151/
查看>>
Android ViewStub详解
查看>>
JavaScript中的prototype、__proto__和constructor
查看>>
Android Studio更新升级方法
查看>>
iOS10全新方法实现推送+deviceToken无法获取或无效的解决
查看>>
centos7 修改selinux 开机导致 faild to load SELinux polic
查看>>
Spring3.1 Cache注解
查看>>
c++ ActiveX基础1:使用VS2010创建MFC ActiveX工程项目
查看>>
linux 基础入门一
查看>>