source: trunk/packages/vizservers/nanovis/VelocityArrowsSlice.cpp @ 3630

Last change on this file since 3630 was 3630, checked in by ldelgass, 8 years ago

Nanovis refactoring to fix problems with scaling and multiple results.
Do rendering in world space to properly place and scale multiple data sets.
Also fix flows to reduce resets of animations. More work toward removing
Cg dependency. Fix panning to convert viewport coords to world coords.

  • Property svn:eol-style set to native
File size: 18.3 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2013  HUBzero Foundation, LLC
4 *
5 */
6#include "nvconf.h"
7
8#include <math.h>
9
10#include <GL/glew.h>
11#include <GL/gl.h>
12
13#include <vrmath/Vector3f.h>
14#include <util/FilePath.h>
15#include <Image.h>
16#include <ImageLoaderFactory.h>
17#include <ImageLoader.h>
18
19#include "nanovis.h"
20#include "VelocityArrowsSlice.h"
21#include "Volume.h"
22#include "Shader.h"
23#include "Camera.h"
24
25using namespace nv;
26using namespace nv::util;
27using namespace vrmath;
28
29static inline float deg2rad(float deg)
30{
31    return ((deg * M_PI) / 180.);
32}
33
34static inline float rad2deg(float rad)
35{
36    return ((rad * 180.) / M_PI);
37}
38
39VelocityArrowsSlice::VelocityArrowsSlice() :
40    _vectorFieldGraphicsID(0),
41    _slicePos(0.5f),
42    _axis(AXIS_Z),
43    _fbo(0),
44    _tex(0),
45    _maxPointSize(1.0f),
46    _renderTargetWidth(128),
47    _renderTargetHeight(128),
48    _velocities(NULL),
49    _projectionVector(1, 1, 0),
50    _tickCountForMinSizeAxis(10),
51    _tickCountX(0),
52    _tickCountY(0),
53    _tickCountZ(0),
54    _pointCount(0),
55    _maxVelocityScale(1, 1, 1),
56    _arrowColor(1, 1, 0),
57    _visible(false),
58    _dirty(true),
59    _vertexBufferGraphicsID(0),
60    _arrowsTex(NULL),
61    _renderMode(LINES)
62{
63    setSliceAxis(AXIS_Z);
64
65    _queryVelocityFP.loadFragmentProgram("queryvelocity.cg");
66
67    _particleShader.loadVertexProgram("velocityslicevp.cg");
68    _particleShader.loadFragmentProgram("velocityslicefp.cg");
69
70    createRenderTarget();
71
72    std::string path = FilePath::getInstance()->getPath("arrows.bmp");
73    if (!path.empty()) {
74        ImageLoader *loader = ImageLoaderFactory::getInstance()->createLoader("bmp");
75        if (loader != NULL) {
76            Image *image = loader->load(path.c_str(), Image::IMG_RGBA);
77            if (image != NULL) {
78                unsigned char *bytes = (unsigned char *)image->getImageBuffer();
79                if (bytes != NULL) {
80                    _arrowsTex = new Texture2D(image->getWidth(), image->getHeight(),
81                                               GL_UNSIGNED_BYTE, GL_LINEAR, 4, NULL);
82                    _arrowsTex->setWrapS(GL_MIRRORED_REPEAT);
83                    _arrowsTex->setWrapT(GL_MIRRORED_REPEAT);
84                    _arrowsTex->initialize(image->getImageBuffer());
85                }
86                delete image;
87            } else {
88                ERROR("Failed to load arrows image");
89            }
90            delete loader;
91        } else {
92            ERROR("Couldn't find loader for arrows image");
93        }
94    } else {
95        ERROR("Couldn't find arrows image");
96    }
97
98    GLfloat minMax[2];
99    glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, minMax);
100    TRACE("Aliased point size range: %g %g", minMax[0], minMax[1]);
101    _maxPointSize = minMax[1];
102    glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, minMax);
103    TRACE("Smooth point size range: %g %g", minMax[0], minMax[1]);
104    _maxPointSize = minMax[1] > _maxPointSize ? minMax[1] : _maxPointSize;
105    TRACE("Max point size: %g", _maxPointSize);
106
107    TRACE("Leaving VelocityArrowsSlice constructor");
108}
109
110VelocityArrowsSlice::~VelocityArrowsSlice()
111{
112    if (_tex != 0) {
113        glDeleteTextures(1, &_tex);
114    }
115    if (_fbo != 0) {
116        glDeleteFramebuffersEXT(1, &_fbo);
117    }
118    if (_arrowsTex != NULL) {
119        delete _arrowsTex;
120    }
121    if (_vertexBufferGraphicsID != 0) {
122        glDeleteBuffers(1, &_vertexBufferGraphicsID);
123    }
124    if (_velocities != NULL) {
125        delete [] _velocities;
126    }
127}
128
129void VelocityArrowsSlice::createRenderTarget()
130{
131    if (_velocities != NULL) {
132        delete [] _velocities;
133    }
134    _velocities = new Vector3f[_renderTargetWidth * _renderTargetHeight];
135
136    if (_vertexBufferGraphicsID != 0) {
137        glDeleteBuffers(1, &_vertexBufferGraphicsID);
138    }
139
140    glGenBuffers(1, &_vertexBufferGraphicsID);
141    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
142    glBufferDataARB(GL_ARRAY_BUFFER_ARB, _renderTargetWidth * _renderTargetHeight * 3 * sizeof(float),
143                    0, GL_DYNAMIC_DRAW_ARB);
144    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
145
146    if (_tex != 0) {
147        glDeleteTextures(1, &_tex);
148    }
149    if (_fbo != 0) {
150        glDeleteFramebuffersEXT(1, &_fbo);
151    }
152
153    glGenFramebuffersEXT(1, &_fbo);
154    glGenTextures(1, &_tex);
155    int fboOrig;
156    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
157    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
158
159    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _tex);
160    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
161    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
162    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
163    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
164
165    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB,
166                 _renderTargetWidth, _renderTargetHeight, 0,
167                 GL_RGBA, GL_FLOAT, NULL);
168
169    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
170                              GL_TEXTURE_RECTANGLE_ARB, _tex, 0);
171
172    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
173}
174
175void VelocityArrowsSlice::setSliceAxis(FlowSliceAxis axis)
176{
177    _axis = axis;
178    switch (_axis) {
179    case AXIS_X:
180        _projectionVector.x = 0;
181        _projectionVector.y = 1;
182        _projectionVector.z = 1;
183        break;
184    case AXIS_Y:
185        _projectionVector.x = 1;
186        _projectionVector.y = 0;
187        _projectionVector.z = 1;
188        break;
189    case AXIS_Z:
190        _projectionVector.x = 1;
191        _projectionVector.y = 1;
192        _projectionVector.z = 0;
193        break;
194    }
195    _dirty = true;
196}
197
198void VelocityArrowsSlice::queryVelocity()
199{
200    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
201    int fboOrig;
202    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
203
204    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
205
206    _queryVelocityFP.bind();
207    _queryVelocityFP.setFPTextureParameter("vfield", _vectorFieldGraphicsID);
208
209    glDisable(GL_DEPTH_TEST);
210    glViewport(0, 0, _renderTargetWidth, _renderTargetHeight);
211    glMatrixMode(GL_PROJECTION);
212    glPushMatrix();
213    glLoadIdentity();
214    glOrtho(0, _renderTargetWidth, 0, _renderTargetHeight, -10.0f, 10.0f);
215    glMatrixMode(GL_MODELVIEW);
216    glPushMatrix();
217    glLoadIdentity();
218
219    glBegin(GL_QUADS);
220    switch (_axis) {
221    case 0:
222        glTexCoord3f(_slicePos, 0, 0); glVertex2i(0,                  0);
223        glTexCoord3f(_slicePos, 1, 0); glVertex2i(_renderTargetWidth, 0);
224        glTexCoord3f(_slicePos, 1, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
225        glTexCoord3f(_slicePos, 0, 1); glVertex2i(0,                  _renderTargetHeight);
226        break;
227    case 1:
228        glTexCoord3f(0, _slicePos, 0); glVertex2i(0,                  0);
229        glTexCoord3f(1, _slicePos, 0); glVertex2i(_renderTargetWidth, 0);
230        glTexCoord3f(1, _slicePos, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
231        glTexCoord3f(0, _slicePos, 1); glVertex2i(0,                  _renderTargetHeight);
232        break;
233    case 2:
234    default:
235        glTexCoord3f(0, 0, _slicePos); glVertex2i(0,                  0);
236        glTexCoord3f(1, 0, _slicePos); glVertex2i(_renderTargetWidth, 0);
237        glTexCoord3f(1, 1, _slicePos); glVertex2i(_renderTargetWidth, _renderTargetHeight);
238        glTexCoord3f(0, 1, _slicePos); glVertex2i(0,                  _renderTargetHeight);
239        break;
240    }
241    glEnd();
242
243    _queryVelocityFP.disableFPTextureParameter("vfield");
244    _queryVelocityFP.unbind();
245
246    glReadPixels(0, 0, _renderTargetWidth, _renderTargetHeight, GL_RGB, GL_FLOAT, _velocities);
247
248    glMatrixMode(GL_PROJECTION);
249    glPopMatrix();
250    glMatrixMode(GL_MODELVIEW);
251    glPopMatrix();
252
253    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
254
255    glPopAttrib();
256}
257
258static void drawLineArrow(int axis)
259{
260    glBegin(GL_LINES);
261    switch (axis) {
262    case 0: // ZY plane
263        glVertex3f(0.0, 0.0, 0.0);
264        glVertex3f(0.0, 0.0, 1.0);
265
266        glVertex3f(0.0, 0.0, 1.0);
267        glVertex3f(0.0, 0.25, 0.75);
268
269        glVertex3f(0.0, 0.0, 1.0);
270        glVertex3f(0.0, -0.25, 0.75);
271        break;
272    case 1: // XZ plane
273        glVertex3f(0.0, 0.0, 0.0);
274        glVertex3f(1.0, 0.0, 0.0);
275
276        glVertex3f(1.0, 0.0, 0.0);
277        glVertex3f(0.75, 0.0, 0.25);
278
279        glVertex3f(1.0, 0.0, 0.0);
280        glVertex3f(0.75, 0.0, -0.25);
281        break;
282    case 2: // XY plane
283    default:
284        glVertex3f(0.0, 0.0, 0.0);
285        glVertex3f(1.0, 0.0, 0.0);
286
287        glVertex3f(1.0, 0.0, 0.0);
288        glVertex3f(0.75, 0.25, 0.0);
289
290        glVertex3f(1.0, 0.0, 0.0);
291        glVertex3f(0.75, -0.25, 0.0);
292        break;
293    }
294    glEnd();
295}
296
297void VelocityArrowsSlice::render()
298{
299    if (!_visible)
300        return;
301
302    if (_dirty) {
303        computeSamplingTicks();
304        queryVelocity();
305        _dirty = false;
306    }
307
308    TRACE("_scale: %g %g %g", _scale.x, _scale.y, _scale.z);
309    TRACE("_maxVelocityScale: %g %g %g",
310          _maxVelocityScale.x, _maxVelocityScale.y, _maxVelocityScale.z);
311
312    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
313
314    glMatrixMode(GL_MODELVIEW);
315    glPushMatrix();
316
317    glTranslatef(_origin.x, _origin.y, _origin.z);
318    glScalef(_scale.x, _scale.y, _scale.z);
319
320    if (_renderMode == LINES) {
321        glDisable(GL_TEXTURE_2D);
322        glDisable(GL_LIGHTING);
323        glLineWidth(2.0);
324        glColor3f(_arrowColor.x, _arrowColor.y, _arrowColor.z);
325 
326        Vector3f pos;
327        Vector3f vel;
328        Vector3f refVec;
329        Vector3f blue(0, 0, 1);
330        Vector3f red(1, 0, 0);
331
332        int index = 0, icount, jcount;
333        switch (_axis) {
334        case 0:
335            icount = _tickCountZ;
336            jcount = _tickCountY;
337            refVec.set(0, 0, 1);
338            break;
339        case 1:
340            icount = _tickCountZ;
341            jcount = _tickCountX;
342            refVec.set(1, 0, 0);
343            break;
344        case 2:
345        default:
346            icount = _tickCountY;
347            jcount = _tickCountX;
348            refVec.set(1, 0, 0);
349            break;
350        }
351
352        for (int i = 0; i < icount; ++i) {
353            for (int j = 0; j < jcount; ++j, ++index) {
354                pos = _samplingPositions[index];
355                // Normalized velocity: [-1,1] components
356                // Project 3D vector onto sample plane
357                vel = _velocities[index].scale(_projectionVector);
358                // Length: [0,1]
359                double length = vel.length();
360                if (length < 0.0 || length > 1.0) {
361                    TRACE("***vec: (%g, %g, %g) length: %g***", vel.x, vel.y, vel.z, length);
362                    continue;
363                }
364                if (length > 1.0e-6) {
365                    Vector3f vnorm = vel.normalize();
366                    Vector3f rotationAxis = refVec.cross(vnorm);
367                    double angle = rad2deg(acos(refVec.dot(vnorm)));
368                    Vector3f color = blue * (1.0 - length) + red * length;
369                    float scale = length;
370                    if (scale < 0.10) scale = 0.10;
371                    glMatrixMode(GL_MODELVIEW);
372                    glPushMatrix();
373                    glColor3f(color.x, color.y, color.z);
374                    glTranslatef(pos.x, pos.y, pos.z);
375                    glScalef(2.0 * _maxVelocityScale.x,
376                             2.0 * _maxVelocityScale.y,
377                             2.0 * _maxVelocityScale.z);
378                    glScalef(scale, scale, scale);
379                    if (angle > 1.0e-6 || angle < -1.0e-6)
380                        glRotated(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
381                    drawLineArrow(_axis);
382                    glPopMatrix();
383                }
384            }
385        }
386
387        glLineWidth(1.0);
388    } else {
389        glColor4f(_arrowColor.x, _arrowColor.y, _arrowColor.z, 1.0f);
390        glEnable(GL_DEPTH_TEST);
391        glDisable(GL_LIGHTING);
392#if 0
393        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
394        glEnable(GL_BLEND);
395        glDepthMask(GL_FALSE);
396#else
397        glDisable(GL_BLEND);
398#endif
399        glAlphaFunc(GL_GREATER, 0.6);
400        glEnable(GL_ALPHA_TEST);
401        glEnable(GL_POINT_SPRITE_ARB);
402        glPointSize(20);
403        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
404
405        _arrowsTex->activate();
406        glEnable(GL_TEXTURE_2D);
407        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
408
409        GLfloat atten[] = {1, 0, 0};
410        glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, atten);
411        glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.0f);
412        glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
413        glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, _maxPointSize);
414        glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
415
416        _particleShader.bind();
417        _particleShader.setVPTextureParameter("vfield", _vectorFieldGraphicsID);
418        _particleShader.setFPTextureParameter("arrows", _arrowsTex->id());
419        _particleShader.setVPParameter1f("tanHalfFOV",
420                                         tan(NanoVis::getCamera()->getFov() * 0.5) * NanoVis::winHeight * 0.5);
421        _particleShader.setGLStateMatrixVPParameter("modelview",
422                                                    Shader::MODELVIEW_MATRIX,
423                                                    Shader::MATRIX_IDENTITY);
424        _particleShader.setGLStateMatrixVPParameter("mvp",
425                                                    Shader::MODELVIEW_PROJECTION_MATRIX,
426                                                    Shader::MATRIX_IDENTITY);
427
428        glEnableClientState(GL_VERTEX_ARRAY);
429        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
430        glVertexPointer(3, GL_FLOAT, 0, 0);
431        //glEnableClientState(GL_COLOR_ARRAY);
432
433        // TBD..
434        glDrawArrays(GL_POINTS, 0, _pointCount);
435        glPointSize(1);
436
437        glDisableClientState(GL_VERTEX_ARRAY);
438        glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
439        glDisable(GL_POINT_SPRITE_ARB);
440
441        _particleShader.disableVPTextureParameter("vfield");
442        _particleShader.disableFPTextureParameter("arrows");
443        _particleShader.unbind();
444
445        glActiveTexture(GL_TEXTURE0);
446        glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
447        _arrowsTex->deactivate();
448    }
449
450    glPopMatrix();
451    glPopAttrib();
452}
453
454void
455VelocityArrowsSlice::setVectorField(Volume *volume)
456{
457    _vectorFieldGraphicsID = volume->textureID();
458    Vector3f bmin, bmax;
459    volume->getBounds(bmin, bmax);
460    _origin = bmin;
461    _scale.set(bmax.x-bmin.x, bmax.y-bmin.y, bmax.z-bmin.z);
462
463    _dirty = true;
464}
465
466void VelocityArrowsSlice::computeSamplingTicks()
467{
468    if (_scale.x < _scale.y) {
469        if (_scale.x < _scale.z || _scale.z == 0.0) {
470            // _scale.x
471            _tickCountX = _tickCountForMinSizeAxis;
472
473            float step = _scale.x / (_tickCountX + 1);
474            _tickCountY = (int)(_scale.y/step);
475            _tickCountZ = (int)(_scale.z/step);
476        } else {
477            // _scale.z
478            _tickCountZ = _tickCountForMinSizeAxis;
479
480            float step = _scale.z / (_tickCountZ + 1);
481            _tickCountX = (int)(_scale.x/step);
482            _tickCountY = (int)(_scale.y/step);
483        }
484    } else {
485        if (_scale.y < _scale.z || _scale.z == 0.0) {
486            // _scale.y
487            _tickCountY = _tickCountForMinSizeAxis;
488
489            float step = _scale.y / (_tickCountY + 1);
490            _tickCountX = (int)(_scale.x/step);
491            _tickCountZ = (int)(_scale.z/step);
492        } else {
493            // _scale.z
494            _tickCountZ = _tickCountForMinSizeAxis;
495
496            float step = _scale.z / (_tickCountZ + 1);
497            _tickCountX = (int)(_scale.x/step);
498            _tickCountY = (int)(_scale.y/step);
499        }
500    }
501
502    switch (_axis) {
503    case 0:
504        _tickCountX = 1;
505        _renderTargetWidth = _tickCountY;
506        _renderTargetHeight = _tickCountZ;
507        break;
508    case 1:
509        _tickCountY = 1;
510        _renderTargetWidth = _tickCountX;
511        _renderTargetHeight = _tickCountZ;
512        break;
513    default:
514    case 2:
515        _tickCountZ = 1;
516        _renderTargetWidth = _tickCountX;
517        _renderTargetHeight = _tickCountY;
518        break;
519    }
520
521    _maxVelocityScale.x = (1.0f / _tickCountX) * 0.8f;
522    _maxVelocityScale.y = (1.0f / _tickCountY) * 0.8f;
523    _maxVelocityScale.z = (1.0f / _tickCountZ) * 0.8f;
524
525    TRACE("Tick counts: %d %d %d", _tickCountX, _tickCountY, _tickCountZ);
526
527    int pointCount = _tickCountX * _tickCountY * _tickCountZ;
528    if (_pointCount != pointCount) {
529        _samplingPositions.clear();
530        _samplingPositions.reserve(pointCount);
531        _pointCount = pointCount;
532    }
533
534    createRenderTarget();
535
536    Vector3f pos;
537    Vector3f *pinfo = NULL;
538    if (_renderMode == GLYPHS) {
539        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
540        pinfo = (Vector3f *)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
541    }
542
543    if (_axis == 2) {
544        for (int y = 1; y <= _tickCountY; ++y) {
545            for (int x = 1; x <= _tickCountX; ++x) {
546                pos.x = (1.0f / (_tickCountX + 1)) * x;
547                pos.y = (1.0f / (_tickCountY + 1)) * y;
548                pos.z = _slicePos;
549                if (_renderMode == LINES) {
550                    _samplingPositions.push_back(pos);
551                } else {
552                    *pinfo = pos;
553                    ++pinfo;
554                }
555            }
556        }
557    } else if (_axis == 1) {
558        for (int z = 1; z <= _tickCountZ; ++z) {
559            for (int x = 1; x <= _tickCountX; ++x) {
560                pos.x = (1.0f / (_tickCountX + 1)) * x;
561                pos.y = _slicePos;
562                pos.z = (1.0f / (_tickCountZ + 1)) * z;
563                if (_renderMode == LINES) {
564                    _samplingPositions.push_back(pos);
565                } else {
566                    *pinfo = pos;
567                    ++pinfo;
568                }
569            }
570        }
571    } else if (_axis == 0) {
572        for (int z = 1; z <= _tickCountZ; ++z) {
573            for (int y = 1; y <= _tickCountY; ++y) {
574                pos.x = _slicePos;
575                pos.y = (1.0f / (_tickCountY + 1)) * y;
576                pos.z = (1.0f / (_tickCountZ + 1)) * z;
577                if (_renderMode == LINES) {
578                    _samplingPositions.push_back(pos);
579                } else {
580                    *pinfo = pos;
581                    ++pinfo;
582                }
583            }
584        }
585    }
586
587    if (_renderMode == GLYPHS) {
588        glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
589    }
590}
Note: See TracBrowser for help on using the repository browser.