OSDN Git Service

modified: utilsrc/src/Admin/Makefile
[eos/others.git] / utiltools / X86MAC64 / cuda / samples / 5_Simulations / smokeParticles / SmokeRenderer.cpp
1 /*
2  * Copyright 1993-2013 NVIDIA Corporation.  All rights reserved.
3  *
4  * Please refer to the NVIDIA end user license agreement (EULA) associated
5  * with this source code for terms and conditions that govern your use of
6  * this software. Any use, reproduction, disclosure, or distribution of
7  * this software and related documentation outside the terms of the EULA
8  * is strictly prohibited.
9  *
10  */
11
12 /*
13     This class renders particles using OpenGL and GLSL shaders
14 */
15
16 #include <math.h>
17 #include <stdlib.h>
18 #include "SmokeRenderer.h"
19 #include "SmokeShaders.h"
20
21 #if defined(__APPLE__) || defined(MACOSX)
22 #include <GLUT/glut.h>
23 #else
24 #include <GL/freeglut.h>
25 #endif
26
27 #define USE_MBLUR 1
28 #define COLOR_ATTENUATION 1
29
30 SmokeRenderer::SmokeRenderer(int maxParticles) :
31     mMaxParticles(maxParticles),
32     mNumParticles(0),
33     mPosVbo(0),
34     mVelVbo(0),
35     mColorVbo(0),
36     mIndexBuffer(0),
37     mParticleRadius(0.005f),
38     mDisplayMode(VOLUMETRIC),
39     mWindowW(800),
40     mWindowH(600),
41     mFov(40.0f),
42     m_downSample(2),
43     m_numSlices(32),
44     m_numDisplayedSlices(32),
45     m_sliceNo(0),
46     m_shadowAlpha(0.005f),
47     m_spriteAlpha(0.1f),
48     m_doBlur(false),
49     m_blurRadius(1.0f),
50     m_displayLightBuffer(false),
51     m_lightPos(5.0f, 5.0f, -5.0f),
52     m_lightTarget(0.0f, 0.0f, 0.0f),
53     m_lightColor(1.0f, 1.0f, 0.5f),
54     m_colorAttenuation(0.1f, 0.2f, 0.3f),
55     m_lightBufferSize(256),
56     m_srcLightTexture(0),
57     m_lightDepthTexture(0),
58     m_lightFbo(0),
59     m_imageTex(0),
60     m_depthTex(0),
61     m_imageFbo(0)
62 {
63     // load shader programs
64     m_simpleProg = new GLSLProgram(particleVS, simplePS);
65     m_particleProg = new GLSLProgram(mblurVS, mblurGS, particlePS);
66     m_particleShadowProg = new GLSLProgram(mblurVS, mblurGS, particleShadowPS);
67
68     m_blurProg = new GLSLProgram(passThruVS, blurPS);
69     m_displayTexProg = new GLSLProgram(passThruVS, texture2DPS);
70
71     // create buffer for light shadows
72     createLightBuffer();
73
74     glutReportErrors();
75 }
76
77
78 SmokeRenderer::~SmokeRenderer()
79 {
80     delete m_particleProg;
81     delete m_particleShadowProg;
82     delete m_blurProg;
83     delete m_displayTexProg;
84     delete m_simpleProg;
85
86     delete m_lightFbo;
87     glDeleteTextures(2, m_lightTexture);
88     glDeleteTextures(1, &m_lightDepthTexture);
89
90     delete m_imageFbo;
91     glDeleteTextures(1, &m_imageTex);
92     glDeleteTextures(1, &m_depthTex);
93 }
94
95 // draw points from vertex buffer objects
96 void SmokeRenderer::drawPoints(int start, int count, bool sort)
97 {
98     glBindBufferARB(GL_ARRAY_BUFFER_ARB, mPosVbo);
99     glVertexPointer(4, GL_FLOAT, 0, 0);
100     glEnableClientState(GL_VERTEX_ARRAY);
101
102     if (mColorVbo)
103     {
104         glBindBufferARB(GL_ARRAY_BUFFER_ARB, mColorVbo);
105         glColorPointer(4, GL_FLOAT, 0, 0);
106         glEnableClientState(GL_COLOR_ARRAY);
107     }
108
109     if (mVelVbo)
110     {
111         glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVelVbo);
112         glClientActiveTexture(GL_TEXTURE0);
113         glTexCoordPointer(4, GL_FLOAT, 0, 0);
114         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
115     }
116
117     if (sort)
118     {
119         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mIndexBuffer);
120         glDrawElements(GL_POINTS, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)));
121         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
122     }
123     else
124     {
125         glDrawArrays(GL_POINTS, start, count);
126     }
127
128     glDisableClientState(GL_VERTEX_ARRAY);
129     glDisableClientState(GL_COLOR_ARRAY);
130
131     glClientActiveTexture(GL_TEXTURE0);
132     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
133 }
134
135 // draw points using given shader program
136 void SmokeRenderer::drawPointSprites(GLSLProgram *prog, int start, int count, bool shadowed)
137 {
138     glEnable(GL_DEPTH_TEST);
139     glDepthMask(GL_FALSE);  // don't write depth
140     glEnable(GL_BLEND);
141
142     prog->enable();
143     prog->setUniform1f("pointRadius", mParticleRadius);
144
145     if (shadowed)
146     {
147         prog->bindTexture("shadowTex", m_lightTexture[m_srcLightTexture], GL_TEXTURE_2D, 0);
148     }
149
150     // draw points
151     drawPoints(start, count, true);
152
153     prog->disable();
154
155     glDepthMask(GL_TRUE);
156     glDisable(GL_BLEND);
157 }
158
159 // calculate vectors for half-angle slice rendering
160 void SmokeRenderer::calcVectors()
161 {
162     // get model view matrix
163     glGetFloatv(GL_MODELVIEW_MATRIX, (float *) m_modelView.get_value());
164
165     // calculate eye space light vector
166     m_lightVector = normalize(m_lightPos);
167     m_lightPosEye = m_modelView * vec4f(m_lightPos, 1.0);
168
169     // calculate half-angle vector between view and light
170     m_viewVector = -vec3f(m_modelView.get_row(2));
171
172     if (dot(m_viewVector, m_lightVector) > 0)
173     {
174         m_halfVector = normalize(m_viewVector + m_lightVector);
175         m_invertedView = false;
176     }
177     else
178     {
179         m_halfVector = normalize(-m_viewVector + m_lightVector);
180         m_invertedView = true;
181     }
182
183     // calculate light view matrix
184     glMatrixMode(GL_MODELVIEW);
185     glPushMatrix();
186     glLoadIdentity();
187     gluLookAt(m_lightPos[0], m_lightPos[1], m_lightPos[2],
188               m_lightTarget[0], m_lightTarget[1], m_lightTarget[2],
189               0.0, 1.0, 0.0);
190
191     // calculate light projection matrix
192     glMatrixMode(GL_PROJECTION);
193     glPushMatrix();
194     glLoadIdentity();
195     gluPerspective(45.0, 1.0, 1.0, 200.0);
196
197     glGetFloatv(GL_MODELVIEW_MATRIX, (float *) m_lightView.get_value());
198     glGetFloatv(GL_PROJECTION_MATRIX, (float *) m_lightProj.get_value());
199
200     glMatrixMode(GL_PROJECTION);
201     glPopMatrix();
202     glMatrixMode(GL_MODELVIEW);
203     glPopMatrix();
204
205     // construct shadow matrix
206     matrix4f scale;
207     scale.set_scale(vec3f(0.5, 0.5, 0.5));
208     matrix4f translate;
209     translate.set_translate(vec3f(0.5, 0.5, 0.5));
210
211     m_shadowMatrix = translate * scale * m_lightProj * m_lightView * inverse(m_modelView);
212
213     // calc object space eye position
214     m_eyePos = inverse(m_modelView) * vec4f(0.0, 0.0, 0.0, 1.0);
215
216     // calc half vector in eye space
217     m_halfVectorEye = m_modelView * vec4f(m_halfVector, 0.0);
218 }
219
220 // draw slice of particles from camera view
221 void SmokeRenderer::drawSlice(int i)
222 {
223     m_imageFbo->Bind();
224     glViewport(0, 0, m_imageW, m_imageH);
225
226     glColor4f(1.0, 1.0, 1.0, m_spriteAlpha);
227
228     if (m_invertedView)
229     {
230         // front-to-back
231         glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
232     }
233     else
234     {
235         // back-to-front
236         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
237     }
238
239     drawPointSprites(m_particleShadowProg, i*m_batchSize, m_batchSize, true);
240
241     m_imageFbo->Disable();
242 }
243
244 // draw slice of particles from light's point of view
245 void SmokeRenderer::drawSliceLightView(int i)
246 {
247     glMatrixMode(GL_MODELVIEW);
248     glPushMatrix();
249     glLoadMatrixf((GLfloat *) m_lightView.get_value());
250
251     glMatrixMode(GL_PROJECTION);
252     glPushMatrix();
253     glLoadMatrixf((GLfloat *) m_lightProj.get_value());
254
255     m_lightFbo->Bind();
256     glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
257
258     glColor4f(m_colorAttenuation[0] * m_shadowAlpha, m_colorAttenuation[1] * m_shadowAlpha, m_colorAttenuation[2] * m_shadowAlpha, 1.0);
259     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
260
261     drawPointSprites(m_particleProg, i*m_batchSize, m_batchSize, false);
262
263     m_lightFbo->Disable();
264
265     glMatrixMode(GL_PROJECTION);
266     glPopMatrix();
267     glMatrixMode(GL_MODELVIEW);
268     glPopMatrix();
269 }
270
271 // draw particles as slices with shadowing
272 void SmokeRenderer::drawSlices()
273 {
274     m_batchSize = mNumParticles / m_numSlices;
275
276     // clear light buffer
277     m_srcLightTexture = 0;
278     m_lightFbo->Bind();
279     m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[m_srcLightTexture], GL_COLOR_ATTACHMENT0_EXT);
280     glClearColor(1.0f - m_lightColor[0], 1.0f - m_lightColor[1], 1.0f - m_lightColor[2], 0.0f);
281     glClear(GL_COLOR_BUFFER_BIT);
282     m_lightFbo->Disable();
283
284     // clear volume image
285     m_imageFbo->Bind();
286     glClearColor(0.0, 0.0, 0.0, 0.0);
287     glClear(GL_COLOR_BUFFER_BIT);
288     m_imageFbo->Disable();
289
290     glActiveTexture(GL_TEXTURE0);
291     glMatrixMode(GL_TEXTURE);
292     glLoadMatrixf((GLfloat *) m_shadowMatrix.get_value());
293
294     // render slices
295     if (m_numDisplayedSlices > m_numSlices) m_numDisplayedSlices = m_numSlices;
296
297     for (int i=0; i<m_numDisplayedSlices; i++)
298     {
299         // draw slice from camera view, sampling light buffer
300         drawSlice(i);
301         // draw slice from light view to light buffer, accumulating shadows
302         drawSliceLightView(i);
303
304         if (m_doBlur)
305         {
306             blurLightBuffer();
307         }
308     }
309
310     glActiveTexture(GL_TEXTURE0);
311     glMatrixMode(GL_TEXTURE);
312     glLoadIdentity();
313 }
314
315 // blur light buffer to simulate scattering effects
316 void SmokeRenderer::blurLightBuffer()
317 {
318     m_lightFbo->Bind();
319     m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[1 - m_srcLightTexture], GL_COLOR_ATTACHMENT0_EXT);
320     glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
321
322     m_blurProg->enable();
323     m_blurProg->bindTexture("tex", m_lightTexture[m_srcLightTexture], GL_TEXTURE_2D, 0);
324     m_blurProg->setUniform2f("texelSize", 1.0f / (float) m_lightBufferSize, 1.0f / (float) m_lightBufferSize);
325     m_blurProg->setUniform1f("blurRadius", m_blurRadius);
326     glDisable(GL_DEPTH_TEST);
327     drawQuad();
328     m_blurProg->disable();
329
330     m_srcLightTexture = 1 - m_srcLightTexture;
331
332     m_lightFbo->Disable();
333 }
334
335 // display texture to screen
336 void SmokeRenderer::displayTexture(GLuint tex)
337 {
338     m_displayTexProg->enable();
339     m_displayTexProg->bindTexture("tex", tex, GL_TEXTURE_2D, 0);
340     drawQuad();
341     m_displayTexProg->disable();
342 }
343
344 // composite final volume image on top of scene
345 void SmokeRenderer::compositeResult()
346 {
347     glViewport(0, 0, mWindowW, mWindowH);
348     glDisable(GL_DEPTH_TEST);
349     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
350     glEnable(GL_BLEND);
351     displayTexture(m_imageTex);
352     glDisable(GL_BLEND);
353 }
354
355 void SmokeRenderer::render()
356 {
357     switch (mDisplayMode)
358     {
359         case POINTS:
360             glColor3f(1.0, 1.0, 1.0);
361             m_simpleProg->enable();
362             drawPoints(0, mNumParticles, false);
363             m_simpleProg->disable();
364             break;
365
366         case SPRITES:
367             glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
368             glColor4f(1.0, 1.0, 1.0, m_spriteAlpha);
369             drawPointSprites(m_particleProg, 0, mNumParticles, false);
370             break;
371
372         case VOLUMETRIC:
373             drawSlices();
374             compositeResult();
375             break;
376
377         case NUM_MODES:
378             break;
379     }
380
381     if (m_displayLightBuffer)
382     {
383         // display light buffer to screen
384         glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
385         glDisable(GL_DEPTH_TEST);
386         displayTexture(m_lightTexture[m_srcLightTexture]);
387         glViewport(0, 0, mWindowW, mWindowH);
388     }
389
390     glutReportErrors();
391 }
392
393 // render scene depth to texture
394 // (this is to ensure that particle are correctly occluded in the low-resolution render buffer)
395 void SmokeRenderer::beginSceneRender(Target target)
396 {
397     if (target == LIGHT_BUFFER)
398     {
399         m_lightFbo->Bind();
400         glViewport(0, 0, m_lightBufferSize, m_lightBufferSize);
401
402         glMatrixMode(GL_MODELVIEW);
403         glPushMatrix();
404         glLoadMatrixf((GLfloat *) m_lightView.get_value());
405
406         glMatrixMode(GL_PROJECTION);
407         glPushMatrix();
408         glLoadMatrixf((GLfloat *) m_lightProj.get_value());
409     }
410     else
411     {
412         m_imageFbo->Bind();
413         glViewport(0, 0, m_imageW, m_imageH);
414     }
415
416     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
417     glDepthMask(GL_TRUE);
418     glClear(GL_DEPTH_BUFFER_BIT);
419 }
420
421 void SmokeRenderer::endSceneRender(Target target)
422 {
423     if (target == LIGHT_BUFFER)
424     {
425         m_lightFbo->Disable();
426         glMatrixMode(GL_PROJECTION);
427         glPopMatrix();
428         glMatrixMode(GL_MODELVIEW);
429         glPopMatrix();
430     }
431     else
432     {
433         m_imageFbo->Disable();
434     }
435
436     glViewport(0, 0, mWindowW, mWindowH);
437     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
438 }
439
440 // create an OpenGL texture
441 GLuint
442 SmokeRenderer::createTexture(GLenum target, int w, int h, GLint internalformat, GLenum format)
443 {
444     GLuint texid;
445     glGenTextures(1, &texid);
446     glBindTexture(target, texid);
447
448     glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
449     glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
450     glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
451     glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
452
453     glTexImage2D(target, 0, internalformat, w, h, 0, format, GL_FLOAT, 0);
454     return texid;
455 }
456
457 // create buffers for off-screen rendering
458 void SmokeRenderer::createBuffers(int w, int h)
459 {
460     if (m_imageFbo)
461     {
462         glDeleteTextures(1, &m_imageTex);
463         glDeleteTextures(1, &m_depthTex);
464         delete m_imageFbo;
465     }
466
467     mWindowW = w;
468     mWindowH = h;
469
470     m_imageW = w / m_downSample;
471     m_imageH = h / m_downSample;
472
473     // create fbo for image buffer
474     GLint format = GL_RGBA16F_ARB;
475     //GLint format = GL_LUMINANCE16F_ARB;
476     //GLint format = GL_RGBA8;
477     m_imageTex = createTexture(GL_TEXTURE_2D, m_imageW, m_imageH, format, GL_RGBA);
478     m_depthTex = createTexture(GL_TEXTURE_2D, m_imageW, m_imageH, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT);
479     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
480     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
481
482     m_imageFbo = new FramebufferObject();
483     m_imageFbo->AttachTexture(GL_TEXTURE_2D, m_imageTex, GL_COLOR_ATTACHMENT0_EXT);
484     m_imageFbo->AttachTexture(GL_TEXTURE_2D, m_depthTex, GL_DEPTH_ATTACHMENT_EXT);
485     m_imageFbo->IsValid();
486 }
487
488 void
489 SmokeRenderer::setLightColor(vec3f c)
490 {
491     m_lightColor = c;
492
493     // set light texture border color
494     GLfloat borderColor[4] = { 1.0f - m_lightColor[0], 1.0f - m_lightColor[1], 1.0f - m_lightColor[2], 0.0f };
495
496     glBindTexture(GL_TEXTURE_2D, m_lightTexture[0]);
497     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
498
499     glBindTexture(GL_TEXTURE_2D, m_lightTexture[1]);
500     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
501
502     glBindTexture(GL_TEXTURE_2D, 0);
503 }
504
505
506 // create FBOs for light buffer
507 void
508 SmokeRenderer::createLightBuffer()
509 {
510     GLint format = GL_RGBA16F_ARB;
511     //GLint format = GL_RGBA8;
512     //GLint format = GL_LUMINANCE16F_ARB;
513
514     m_lightTexture[0] = createTexture(GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize, format, GL_RGBA);
515     // make shadows clamp to light color at edges
516     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
517     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
518
519     m_lightTexture[1] = createTexture(GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize, format, GL_RGBA);
520     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
521     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
522
523     m_lightDepthTexture = createTexture(GL_TEXTURE_2D, m_lightBufferSize, m_lightBufferSize, GL_DEPTH_COMPONENT24_ARB, GL_DEPTH_COMPONENT);
524
525     m_lightFbo = new FramebufferObject();
526     m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightTexture[m_srcLightTexture], GL_COLOR_ATTACHMENT0_EXT);
527     m_lightFbo->AttachTexture(GL_TEXTURE_2D, m_lightDepthTexture, GL_DEPTH_ATTACHMENT_EXT);
528     m_lightFbo->IsValid();
529 }
530
531 void SmokeRenderer::setWindowSize(int w, int h)
532 {
533     mAspect = (float) mWindowW / (float) mWindowH;
534     mInvFocalLen = tan(mFov*0.5f*NV_PI/180.0f);
535
536     createBuffers(w, h);
537 }
538
539 void SmokeRenderer::drawQuad()
540 {
541     glBegin(GL_QUADS);
542     glTexCoord2f(0.0f, 0.0f);
543     glVertex2f(-1.0f, -1.0f);
544     glTexCoord2f(1.0f, 0.0f);
545     glVertex2f(1.0f, -1.0f);
546     glTexCoord2f(1.0f, 1.0f);
547     glVertex2f(1.0f,  1.0f);
548     glTexCoord2f(0.0f, 1.0f);
549     glVertex2f(-1.0f,  1.0f);
550     glEnd();
551 }
552
553 void SmokeRenderer::drawVector(vec3f v)
554 {
555     glBegin(GL_LINES);
556     glVertex3f(0.0f, 0.0f, 0.0f);
557     glVertex3fv((float *) &v[0]);
558     glEnd();
559 }
560
561 // render vectors to screen for debugging
562 void SmokeRenderer::debugVectors()
563 {
564     glColor3f(1.0f, 1.0f, 0.0f);
565     drawVector(m_lightVector);
566
567     glColor3f(0.0f, 1.0f, 0.0f);
568     drawVector(m_viewVector);
569
570     glColor3f(0.0f, 0.0f, 1.0f);
571     drawVector(-m_viewVector);
572
573     glColor3f(1.0f, 0.0f, 0.0f);
574     drawVector(m_halfVector);
575 }