Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8704 was 8700, checked in by amaechler, 18 years ago

branches/atmospheric_engine: …

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