Программа эмуляции эффекта тумана
class CFog : public CObject { DECLARE_SERIAL(CFog) enum {LEN=256}; private: GLfloat alpha_scale, alpha_bias; GLfloat fog_map[LEN]; GLfloat *buffer; int last_width, last_height; // защищённые данные public: GLfloat eye_near, eye_far; GLfloat fog_start, fog_end; GLenum fog_mode; GLfloat fog_density; union { struct {GLfloat fog_red, fog_green, fog_blue, fog_alpha;}; GLfloat fogColor[4]; }; BOOL valid; // состояние не изменялось (не пересчитывать карты, etc) BYTE af; // 0 -> OFF; 1->GL_FOG; 2->AF_FOG // интерфейс для установки параметров программного тумана public: void GLFog(); inline void SetAFType(BYTE type=2) {af=type; valid=FALSE;} inline BYTE GetAFType() {return af;} inline void afEyeNearFar(GLfloat fnear, GLfloat ffar) { eye_near = fnear; eye_far = ffar; valid = FALSE; } inline void afFogStartEnd(GLfloat start, GLfloat end) { fog_start = start; fog_end = end; valid = FALSE; } inline void afFogMode(GLenum mode) { fog_mode = mode; valid = FALSE; } inline void afFogDensity(GLfloat density) { fog_density = density; valid = FALSE; } inline void afFogColor(GLfloat red, GLfloat green, GLfloat blue) { fog_red = red; fog_green = green; fog_blue = blue; } void afDoFinalFogPass(GLint x, GLint y, GLsizei width, GLsizei height); CFog(); virtual ~CFog(); void Serialize(CArchive &ar); }; #include "stdafx.h" #include "GL.h" #include "Fog.h" CFog::CFog() { eye_near = 0.0; eye_far = 1.0; fog_start = 0.0; fog_end = 1.0; fog_mode = GL_EXP; fog_density = 1.0; valid = FALSE; af = TRUE; buffer = 0; fog_alpha = 1.0; } CFog::~CFog(){ if (buffer) delete [] buffer; } void CFog::afDoFinalFogPass(GLint x, GLint y, GLsizei width, GLsizei height) { int i; switch (af){ case 0: glDisable(GL_FOG); return; // туман не нужен case 1: GLFog(); return; // туман GL case 2: glDisable(GL_FOG); break; // программный туман default: return; // этого не может быть! }; if (width * height != last_width * last_height) { if (buffer) delete [] buffer; buffer = new GLfloat[width * height]; last_width = width; last_height = height; } if (!valid) { switch (fog_mode) { case GL_LINEAR: // вычислить alpha для линейного тумана, начиная с "f = (e-z)/(e-s)" alpha_scale = (eye_far - eye_near) / (fog_end - fog_start); alpha_bias = (eye_near - fog_start) / (fog_end - fog_start); break; case GL_EXP: // установить fog_map: "f = exp(-d*z)" for (i = 0; i < LEN; i += 1) { float fi, z, dz; fi = i * 1.0 / (LEN - 1); z = eye_near + fi * (eye_far - eye_near); dz = fog_density * z; fog_map[i] = 1.0 - exp(-dz); } break; case GL_EXP2: // установить fog_map: "f = exp(-d*z)^2)" for (i = 0; i < LEN; i += 1) { float fi, z, dz; fi = i * 1.0 / (LEN - 1); z = eye_near + fi * (eye_far - eye_near); dz = fog_density * z; fog_map[i] = 1.0 - exp(-dz * dz); } break; default:; } valid = TRUE; } // afDoFinalFogPass не пытается сохранить эти переменные ! glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1); // сохранить текущую позицию растра, окно вывода, состояние матриц, // функцию затенения, ... glPushAttrib(GL_PIXEL_MODE_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT | GL_VIEWPORT_BIT | GL_CURRENT_BIT); // перенести текущую позицию растра в (x,y) glMatrixMode(GL_MODELVIEW); glViewport(x-1, y-1, 2, 2); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glRasterPos2i(0, 0); // точно не нужно, чтобы туман или Z-буфер были разрешены glDisable(GL_FOG); glDisable(GL_DEPTH_TEST); // альфа = "1 - f", где f - фактор затенения glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); switch (fog_mode) { case GL_LINEAR: // установить RGB = цвету тумана glPixelTransferf(GL_RED_SCALE, 0); glPixelTransferf(GL_GREEN_SCALE, 0); glPixelTransferf(GL_BLUE_SCALE, 0); glPixelTransferf(GL_RED_BIAS, fog_red); glPixelTransferf(GL_GREEN_BIAS, fog_green); glPixelTransferf(GL_BLUE_BIAS, fog_blue); glPixelTransferf(GL_ALPHA_SCALE, alpha_scale); glPixelTransferf(GL_ALPHA_BIAS, alpha_bias); break; case GL_EXP: case GL_EXP2: // установить RGB = цвету тумана glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 1, &fog_red); glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 1, &fog_green); glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 1, &fog_blue); glPixelMapfv(GL_PIXEL_MAP_A_TO_A, LEN, fog_map); glPixelTransferi(GL_MAP_COLOR, GL_TRUE); break; } // читаем Z-буфер glReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, buffer); // и записывем его обратно вместо альфа glDrawPixels(width, height, GL_ALPHA, GL_FLOAT, buffer); // восстанавливаем установки GL glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); } void CFog::GLFog() { glEnable(GL_FOG); if (!valid) { valid = TRUE; glFogi (GL_FOG_MODE, fog_mode); glHint (GL_FOG_HINT, GL_NICEST); // попиксельный туман glFogf (GL_FOG_START, fog_start); glFogf (GL_FOG_END, fog_end); glFogf(GL_FOG_DENSITY, fog_density); glFogfv (GL_FOG_COLOR, fogColor); } }