OGL雾化

来源:互联网 发布:淘宝能贷款能贷多少 编辑:程序博客网 时间:2024/06/11 07:27
雾是一个通用是术语,用来模拟薄雾,模糊,氛围,烟尘或者污染。
在RGBA或索引颜色模式下,都支持雾。

1.雾颜色着色的时机

顶点雾坐标颜色,应该在顶点处理时在视图空间计算光照后根据雾公式计算雾颜色,且光栅化时插值得到片段像素雾颜色。
具体雾颜色应用到像素上,应该在Fragment Shader 取得纹理颜色后,有镜面光照辅助颜色着色后,再在上面混合雾颜色。

2.雾计算公式和基本设置

GL_EXP模式:f = e ^(-(density*z))
GL_EXP2模式:f = e ^(-(density*z)^2)
GL_LINEAR模式:f = (end - z) / (end-start) 这个计算比较快,常用的雾颜色计算
f是像素颜色和雾颜色的混合因子, z是物体位置距离摄像机的距离是正值;density是雾浓度; start,end是雾开始和全部雾化的距离。
EXT_fog_coord插值有3种(linear、exp、exp2);而Direc3D只对应于linear fog mode。

RGBA模式下雾着色的计算公式:
C = f*Ci + (1-f)*Cf; Ci是源片断的颜色,Cf是GL_FOG_COLOR分配的雾颜色值。
索引颜色模式下雾颜色计算公式:
I = Ii + (1-f)If; Ii是片断颜色索引,If是雾颜色索引。

设置:
 glEnable(GL_FOG);// 开始雾效果。
   {
      GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0};

      fogMode = GL_EXP;
      glFogi (GL_FOG_MODE, fogMode);//设置雾混合因子的计算公式, 雾衰减方式。
      glFogfv (GL_FOG_COLOR, fogColor); // 雾颜色
      glFogf (GL_FOG_DENSITY, 0.35); // 雾浓度
      glHint (GL_FOG_HINT, GL_DONT_CARE); // 像素覆盖值的采样
      glFogf (GL_FOG_START, 1.0); // 雾开始距离
      glFogf (GL_FOG_END, 5.0); // 全雾化的距离, 在全雾化外的物体可以不渲染draw call因此采用雾化在大型程序中可以提高性能。
   }
实例:
#include <GL/glut.h>#include <math.h>#include <stdlib.h>#include <stdio.h>static GLint fogMode;/*  Initialize depth buffer, fog, light source,  *  material property, and lighting model. */static void init(void){   GLfloat position[] = { 0.5, 0.5, 3.0, 0.0 };   glEnable(GL_DEPTH_TEST);   glLightfv(GL_LIGHT0, GL_POSITION, position);   glEnable(GL_LIGHTING);   glEnable(GL_LIGHT0);   {      GLfloat mat[3] = {0.1745, 0.01175, 0.01175};      glMaterialfv (GL_FRONT, GL_AMBIENT, mat);      mat[0] = 0.61424; mat[1] = 0.04136; mat[2] = 0.04136;      glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);      mat[0] = 0.727811; mat[1] = 0.626959; mat[2] = 0.626959;      glMaterialfv (GL_FRONT, GL_SPECULAR, mat);      glMaterialf (GL_FRONT, GL_SHININESS, 0.6*128.0);   }   glEnable(GL_FOG);   {      GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0};      fogMode = GL_EXP;      glFogi (GL_FOG_MODE, fogMode);      glFogfv (GL_FOG_COLOR, fogColor);      glFogf (GL_FOG_DENSITY, 0.35);      glHint (GL_FOG_HINT, GL_DONT_CARE);      glFogf (GL_FOG_START, 1.0);      glFogf (GL_FOG_END, 5.0);   }   glClearColor(0.5, 0.5, 0.5, 1.0);  /* fog color */}static void renderSphere (GLfloat x, GLfloat y, GLfloat z){   glPushMatrix();   glTranslatef (x, y, z);   glutSolidSphere(0.4, 16, 16);   glPopMatrix();}/* display() draws 5 spheres at different z positions. */void display(void){   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   renderSphere (-2., -0.5, -1.0);   renderSphere (-1., -0.5, -2.0);   renderSphere (0., -0.5, -3.0);   renderSphere (1., -0.5, -4.0);   renderSphere (2., -0.5, -5.0);   glFlush();}void reshape(int w, int h){   glViewport(0, 0, (GLsizei) w, (GLsizei) h);   glMatrixMode(GL_PROJECTION);   glLoadIdentity();   if (w <= h)      glOrtho (-2.5, 2.5, -2.5*(GLfloat)h/(GLfloat)w,         2.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);   else      glOrtho (-2.5*(GLfloat)w/(GLfloat)h,         2.5*(GLfloat)w/(GLfloat)h, -2.5, 2.5, -10.0, 10.0);   glMatrixMode(GL_MODELVIEW);   glLoadIdentity ();}void keyboard(unsigned char key, int x, int y){   switch (key) {      case 'f':      case 'F':         if (fogMode == GL_EXP) {    fogMode = GL_EXP2;    printf ("Fog mode is GL_EXP2\n");         }         else if (fogMode == GL_EXP2) {            fogMode = GL_LINEAR;            printf ("Fog mode is GL_LINEAR\n");         }         else if (fogMode == GL_LINEAR) {            fogMode = GL_EXP;            printf ("Fog mode is GL_EXP\n");         }         glFogi (GL_FOG_MODE, fogMode);         glutPostRedisplay();         break;      case 27:         exit(0);         break;      default:         break;   }}/*  Main Loop *  Open window with initial window size, title bar,  *  RGBA display mode, depth buffer, and handle input events. */int main(int argc, char** argv){   glutInit(&argc, argv);   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);   glutInitWindowSize(500, 500);   glutCreateWindow(argv[0]);   init();   glutReshapeFunc (reshape);   glutKeyboardFunc (keyboard);   glutDisplayFunc (display);   glutMainLoop();   return 0;}


3.雾坐标的设置

在雾计算公式中,z值默认是根据观察点和片断的距离自动计算生成的,但是也可以显式设置,目的是为了实现基于水平面的雾(例如高空飞行器)中。
开始显式设置雾坐标:
glFogi(GL_FOG_COORD_SRC, GL_FOG_COORD);// GL_FRAGMENT_DEPTH是根据深度自动计算。
float f1 = 1.0f;
glFogCoordf(f1); // 设置雾坐标。

0 0