source: nanovis/branches/1.1/VolumeRenderer.cpp @ 6632

Last change on this file since 6632 was 4904, checked in by ldelgass, 9 years ago

Merge serveral changes from trunk. Does not include threading, world space
changes, etc.

  • Property svn:eol-style set to native
File size: 18.8 KB
RevLine 
[2798]1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
[406]2/*
3 * ----------------------------------------------------------------------
4 * VolumeRenderer.cpp : VolumeRenderer class for volume visualization
5 *
6 * ======================================================================
7 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
8 *           Purdue Rendering and Perceptualization Lab (PURPL)
9 *
[3502]10 *  Copyright (c) 2004-2013  HUBzero Foundation, LLC
[406]11 *
12 *  See the file "license.terms" for information on usage and
13 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * ======================================================================
15 */
[2822]16#include <stdlib.h>
[2973]17#include <float.h>
[2804]18
[2972]19#include <vector>
20
[2822]21#include <GL/glew.h>
22
[3492]23#include <vrmath/Vector3f.h>
24#include <vrmath/Matrix4x4d.h>
25
[2804]26#include "nanovis.h"
[2822]27#include "VolumeRenderer.h"
[3492]28#include "Plane.h"
[2822]29#include "ConvexPolygon.h"
[4889]30#include "StdVertexShader.h"
[884]31#include "Trace.h"
[406]32
[4889]33using namespace nv;
[3492]34using namespace vrmath;
35
[2974]36VolumeRenderer::VolumeRenderer()
[406]37{
[2877]38    initShaders();
[617]39
[884]40    _volumeInterpolator = new VolumeInterpolator();
[418]41}
42
[580]43VolumeRenderer::~VolumeRenderer()
44{
[3362]45    delete _cutplaneShader;
[617]46    delete _zincBlendeShader;
47    delete _regularVolumeShader;
48    delete _stdVertexShader;
[884]49    delete _volumeInterpolator;
[580]50}
[418]51
52//initialize the volume shaders
[2877]53void VolumeRenderer::initShaders()
[2822]54{
[4889]55    _cutplaneShader = new Shader();
[4904]56    _cutplaneShader->loadVertexProgram("cutplane_vp.cg");
57    _cutplaneShader->loadFragmentProgram("cutplane_fp.cg");
[3362]58
[2822]59    //standard vertex program
[4889]60    _stdVertexShader = new StdVertexShader();
[406]61
[2822]62    //volume rendering shader: one cubic volume
[4889]63    _regularVolumeShader = new RegularVolumeShader();
[524]64
[2822]65    //volume rendering shader: one zincblende orbital volume.
66    //This shader renders one orbital of the simulation.
67    //A sim has S, P, D, SS orbitals. thus a full rendering requires 4 zincblende orbital volumes.
68    //A zincblende orbital volume is decomposed into 2 "interlocking" cubic 4-component volumes and passed to the shader.
[4904]69    //We render each orbital with independent transfer functions then blend the result.
[2822]70    //
71    //The engine is already capable of rendering multiple volumes and combine them. Thus, we just invoke this shader on
72    //S, P, D and SS orbitals with different transfor functions. The result is a multi-orbital rendering.
[4889]73    _zincBlendeShader = new ZincBlendeVolumeShader();
[406]74}
75
[1258]76struct SortElement {
77    float z;
[2877]78    int volumeId;
79    int sliceId;
[2822]80
[2804]81    SortElement(float _z, int _v, int _s) :
[2877]82        z(_z),
83        volumeId(_v),
84        sliceId(_s)
[2804]85    {}
[415]86};
87
[2877]88static int sliceSort(const void *a, const void *b)
[2822]89{
90    if ((*((SortElement*)a)).z > (*((SortElement*)b)).z)
[2804]91        return 1;
92    else
93        return -1;
[415]94}
95
[1258]96void
[2877]97VolumeRenderer::renderAll()
[580]98{
[1478]99    size_t total_rendered_slices = 0;
[900]100
[2877]101    if (_volumeInterpolator->isStarted()) {
[1478]102#ifdef notdef
[884]103        ani_vol = _volumeInterpolator->getVolume();
[1478]104        ani_tf = ani_vol->transferFunction();
105#endif
[2853]106        TRACE("VOLUME INTERPOLATOR IS STARTED ----------------------------");
[884]107    }
[1478]108    // Determine the volumes that are to be rendered.
[2804]109    std::vector<Volume *> volumes;
[3567]110    for (NanoVis::VolumeHashmap::iterator itr = NanoVis::volumeTable.begin();
111         itr != NanoVis::volumeTable.end(); ++itr) {
112        Volume *volume = itr->second;
113        if (!volume->visible()) {
[2853]114            continue; // Skip this volume
115        }
116        // BE CAREFUL: Set the number of slices to something slightly
117        // different for each volume.  If we have identical volumes at exactly
118        // the same position with exactly the same number of slices, the
119        // second volume will overwrite the first, so the first won't appear
120        // at all.
[3567]121        volumes.push_back(volume);
122        volume->numSlices(256 - volumes.size());
[1478]123    }
[884]124
[2932]125    glPushAttrib(GL_ENABLE_BIT);
126
[1258]127    //two dimension pointer array
[2853]128    ConvexPolygon ***polys = new ConvexPolygon**[volumes.size()];
[1258]129    //number of actual slices for each volume
[2932]130    size_t *actual_slices = new size_t[volumes.size()];
[3362]131    float *z_steps = new float[volumes.size()];
[884]132
[3452]133    TRACE("start loop %d", volumes.size());
[1478]134    for (size_t i = 0; i < volumes.size(); i++) {
[4612]135        Volume *volume = volumes[i];
[1478]136        polys[i] = NULL;
137        actual_slices[i] = 0;
[1429]138
[4612]139        int n_slices = volume->numSlices();
140        if (volume->isosurface()) {
[2853]141            // double the number of slices
142            n_slices <<= 1;
143        }
[2804]144
[4904]145        // Get any additional transforms on Volume
146        Vector3f volPos = volume->getPosition();
147        Vector3f volScale = volume->getPhysicalScaling();
148        // Get world coords of volume bbox
[900]149        double x0 = 0;
150        double y0 = 0;
151        double z0 = 0;
[4904]152        double x1 = x0 + 1;
153        double y1 = y0 + 1;
154        double z1 = z0 + 1;
[2804]155
[3492]156        Matrix4x4d model_view_no_trans, model_view_trans;
157        Matrix4x4d model_view_no_trans_inverse, model_view_trans_inverse;
[2804]158
[2853]159        //initialize volume plane with world coordinates
[3492]160        nv::Plane volume_planes[6];
[2906]161        volume_planes[0].setCoeffs( 1,  0,  0, -x0);
[4904]162        volume_planes[1].setCoeffs(-1,  0,  0,  x1);
[2906]163        volume_planes[2].setCoeffs( 0,  1,  0, -y0);
[4904]164        volume_planes[3].setCoeffs( 0, -1,  0,  y1);
[2906]165        volume_planes[4].setCoeffs( 0,  0,  1, -z0);
[4904]166        volume_planes[5].setCoeffs( 0,  0, -1,  z1);
[2804]167
[4904]168        TRACE("VOL POS: %g %g %g",
169              volPos.x, volPos.y, volPos.z);
170        TRACE("VOL SCALE: %g %g %g",
171              volScale.x, volScale.y, volScale.z);
172
[2853]173        //get modelview matrix with no translation
[900]174        glPushMatrix();
[4904]175        glScalef(volScale.x, volScale.y, volScale.z);
[2804]176
[900]177        glEnable(GL_DEPTH_TEST);
[2804]178
[3492]179        GLdouble mv_no_trans[16];
180        glGetDoublev(GL_MODELVIEW_MATRIX, mv_no_trans);
[2804]181
[3492]182        model_view_no_trans = Matrix4x4d(mv_no_trans);
[900]183        model_view_no_trans_inverse = model_view_no_trans.inverse();
[2804]184
[900]185        glPopMatrix();
[2804]186
[2853]187        //get modelview matrix with translation
[900]188        glPushMatrix();
[3362]189        glTranslatef(volPos.x, volPos.y, volPos.z);
[4904]190        glScalef(volScale.x, volScale.y, volScale.z);
[3362]191
[3492]192        GLdouble mv_trans[16];
193        glGetDoublev(GL_MODELVIEW_MATRIX, mv_trans);
[2804]194
[3492]195        model_view_trans = Matrix4x4d(mv_trans);
[900]196        model_view_trans_inverse = model_view_trans.inverse();
[2804]197
[3492]198        model_view_trans.print();
199
[2853]200        //draw volume bounding box with translation (the correct location in
201        //space)
[4612]202        if (volume->outline()) {
[900]203            float olcolor[3];
[4612]204            volume->getOutlineColor(olcolor);
[4904]205            drawBoundingBox(x0, y0, z0, x1, y1, z1,
206                            olcolor[0], olcolor[1], olcolor[2],
207                            1.5);
[900]208        }
209        glPopMatrix();
[2804]210
[3362]211        // transform volume_planes to eye coordinates.
212        // Need to transform without translation since we don't want
213        // to translate plane normals, just rotate them
[2804]214        for (size_t j = 0; j < 6; j++) {
[1478]215            volume_planes[j].transform(model_view_no_trans);
[2853]216        }
[4904]217        double eyeMinX, eyeMaxX, eyeMinY, eyeMaxY;
218        double zNear, zFar;
[2973]219        getEyeSpaceBounds(model_view_no_trans,
220                          eyeMinX, eyeMaxX,
221                          eyeMinY, eyeMaxY,
222                          zNear, zFar);
[2804]223
[2853]224        //compute actual rendering slices
225        float z_step = fabs(zNear-zFar)/n_slices;
[3362]226        z_steps[i] = z_step;
[1478]227        size_t n_actual_slices;
[2804]228
[4612]229        if (volume->dataEnabled()) {
[3362]230            if (z_step == 0.0f)
231                n_actual_slices = 1;
232            else
233                n_actual_slices = (int)(fabs(zNear-zFar)/z_step + 1);
[1478]234            polys[i] = new ConvexPolygon*[n_actual_slices];
[900]235        } else {
236            n_actual_slices = 0;
[1478]237            polys[i] = NULL;
[900]238        }
[1478]239        actual_slices[i] = n_actual_slices;
[2804]240
[3362]241        TRACE("near: %g far: %g eye space bounds: (%g,%g)-(%g,%g) z_step: %g slices: %d",
242              zNear, zFar, eyeMinX, eyeMaxX, eyeMinY, eyeMaxY, z_step, n_actual_slices);
[2804]243
[3492]244        Vector4f vert1, vert2, vert3, vert4;
[3362]245
[2853]246        // Render cutplanes first with depth test enabled.  They will mark the
247        // image with their depth values.  Then we render other volume slices.
248        // These volume slices will be occluded correctly by the cutplanes and
249        // vice versa.
[1825]250
[4612]251        for (int j = 0; j < volume->getCutplaneCount(); j++) {
[4818]252            if (!volume->cutplanesVisible() || !volume->isCutplaneEnabled(j)) {
[2853]253                continue;
254            }
[4904]255            Vector4f texcoord1, texcoord2, texcoord3, texcoord4;
[4612]256            float offset = volume->getCutplane(j)->offset;
257            int axis = volume->getCutplane(j)->orient;
[3362]258
259            switch (axis) {
[4904]260            case CutPlane::X_AXIS: // YZ plane
[3492]261                vert1 = Vector4f(offset, 0, 0, 1);
262                vert2 = Vector4f(offset, 1, 0, 1);
263                vert3 = Vector4f(offset, 1, 1, 1);
264                vert4 = Vector4f(offset, 0, 1, 1);
[4904]265                texcoord1 = Vector4f(offset, 0, 0, 1);
266                texcoord2 = Vector4f(offset, 1, 0, 1);
267                texcoord3 = Vector4f(offset, 1, 1, 1);
268                texcoord4 = Vector4f(offset, 0, 1, 1);
[3362]269                break;
[4904]270            case CutPlane::Y_AXIS: // XZ plane
[3492]271                vert1 = Vector4f(0, offset, 0, 1);
272                vert2 = Vector4f(1, offset, 0, 1);
273                vert3 = Vector4f(1, offset, 1, 1);
274                vert4 = Vector4f(0, offset, 1, 1);
[4904]275                texcoord1 = Vector4f(0, offset, 0, 1);
276                texcoord2 = Vector4f(1, offset, 0, 1);
277                texcoord3 = Vector4f(1, offset, 1, 1);
278                texcoord4 = Vector4f(0, offset, 1, 1);
[3362]279                break;
[4904]280            case CutPlane::Z_AXIS: // XY plane
[3362]281            default:
[3492]282                vert1 = Vector4f(0, 0, offset, 1);
283                vert2 = Vector4f(1, 0, offset, 1);
284                vert3 = Vector4f(1, 1, offset, 1);
285                vert4 = Vector4f(0, 1, offset, 1);
[4904]286                texcoord1 = Vector4f(0, 0, offset, 1);
287                texcoord2 = Vector4f(1, 0, offset, 1);
288                texcoord3 = Vector4f(1, 1, offset, 1);
289                texcoord4 = Vector4f(0, 1, offset, 1);
[3362]290                break;
[2853]291            }
[2804]292
[3362]293            _cutplaneShader->bind();
[4612]294            _cutplaneShader->setFPTextureParameter("volume", volume->textureID());
295            _cutplaneShader->setFPTextureParameter("tf", volume->transferFunction()->id());
[2804]296
[2853]297            glPushMatrix();
[3362]298            glTranslatef(volPos.x, volPos.y, volPos.z);
[4904]299            glScalef(volScale.x, volScale.y, volScale.z);
[3362]300            _cutplaneShader->setGLStateMatrixVPParameter("modelViewProjMatrix",
[4889]301                                                         Shader::MODELVIEW_PROJECTION_MATRIX);
[2853]302            glPopMatrix();
[2804]303
[2853]304            glEnable(GL_DEPTH_TEST);
305            glDisable(GL_BLEND);
[2804]306
[3362]307            glBegin(GL_QUADS);
308            glTexCoord3f(texcoord1.x, texcoord1.y, texcoord1.z);
309            glVertex3f(vert1.x, vert1.y, vert1.z);
310            glTexCoord3f(texcoord2.x, texcoord2.y, texcoord2.z);
311            glVertex3f(vert2.x, vert2.y, vert2.z);
312            glTexCoord3f(texcoord3.x, texcoord3.y, texcoord3.z);
313            glVertex3f(vert3.x, vert3.y, vert3.z);
314            glTexCoord3f(texcoord4.x, texcoord4.y, texcoord4.z);
315            glVertex3f(vert4.x, vert4.y, vert4.z);
[2853]316            glEnd();
[3362]317
[2853]318            glDisable(GL_DEPTH_TEST);
[3362]319            _cutplaneShader->disableFPTextureParameter("tf");
320            _cutplaneShader->disableFPTextureParameter("volume");
321            _cutplaneShader->unbind();
[2853]322        } //done cutplanes
[2804]323
[3362]324        // Now prepare proxy geometry slices
[2853]325
[2973]326        // Initialize view-aligned quads with eye space bounds of
327        // volume
[3492]328        vert1 = Vector4f(eyeMinX, eyeMinY, -0.5, 1);
329        vert2 = Vector4f(eyeMaxX, eyeMinY, -0.5, 1);
330        vert3 = Vector4f(eyeMaxX, eyeMaxY, -0.5, 1);
331        vert4 = Vector4f(eyeMinX, eyeMaxY, -0.5, 1);
[2804]332
[1478]333        size_t counter = 0;
[2804]334
[3362]335        // Transform slices and store them
[900]336        float slice_z;
[1478]337        for (size_t j = 0; j < n_actual_slices; j++) {
[2853]338            slice_z = zFar + j * z_step; //back to front
[2804]339
[900]340            ConvexPolygon *poly = new ConvexPolygon();
[1478]341            polys[i][counter] = poly;
[900]342            counter++;
[2804]343
[900]344            poly->vertices.clear();
[2877]345            poly->setId(i);
[2804]346
[2973]347            // Set eye space Z-coordinate of slice
[900]348            vert1.z = slice_z;
349            vert2.z = slice_z;
350            vert3.z = slice_z;
351            vert4.z = slice_z;
[2804]352
[2877]353            poly->appendVertex(vert1);
354            poly->appendVertex(vert2);
355            poly->appendVertex(vert3);
356            poly->appendVertex(vert4);
[2804]357
358            for (size_t k = 0; k < 6; k++) {
[3362]359                if (!poly->clip(volume_planes[k], true))
360                    break;
[2853]361            }
[2804]362
[3362]363            if (poly->vertices.size() >= 3) {
364                poly->transform(model_view_no_trans_inverse);
365                poly->transform(model_view_trans);
[2853]366                total_rendered_slices++;
[3362]367            }
[900]368        }
[1258]369    } //iterate all volumes
[3452]370    TRACE("end loop");
[2804]371
[1493]372    // We sort all the polygons according to their eye-space depth, from
373    // farthest to the closest.  This step is critical for correct blending
[2804]374
[2853]375    SortElement *slices = (SortElement *)
376        malloc(sizeof(SortElement) * total_rendered_slices);
[2804]377
[1478]378    size_t counter = 0;
[2804]379    for (size_t i = 0; i < volumes.size(); i++) {
380        for (size_t j = 0; j < actual_slices[i]; j++) {
381            if (polys[i][j]->vertices.size() >= 3) {
[900]382                slices[counter] = SortElement(polys[i][j]->vertices[0].z, i, j);
383                counter++;
384            }
385        }
[884]386    }
[2804]387
[1258]388    //sort them
[2877]389    qsort(slices, total_rendered_slices, sizeof(SortElement), sliceSort);
[2804]390
[1258]391    //Now we are ready to render all the slices from back to front
[900]392    glEnable(GL_DEPTH_TEST);
[2932]393    // Non pre-multiplied alpha
394    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
[900]395    glEnable(GL_BLEND);
[2804]396
397    for (size_t i = 0; i < total_rendered_slices; i++) {
[4904]398        int volIdx = slices[i].volumeId;
399        int sliceIdx = slices[i].sliceId;
400        ConvexPolygon *currentSlice = polys[volIdx][sliceIdx];
[1478]401
[4904]402        Volume *volume = volumes[volIdx];
403        Vector3f volScale = volume->getPhysicalScaling();
[2804]404
[900]405        glPushMatrix();
[4904]406        glScalef(volScale.x, volScale.y, volScale.z);
[2804]407
[4904]408        float z_step = z_steps[volIdx];
[3362]409        // FIXME: compute view-dependent volume sample distance
[4904]410        double avgSampleDistance = 1.0 / pow(volume->width() * volScale.x *
411                                             volume->height() * volScale.y *
412                                             volume->depth() * volScale.z, 1.0/3.0);
[3362]413        float sampleRatio = z_step / avgSampleDistance;
414
[1493]415#ifdef notdef
[3452]416        TRACE("shading slice: volume %s addr=%x slice=%d, volume=%d z_step=%g avgSD=%g",
[4904]417              volume->name(), volume, sliceIdx, volIdx, z_step, avgSampleDistance);
[1493]418#endif
[4612]419        activateVolumeShader(volume, false, sampleRatio);
[900]420        glPopMatrix();
[2804]421
[900]422        glBegin(GL_POLYGON);
[3362]423        currentSlice->emit(true);
[900]424        glEnd();
[884]425
[2877]426        deactivateVolumeShader();
[884]427    }
[2804]428
[2932]429    glPopAttrib();
[2804]430
[900]431    //Deallocate all the memory used
[2804]432    for (size_t i = 0; i < volumes.size(); i++) {
433        for (size_t j = 0; j <actual_slices[i]; j++) {
[900]434            delete polys[i][j];
435        }
[1258]436        if (polys[i]) {
[900]437            delete[] polys[i];
438        }
[452]439    }
[900]440    delete[] polys;
441    delete[] actual_slices;
[3362]442    delete[] z_steps;
[900]443    free(slices);
[415]444}
445
[1478]446void
[2877]447VolumeRenderer::drawBoundingBox(float x0, float y0, float z0,
448                                float x1, float y1, float z1,
449                                float r, float g, float b,
[4904]450                                float lineWidth)
[406]451{
[2932]452    glPushAttrib(GL_ENABLE_BIT);
453
[1028]454    glEnable(GL_DEPTH_TEST);
455    glDisable(GL_TEXTURE_2D);
456    glEnable(GL_BLEND);
[406]457
[2932]458    glMatrixMode(GL_MODELVIEW);
459    glPushMatrix();
460
[1028]461    glColor4d(r, g, b, 1.0);
[4904]462    glLineWidth(lineWidth);
[2804]463
[1028]464    glBegin(GL_LINE_LOOP);
465    {
[2853]466        glVertex3d(x0, y0, z0);
467        glVertex3d(x1, y0, z0);
468        glVertex3d(x1, y1, z0);
469        glVertex3d(x0, y1, z0);
[1028]470    }
471    glEnd();
[2804]472
[1028]473    glBegin(GL_LINE_LOOP);
474    {
[2853]475        glVertex3d(x0, y0, z1);
476        glVertex3d(x1, y0, z1);
477        glVertex3d(x1, y1, z1);
478        glVertex3d(x0, y1, z1);
[1028]479    }
480    glEnd();
[2853]481
[1028]482    glBegin(GL_LINE_LOOP);
483    {
[2853]484        glVertex3d(x0, y0, z0);
485        glVertex3d(x0, y0, z1);
486        glVertex3d(x0, y1, z1);
487        glVertex3d(x0, y1, z0);
[1028]488    }
489    glEnd();
[2804]490
[1028]491    glBegin(GL_LINE_LOOP);
492    {
[2853]493        glVertex3d(x1, y0, z0);
494        glVertex3d(x1, y0, z1);
495        glVertex3d(x1, y1, z1);
496        glVertex3d(x1, y1, z0);
[1028]497    }
498    glEnd();
[406]499
[1028]500    glPopMatrix();
[2932]501    glPopAttrib();
[406]502}
503
[1478]504void
[4904]505VolumeRenderer::activateVolumeShader(Volume *volume,
506                                     bool sliceMode,
[3362]507                                     float sampleRatio)
[617]508{
[1478]509    //vertex shader
510    _stdVertexShader->bind();
[4612]511    TransferFunction *transferFunc  = volume->transferFunction();
512    if (volume->volumeType() == Volume::CUBIC) {
513        _regularVolumeShader->bind(transferFunc->id(), volume, sliceMode, sampleRatio);
514    } else if (volume->volumeType() == Volume::ZINCBLENDE) {
515        _zincBlendeShader->bind(transferFunc->id(), volume, sliceMode, sampleRatio);
[1478]516    }
[406]517}
[2877]518
519void VolumeRenderer::deactivateVolumeShader()
[580]520{
[617]521    _stdVertexShader->unbind();
522    _regularVolumeShader->unbind();
523    _zincBlendeShader->unbind();
[406]524}
525
[3492]526void VolumeRenderer::getEyeSpaceBounds(const Matrix4x4d& mv,
[2973]527                                       double& xMin, double& xMax,
528                                       double& yMin, double& yMax,
529                                       double& zNear, double& zFar)
[406]530{
[2822]531    double x0 = 0;
532    double y0 = 0;
533    double z0 = 0;
534    double x1 = 1;
535    double y1 = 1;
536    double z1 = 1;
[406]537
[2822]538    double zMin, zMax;
[2973]539    xMin = DBL_MAX;
540    xMax = -DBL_MAX;
541    yMin = DBL_MAX;
542    yMax = -DBL_MAX;
543    zMin = DBL_MAX;
544    zMax = -DBL_MAX;
[406]545
[2822]546    double vertex[8][4];
[406]547
[2822]548    vertex[0][0]=x0; vertex[0][1]=y0; vertex[0][2]=z0; vertex[0][3]=1.0;
549    vertex[1][0]=x1; vertex[1][1]=y0; vertex[1][2]=z0; vertex[1][3]=1.0;
550    vertex[2][0]=x0; vertex[2][1]=y1; vertex[2][2]=z0; vertex[2][3]=1.0;
551    vertex[3][0]=x0; vertex[3][1]=y0; vertex[3][2]=z1; vertex[3][3]=1.0;
552    vertex[4][0]=x1; vertex[4][1]=y1; vertex[4][2]=z0; vertex[4][3]=1.0;
553    vertex[5][0]=x1; vertex[5][1]=y0; vertex[5][2]=z1; vertex[5][3]=1.0;
554    vertex[6][0]=x0; vertex[6][1]=y1; vertex[6][2]=z1; vertex[6][3]=1.0;
555    vertex[7][0]=x1; vertex[7][1]=y1; vertex[7][2]=z1; vertex[7][3]=1.0;
[406]556
[2822]557    for (int i = 0; i < 8; i++) {
[3492]558        Vector4f eyeVert = mv.transform(Vector4f(vertex[i][0],
559                                                 vertex[i][1],
560                                                 vertex[i][2],
561                                                 vertex[i][3]));
[2973]562        if (eyeVert.x < xMin) xMin = eyeVert.x;
563        if (eyeVert.x > xMax) xMax = eyeVert.x;
564        if (eyeVert.y < yMin) yMin = eyeVert.y;
565        if (eyeVert.y > yMax) yMax = eyeVert.y;
566        if (eyeVert.z < zMin) zMin = eyeVert.z;
567        if (eyeVert.z > zMax) zMax = eyeVert.z;
[2822]568    }
[406]569
[2822]570    zNear = zMax;
571    zFar = zMin;
[406]572}
Note: See TracBrowser for help on using the repository browser.