fog.cpp
上传用户:qccn516
上传日期:2013-05-02
资源大小:3382k
文件大小:7k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /* Fog
  2.  *
  3.  * Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include "mesh.h"
  20. #include "pbuffer.h"
  21. #include "texture.h"
  22. #include "shader.h"
  23. #include "engine.h"
  24. #include "fog.h"
  25. int Fog::counter = 0;
  26. PBuffer *Fog::pbuffer;
  27. Texture *Fog::depth_tex;
  28. Texture *Fog::fog_tex;
  29. PBuffer *Fog::pbuffers[3];
  30. Texture *Fog::depth_texes[3];
  31. Texture *Fog::fog_texes[3];
  32. Shader *Fog::depth_to_rgb_shader;
  33. Shader *Fog::pass_shader;
  34. Shader *Fog::fail_shader;
  35. Shader *Fog::final_shader;
  36. /*
  37.  */
  38. Fog::Fog(Mesh *mesh,const vec4 &color) : mesh(mesh), color(color) {
  39. pos.radius = getRadius();
  40. pos = getCenter();
  41. if(counter++ == 0) { // loading global objects
  42. for(int i = 0; i < 3; i++) {
  43. pbuffers[i] = new PBuffer(128 << i,128 << i,PBuffer::RGBA | PBuffer::DEPTH | PBuffer::STENCIL);
  44. pbuffers[i]->enable();
  45. glClearColor(0,0,0,1);
  46. glEnable(GL_DEPTH_TEST);
  47. glEnable(GL_CULL_FACE);
  48. pbuffers[i]->disable();
  49. depth_texes[i] = new Texture(128 << i,128 << i,Texture::TEXTURE_2D,Texture::RGB | Texture::NEAREST);
  50. fog_texes[i] = new Texture(128 << i,128 << i,Texture::TEXTURE_2D,Texture::RGBA | Texture::LINEAR);
  51. }
  52. depth_to_rgb_shader = Engine::loadShader(FOG_DEPTH_TO_RGB);
  53. pass_shader = Engine::loadShader(FOG_PASS);
  54. fail_shader = Engine::loadShader(FOG_FAIL);
  55. final_shader = Engine::loadShader(FOG_FINAL);
  56. }
  57. }
  58. Fog::~Fog() {
  59. if(--counter == 0) {
  60. for(int i = 0; i < 3; i++) {
  61. delete pbuffers[i];
  62. delete depth_texes[i];
  63. delete fog_texes[i];
  64. }
  65. delete depth_to_rgb_shader;
  66. delete pass_shader;
  67. delete fail_shader;
  68. }
  69. }
  70. /*
  71.  */
  72. void Fog::enable() {
  73. // give color to shader
  74. Engine::fog_color = color;
  75. // select best resolution
  76. // depend on viewport size
  77. if(Engine::viewport[3] > 512) {
  78. pbuffer = pbuffers[2];
  79. depth_tex = depth_texes[2];
  80. fog_tex = fog_texes[2];
  81. } else if(Engine::viewport[2] > 256) {
  82. pbuffer = pbuffers[1];
  83. depth_tex = depth_texes[1];
  84. fog_tex = fog_texes[1];
  85. } else {
  86. pbuffer = pbuffers[0];
  87. depth_tex = depth_texes[0];
  88. fog_tex = fog_texes[0];
  89. }
  90. // activate pbuffer
  91. pbuffer->enable();
  92. glGetIntegerv(GL_VIEWPORT,Engine::viewport);
  93. // load matrixes
  94. glMatrixMode(GL_PROJECTION);
  95. glLoadMatrixf(Engine::projection);
  96. glMatrixMode(GL_MODELVIEW);
  97. glLoadMatrixf(Engine::modelview);
  98. if(Engine::modelview.det() < 0.0) glFrontFace(GL_CW);
  99. else glFrontFace(GL_CCW);
  100. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  101. depth_to_rgb_shader->enable();
  102. depth_to_rgb_shader->bind();
  103. // render scene without materials (one pass)
  104. }
  105. void Fog::disable() {
  106. // render back triangles
  107. glCullFace(GL_FRONT);
  108. Engine::num_triangles += mesh->render(true);
  109. glCullFace(GL_BACK);
  110. depth_to_rgb_shader->disable();
  111. // save depth values
  112. depth_tex->bind();
  113. depth_tex->copy();
  114. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  115. // fog pass
  116. pass_shader->enable();
  117. pass_shader->bind();
  118. depth_tex->bind();
  119. Engine::num_triangles += mesh->render(true);
  120. pass_shader->disable();
  121. // find fog fail area
  122. glEnable(GL_STENCIL_TEST);
  123. glDepthFunc(GL_ALWAYS);
  124. glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
  125. glStencilFunc(GL_ALWAYS,1,~0);
  126. glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
  127. glCullFace(GL_FRONT);
  128. Engine::num_triangles += mesh->render();
  129. glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);
  130. glCullFace(GL_BACK);
  131. Engine::num_triangles += mesh->render();
  132. glStencilFunc(GL_EQUAL,1,~0);
  133. glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
  134. glCullFace(GL_FRONT);
  135. glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
  136. // fog fail
  137. fail_shader->enable();
  138. fail_shader->bind();
  139. depth_tex->bind();
  140. Engine::num_triangles += mesh->render(true);
  141. fail_shader->disable();
  142. glCullFace(GL_BACK);
  143. glDepthFunc(GL_LESS);
  144. glDisable(GL_STENCIL_TEST);
  145. fog_tex->bind();
  146. fog_tex->copy();
  147. pbuffer->disable();
  148. glGetIntegerv(GL_VIEWPORT,Engine::viewport);
  149. }
  150. /*
  151.  */
  152. int Fog::render() {
  153. glEnable(GL_BLEND);
  154. glBlendFunc(GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA);
  155. final_shader->enable();
  156. final_shader->bind();
  157. fog_tex->bind();
  158. int ret = mesh->render(true);
  159. // find fog fail area
  160. glEnable(GL_STENCIL_TEST);
  161. glDepthFunc(GL_ALWAYS);
  162. glClear(GL_STENCIL_BUFFER_BIT);
  163. glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
  164. glStencilFunc(GL_ALWAYS,1,~0);
  165. glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
  166. glCullFace(GL_FRONT);
  167. ret += mesh->render(true);
  168. glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);
  169. glCullFace(GL_BACK);
  170. ret += mesh->render(true);
  171. glStencilFunc(GL_EQUAL,1,~0);
  172. glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
  173. glCullFace(GL_FRONT);
  174. glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
  175. // fog fail
  176. ret += mesh->render(false);
  177. glCullFace(GL_BACK);
  178. glDepthFunc(GL_LESS);
  179. glDisable(GL_STENCIL_TEST);
  180. final_shader->disable();
  181. glDisable(GL_BLEND);
  182. return ret;
  183. }
  184. /*
  185.  */
  186. float Fog::getDensity(const vec3 &point) {
  187. float dist = 0;
  188. vec3 p0,n0,p1,n1;
  189. vec3 dir = point - Engine::camera;
  190. dir.normalize();
  191. if(mesh->intersection(Engine::camera,point,p0,n0)) {
  192. if(mesh->intersection(p0 + dir * 0.001,point,p1,n1)) { // two intersections
  193. dist = (p1 - p0).length();
  194. } else { // one intersection
  195. if(inside(point)) dist = (point - p0).length();
  196. else dist = (p0 - Engine::camera).length();
  197. }
  198. } else { // zero intersections
  199. // but camera and point in the fog
  200. if(inside(Engine::camera)) dist = (point - Engine::camera).length();
  201. }
  202. return pow(2.0,-dist * color.w / 256.0 * 64.0);
  203. }
  204. int Fog::inside(const vec3 &point) {
  205. for(int i = 0; i < mesh->getNumSurfaces(); i++) {
  206. int num_triangles = mesh->getNumTriangles(i);
  207. Mesh::Triangle *triangles = mesh->getTriangles(i);
  208. for(int j = 0; j < num_triangles; j++) {
  209. if(triangles[j].plane * vec4(point,1) > 0.0) return 0;
  210. }
  211. }
  212. return 1;
  213. }
  214. /*
  215.  */
  216. const vec3 &Fog::getMin() {
  217. return mesh->getMin();
  218. }
  219. const vec3 &Fog::getMax() {
  220. return mesh->getMax();
  221. }
  222. const vec3 &Fog::getCenter() {
  223. return mesh->getCenter();
  224. }
  225. float Fog::getRadius() {
  226. return mesh->getRadius();
  227. }