Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/atmospheric_engine/src/lib/graphics/effects/cloud_effect.cc @ 8716

Last change on this file since 8716 was 8713, checked in by hdavid, 19 years ago

branches/atmospheric_engine

File size: 10.3 KB
Line 
1/*
2  orxonox - the future of 3D-vertical-scrollers
3 
4  Copyright (C) 2004 orx
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2, or (at your option)
9  any later version.
10 
11### File Specific:
12  main-programmer: hdavid, amaechler
13 
14  INSPIRED BY http://www.codesampler.com/usersrc/usersrc_6.htm#oglu_sky_dome_shader
15*/
16
17#include "cloud_effect.h"
18
19#include "util/loading/load_param.h"
20#include "util/loading/factory.h"
21#include "util/loading/resource_manager.h"
22
23#include "material.h"
24#include "state.h"
25#include "p_node.h"
26#include "shader.h"
27#include "shell_command.h"
28
29#include "parser/tinyxml/tinyxml.h"
30
31
32using namespace std;
33
34SHELL_COMMAND(activate, CloudEffect, activateCloud);
35SHELL_COMMAND(deactivate, CloudEffect, deactivateCloud);
36
37CREATE_FACTORY(CloudEffect, CL_CLOUD_EFFECT);
38
39CloudEffect::CloudEffect(const TiXmlElement* root)
40{
41  this->setClassID(CL_CLOUD_EFFECT, "CloudEffect");
42
43  this->init();
44
45  if (root != NULL)
46    this->loadParams(root);
47
48  if(cloudActivate)
49    this->activate();
50}
51
52CloudEffect::~CloudEffect()
53{
54  this->deactivate();
55 
56  delete shader;
57}
58
59
60void CloudEffect::init()
61{
62  PRINTF(0)("Initializing CloudEffect\n");
63 
64  this->offsetZ = 0;
65  this->animationSpeed = 2;
66  this->scale = 0.0004f;
67  this->atmosphericRadius = 4000;
68  this->planetRadius = 1500;
69  this->divs = 50;
70
71  noise3DTexSize = 128;
72  noise3DTexName = 0;
73
74  this->make3DNoiseTexture();
75
76  glGenTextures(1, &noise3DTexName);
77  glBindTexture(GL_TEXTURE_3D, noise3DTexName);
78
79  glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
80  glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
81  glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
82  glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
83  glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
84
85  glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA,
86               noise3DTexSize, noise3DTexSize, noise3DTexSize,
87               0, GL_RGBA, GL_UNSIGNED_BYTE, noise3DTexPtr);
88 
89  shader = new Shader(ResourceManager::getInstance()->getDataDir() + "/shaders/cloud.vert",
90                      ResourceManager::getInstance()->getDataDir() + "/shaders/cloud.frag");
91
92  this->shader->activateShader();
93
94  Shader::Uniform(shader, "Noise").set(0);
95  Shader::Uniform(shader, "SkyColor").set(0.0f, 0.0f, 0.8f);
96  Shader::Uniform(shader, "CloudColor").set(0.8f, 0.8f, 0.8f);
97 
98  offset = new Shader::Uniform(shader, "Offset");
99
100  this->shader->deactivateShader();
101}
102
103
104void CloudEffect::loadParams(const TiXmlElement* root)
105{
106  WeatherEffect::loadParams(root);
107
108  LoadParam(root, "speed", this, CloudEffect, setAnimationSpeed);
109  LoadParam(root, "scale", this, CloudEffect, setCloudScale);
110 
111  LoadParam(root, "planetRadius", this, CloudEffect, setPlanetRadius);
112  LoadParam(root, "atmosphericRadius", this, CloudEffect, setAtmosphericRadius);
113  LoadParam(root, "divisions", this, CloudEffect, setDivisions);
114 
115  LOAD_PARAM_START_CYCLE(root, element);
116  {
117    LoadParam_CYCLE(element, "option", this, CloudEffect, setCloudOption);
118  }
119  LOAD_PARAM_END_CYCLE(element);
120}
121
122
123void CloudEffect::activate()
124{
125  PRINTF(0)( "Activating\n");
126 
127  // Can only be set after the loadParams call
128  this->shader->activateShader();
129  Shader::Uniform(shader, "Scale").set(this->scale);
130  this->shader->deactivateShader();
131 
132  this->generateSkyPlane(this->divs, this->planetRadius, this->atmosphericRadius, 1, 1);
133
134  this->cloudActivate = true;
135}
136
137void CloudEffect::deactivate()
138{
139  PRINTF(0)("Deactivating CloudEffect\n");
140
141  this->cloudActivate = false;
142}
143
144void CloudEffect::draw() const
145{
146  if (!this->cloudActivate)
147    return;
148
149  glPushAttrib(GL_ENABLE_BIT);
150
151  glDisable(GL_LIGHTING);
152  glDisable(GL_BLEND);
153
154  glEnable(GL_TEXTURE_3D);
155  glBindTexture(GL_TEXTURE_3D, noise3DTexName);
156
157  this->shader->activateShader();
158  offset->set(0.0f, 0.0f, offsetZ);
159
160
161  /*glColor3f(1.0, 1.0, 1.0);
162  glBegin(GL_QUADS);
163
164  glTexCoord2f(1.0f, 1.0f); glVertex3f(0.0f, 0.0f,  0.0f);
165  glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.0f, 10.0f,  0.0f);
166  glTexCoord2f(0.0f, 0.0f); glVertex3f( 10.0f, 10.0f,  0.0f);
167  glTexCoord2f(1.0f, 0.0f); glVertex3f(10.0f, 0.0f,  0.0f);
168
169  glEnd();*/
170
171  glPushMatrix();
172  glTranslatef(0.0f,pRadius,0.0f);
173  //glRotatef(timeGetTime()/2000.0f,0.0f, 1.0f, 0.0f);
174
175  glBegin(GL_TRIANGLES);
176
177  for (int i=0; i < numIndices; i++)
178  {
179    glColor3f(1.0f, 1.0f, 1.0f);
180
181    glTexCoord2f(planeVertices[indices[i]].u, planeVertices[indices[i]].v);
182    glVertex3f(planeVertices[indices[i]].x, planeVertices[indices[i]].y, planeVertices[indices[i]].z);
183  }
184
185  glEnd();
186
187  glPopMatrix();
188
189  this->shader->deactivateShader();
190
191  glPopAttrib();
192
193}
194
195void CloudEffect::tick (float dt)
196{
197  if (this->cloudActivate)
198    this->offsetZ += 0.05 * dt * this->animationSpeed;
199}
200
201void CloudEffect::generateSkyPlane(int divisions, float planetRadius, float atmosphereRadius, float hTile, float vTile)
202{
203  // Make sure our vertex array is clear
204  if (planeVertices) 
205  {
206    delete planeVertices;
207    planeVertices = NULL;
208  }
209
210  // Make sure our index array is clear
211  if (indices)
212  {
213    delete indices;
214    indices = NULL;
215  }
216
217  // Set the number of divisions into a valid range
218  int divs = divisions;
219  if (divisions < 1) 
220    divs = 1;
221
222  if (divisions > 256) 
223    divs = 256; 
224
225  pRadius = planetRadius;
226
227  // Initialize the Vertex and indices arrays
228  numPlaneVertices = (divs + 1) * (divs + 1);   // 1 division would give 4 verts
229  numIndices  = divs * divs * 2 * 3;       // 1 division would give 6 indices for 2 tris
230
231  planeVertices = new VERTEX[numPlaneVertices];
232  memset(planeVertices, 0, sizeof(VERTEX));
233
234  indices = new int[numIndices];
235  memset(indices, 0, sizeof(int)*numIndices);
236
237  // Calculate some values we will need
238  float plane_size = 2.0f * (float)sqrt((SQR(atmosphereRadius)-SQR(planetRadius)));
239  float delta = plane_size/(float)divs;
240  float tex_delta = 2.0f/(float)divs;
241 
242  // Variables we'll use during the dome's generation
243  float x_dist   = 0.0f;
244  float z_dist   = 0.0f;
245  float x_height = 0.0f;
246  float z_height = 0.0f;
247  float height = 0.0f;
248
249  VERTEX SV; // temporary vertex
250
251  for (int i=0;i <= divs;i++)
252  {
253    for (int j=0; j <= divs; j++)
254    {
255      x_dist = (-0.5f * plane_size) + ((float)j*delta);
256      z_dist = (-0.5f * plane_size) + ((float)i*delta);
257
258      x_height = (x_dist*x_dist) / atmosphereRadius;
259      z_height = (z_dist*z_dist) / atmosphereRadius;
260      height = x_height + z_height;
261
262      SV.x = x_dist;
263      SV.y = 0.0f - height;
264      SV.z = z_dist;
265
266      // Calculate the texture coordinates
267      SV.u = hTile*((float)j * tex_delta*0.5f);
268      SV.v = vTile*(1.0f - (float)i * tex_delta*0.5f);
269
270      planeVertices[i*(divs+1)+j] = SV;
271    }
272  }
273
274  // Calculate the indices
275  int index = 0;
276  for (int i=0; i < divs;i++)
277  {
278    for (int j=0; j < divs; j++)
279    {
280      int startvert = (i*(divs+1) + j);
281
282        // tri 1
283      indices[index++] = startvert;
284      indices[index++] = startvert+1;
285      indices[index++] = startvert+divs+1;
286
287      // tri 2
288      indices[index++] = startvert+1;
289      indices[index++] = startvert+divs+2;
290      indices[index++] = startvert+divs+1;
291    }
292  } 
293}
294
295void CloudEffect::make3DNoiseTexture()
296{
297  int f, i, j, k, inc;
298  int startFrequency = 4;
299  int numOctaves = 4;
300  double ni[3];
301  double inci, incj, inck;
302  int frequency = startFrequency;
303  GLubyte *ptr;
304  double amp = 0.5;
305
306  if ((noise3DTexPtr = (GLubyte *) malloc(noise3DTexSize *
307                                          noise3DTexSize *
308                                          noise3DTexSize * 4)) == NULL)
309    PRINTF(0)("ERROR: Could not allocate 3D noise texture\n");
310
311  for (f=0, inc=0; f < numOctaves;
312       ++f, frequency *= 2, ++inc, amp *= 0.5)
313  {
314    SetNoiseFrequency(frequency);
315    ptr = noise3DTexPtr;
316    ni[0] = ni[1] = ni[2] = 0;
317
318    inci = 1.0 / (noise3DTexSize / frequency);
319    for (i=0; i<noise3DTexSize; ++i, ni[0] += inci)
320    {
321      incj = 1.0 / (noise3DTexSize / frequency);
322      for (j=0; j<noise3DTexSize; ++j, ni[1] += incj)
323      {
324        inck = 1.0 / (noise3DTexSize / frequency);
325        for (k=0; k<noise3DTexSize; ++k, ni[2] += inck, ptr+= 4)
326        {
327          *(ptr+inc) = (GLubyte) (((noise3(ni)+1.0) * amp)*128.0);
328        }
329      }
330    }
331  }
332}
333
334void CloudEffect::initNoise()
335{
336  int i, j, k;
337
338  srand(30757);
339  for (i = 0 ; i < B ; i++)
340  {
341    p[i] = i;
342    g1[i] = (double)((rand() % (B + B)) - B) / B;
343
344    for (j = 0 ; j < 2 ; j++)
345      g2[i][j] = (double)((rand() % (B + B)) - B) / B;
346    normalize2(g2[i]);
347
348    for (j = 0 ; j < 3 ; j++)
349      g3[i][j] = (double)((rand() % (B + B)) - B) / B;
350    normalize3(g3[i]);
351  }
352
353  while (--i)
354  {
355    k = p[i];
356    p[i] = p[j = rand() % B];
357    p[j] = k;
358  }
359
360  for (i = 0 ; i < B + 2 ; i++)
361  {
362    p[B + i] = p[i];
363    g1[B + i] = g1[i];
364    for (j = 0 ; j < 2 ; j++)
365      g2[B + i][j] = g2[i][j];
366    for (j = 0 ; j < 3 ; j++)
367      g3[B + i][j] = g3[i][j];
368  }
369}
370
371void CloudEffect::SetNoiseFrequency( int frequency)
372{
373  start = 1;
374  B = frequency;
375  BM = B-1;
376}
377
378double CloudEffect::noise3( double vec[3])
379{
380  int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
381  double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
382  int i, j;
383
384  if (start)
385  {
386    start = 0;
387    initNoise();
388  }
389
390  setup(0, bx0,bx1, rx0,rx1);
391  setup(1, by0,by1, ry0,ry1);
392  setup(2, bz0,bz1, rz0,rz1);
393
394  i = p[ bx0 ];
395  j = p[ bx1 ];
396
397  b00 = p[ i + by0 ];
398  b10 = p[ j + by0 ];
399  b01 = p[ i + by1 ];
400  b11 = p[ j + by1 ];
401
402  t  = s_curve(rx0);
403  sy = s_curve(ry0);
404  sz = s_curve(rz0);
405
406  q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0);
407  q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0);
408  a = lerp(t, u, v);
409
410  q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0);
411  q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0);
412  b = lerp(t, u, v);
413
414  c = lerp(sy, a, b);
415
416  q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1);
417  q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1);
418  a = lerp(t, u, v);
419
420  q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1);
421  q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1);
422  b = lerp(t, u, v);
423
424  d = lerp(sy, a, b);
425
426  return lerp(sz, c, d);
427}
428
429void CloudEffect::normalize2( double v[2])
430{
431  double s;
432
433  s = sqrt(v[0] * v[0] + v[1] * v[1]);
434  v[0] = v[0] / s;
435  v[1] = v[1] / s;
436}
437
438void CloudEffect::normalize3( double v[3])
439{
440  double s;
441
442  s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
443  v[0] = v[0] / s;
444  v[1] = v[1] / s;
445  v[2] = v[2] / s;
446}
447
Note: See TracBrowser for help on using the repository browser.