osg可视化fluid3d

发布时间 2023-11-13 21:56:36作者: abcstar

下面是用osg3.6.5可视化的烟雾模拟,smoke simulation.这里fluid solver来自" Jos Stam, Real-Time Fluid Dynamics for Games",

按D键,添加烟雾,按G,T,H分别添加x,y,z方向的力,添加的烟雾过一阵自动会消散。

screenshot为

 

solver3d.h

#ifndef SOLVER3D_H
#define SOLVER3D_H

#ifdef __cplusplus
extern "C"{
#endif

void dens_step(int,int,int,float *,float *,float *,float *,float *,float,float);
void vel_step(int,int,int,float *,float *,float *,float *,float *,float *,float,float);

#ifdef __cplusplus
}
#endif
#endif

 

solver3d.c

 /*A 3D Real Time Fluid Solver based on Jos Stam's fluid solver (stable N-S solver).  Reference: Jos Stam, "Real-Time Fluid Dynamics for Games". Proceedings of the Game Developer Conference, March 2003.
  *http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf]
  *The code is only for research. 
  *By SoRoMan.
  */

#define IX(i,j,k) ((i)+(M+2)*(j) + (M+2)*(N+2)*(k)) /* 3d arrary access index*/
#define SWAP(x0,x) {float * tmp=x0;x0=x;x=tmp;}
#define FOR_EACH_CELL for ( i=1 ; i<=M ; i++ ) { for ( j=1 ; j<=N ; j++ ) { for ( k=1 ; k<=O ; k++ ) {
#define END_FOR }}}
#define MAX(a,b)            (((a) > (b)) ? (a) : (b))
#define LINEARSOLVERTIMES 10

void add_source ( int M, int N, int O, float * x, float * s, float dt )
{
    int i, size=(M+2)*(N+2)*(O+2);
    for ( i=0 ; i<size ; i++ ) x[i] += dt*s[i];
}

void  set_bnd ( int M, int N, int O, int b, float * x )
{
    int i,j;

    for ( i=1 ; i<=M ; i++ ) {
        for ( j=1 ; j<=N ; j++ ) {
            x[IX(i,j,0 )] = b==3 ? -x[IX(i,j,1)] : x[IX(i,j,1)];
            x[IX(i,j,O+1)] = b==3 ? -x[IX(i,j,O)] : x[IX(i,j,O)];
        }
    }

        for ( i=1 ; i<=N ; i++ ) {
            for ( j=1 ; j<=O ; j++ ) {
                x[IX(0  ,i, j)] = b==1 ? -x[IX(1,i,j)] : x[IX(1,i,j)];
                x[IX(M+1,i, j)] = b==1 ? -x[IX(M,i,j)] : x[IX(M,i,j)];
            }
        }

        for ( i=1 ; i<=M ; i++ ) {
            for ( j=1 ; j<=O ; j++ ) {
                x[IX(i,0,j )] = b==2 ? -x[IX(i,1,j)] : x[IX(i,1,j)];
                x[IX(i,N+1,j)] = b==2 ? -x[IX(i,N,j)] : x[IX(i,N,j)];
            }
        }

        x[IX(0  ,0, 0  )] = 1.0/3.0*(x[IX(1,0,0  )]+x[IX(0  ,1,0)]+x[IX(0 ,0,1)]);
        x[IX(0  ,N+1, 0)] = 1.0/3.0*(x[IX(1,N+1, 0)]+x[IX(0  ,N, 0)] + x[IX(0  ,N+1, 1)]);

        x[IX(M+1,0, 0 )] = 1.0/3.0*(x[IX(M,0,0  )]+x[IX(M+1,1,0)] + x[IX(M+1,0,1)]) ;
        x[IX(M+1,N+1,0)] = 1.0/3.0*(x[IX(M,N+1,0)]+x[IX(M+1,N,0)]+x[IX(M+1,N+1,1)]);

        x[IX(0  ,0, O+1 )] = 1.0/3.0*(x[IX(1,0,O+1  )]+x[IX(0  ,1,O+1)]+x[IX(0 ,0,O)]);
        x[IX(0  ,N+1, O+1)] = 1.0/3.0*(x[IX(1,N+1, O+1)]+x[IX(0  ,N, O+1)] + x[IX(0  ,N+1, O)]);

        x[IX(M+1,0, O+1 )] = 1.0/3.0*(x[IX(M,0,O+1  )]+x[IX(M+1,1,O+1)] + x[IX(M+1,0,O)]) ;
        x[IX(M+1,N+1,O+1)] = 1.0/3.0*(x[IX(M,N+1,O+1)]+x[IX(M+1,N,O+1)]+x[IX(M+1,N+1,O)]);
}

void lin_solve ( int M, int N, int O, int b, float * x, float * x0, float a, float c )
{
    int i, j, k,l;

    for ( l=0 ; l<LINEARSOLVERTIMES ; l++ ) {
        FOR_EACH_CELL
            x[IX(i,j,k)] = (x0[IX(i,j,k)] + a*(x[IX(i-1,j,k)]+x[IX(i+1,j,k)]+x[IX(i,j-1,k)]+x[IX(i,j+1,k)]+x[IX(i,j,k-1)]+x[IX(i,j,k+1)]))/c;
        END_FOR
            set_bnd ( M, N, O, b, x );
    }
}

void diffuse (  int M, int N, int O, int b, float * x, float * x0, float diff, float dt )
{
    /*float a=dt*diff*M*N*O;*/
    int max = MAX(MAX(M, N), MAX(N, O));
    float a=dt*diff*max*max*max;
    lin_solve ( M, N, O, b, x, x0, a, 1+6*a );
}

void advect (  int M, int N, int O, int b, float * d, float * d0, float * u, float * v, float * w, float dt )
{
    int i, j, k, i0, j0, k0, i1, j1, k1;
    float x, y, z, s0, t0, s1, t1, u1, u0, dtx,dty,dtz;
    
    dtx=dty=dtz=dt*MAX(MAX(M, N), MAX(N, O));
    /*dtx = dt*M;
    dty = dt*N;
    dtz = dt*O;*/

    FOR_EACH_CELL
        x = i-dtx*u[IX(i,j,k)]; y = j-dty*v[IX(i,j,k)]; z = k-dtz*w[IX(i,j,k)];
        if (x<0.5f) x=0.5f; if (x>M+0.5f) x=M+0.5f; i0=(int)x; i1=i0+1;
        if (y<0.5f) y=0.5f; if (y>N+0.5f) y=N+0.5f; j0=(int)y; j1=j0+1;
        if (z<0.5f) z=0.5f; if (z>O+0.5f) z=O+0.5f; k0=(int)z; k1=k0+1;

        s1 = x-i0; s0 = 1-s1; t1 = y-j0; t0 = 1-t1; u1 = z-k0; u0 = 1-u1;
        d[IX(i,j,k)] = s0*(t0*u0*d0[IX(i0,j0,k0)]+t1*u0*d0[IX(i0,j1,k0)]+t0*u1*d0[IX(i0,j0,k1)]+t1*u1*d0[IX(i0,j1,k1)])+
            s1*(t0*u0*d0[IX(i1,j0,k0)]+t1*u0*d0[IX(i1,j1,k0)]+t0*u1*d0[IX(i1,j0,k1)]+t1*u1*d0[IX(i1,j1,k1)]);
    END_FOR
        set_bnd (M, N, O, b, d );
}

void project ( int M, int N, int O, float * u, float * v, float * w, float * p, float * div )
{
    int i, j, k;

    FOR_EACH_CELL
        div[IX(i,j,k)] = -1.0/3.0*((u[IX(i+1,j,k)]-u[IX(i-1,j,k)])/M+(v[IX(i,j+1,k)]-v[IX(i,j-1,k)])/M+(w[IX(i,j,k+1)]-w[IX(i,j,k-1)])/M);
        p[IX(i,j,k)] = 0;
    END_FOR    
        set_bnd ( M, N, O, 0, div ); set_bnd (M, N, O, 0, p );

    lin_solve ( M, N, O, 0, p, div, 1, 6 );

    FOR_EACH_CELL
        u[IX(i,j,k)] -= 0.5f*M*(p[IX(i+1,j,k)]-p[IX(i-1,j,k)]);
        v[IX(i,j,k)] -= 0.5f*M*(p[IX(i,j+1,k)]-p[IX(i,j-1,k)]);
        w[IX(i,j,k)] -= 0.5f*M*(p[IX(i,j,k+1)]-p[IX(i,j,k-1)]);
    END_FOR
        set_bnd (  M, N, O, 1, u ); set_bnd (  M, N, O, 2, v );set_bnd (  M, N, O, 3, w);
}

void dens_step ( int M, int N, int O, float * x, float * x0, float * u, float * v, float * w, float diff, float dt )
{
    add_source ( M, N, O, x, x0, dt );
    SWAP ( x0, x ); diffuse ( M, N, O, 0, x, x0, diff, dt );
    SWAP ( x0, x ); advect ( M, N, O, 0, x, x0, u, v, w, dt );
}

void vel_step ( int M, int N, int O, float * u, float * v,  float * w, float * u0, float * v0, float * w0, float visc, float dt )
{
    add_source ( M, N, O, u, u0, dt ); add_source ( M, N, O, v, v0, dt );add_source ( M, N, O, w, w0, dt );
    SWAP ( u0, u ); diffuse ( M, N, O, 1, u, u0, visc, dt );
    SWAP ( v0, v ); diffuse ( M, N, O, 2, v, v0, visc, dt );
    SWAP ( w0, w ); diffuse ( M, N, O, 3, w, w0, visc, dt );
    project ( M, N, O, u, v, w, u0, v0 );
    SWAP ( u0, u ); SWAP ( v0, v );SWAP ( w0, w );
    advect ( M, N, O, 1, u, u0, u0, v0, w0, dt ); advect ( M, N, O, 2, v, v0, u0, v0, w0, dt );advect ( M, N, O, 3, w, w0, u0, v0, w0, dt );
    project ( M, N, O, u, v, w, u0, v0 );
}

main.cpp

// OpenSceneGraph library.
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/StateSetManipulator>
#include <osgGA/TrackballManipulator>
#include <osgViewer/ViewerEventHandlers>
#include <osgUtil/SmoothingVisitor>
#include <osg/BlendFunc>
#include <osg/PositionAttitudeTransform>

#include <stdio.h>
#include "solver3d.h"
#include <time.h>

//#pragma comment(lib, "osg.lib")
//#pragma comment(lib, "osgDB.lib")
//#pragma comment(lib, "osgGA.lib")
//#pragma comment(lib, "osgViewer.lib")
//#pragma comment(lib, "osgUtil.lib")

typedef unsigned char boolean;
#define FALSE 0
#define TRUE 1


/* global variables */
/*fluid field information*/
static int M = 30; /*grid size x*/
static int N = 30; /*grid size y*/
static int O = 30; /*grid size z*/
static float dt = 0.4f; /*time step*/
static float diff = 0.0f; /*diffuse factor*/
static float visc = 0.0f; /*viscous factor*/
static float force = 10.0f;  /*force added each time*/
static float source = 200.0f; /*source added each time*/
static int vert_sum = M*N*O;

//#define VID(i,j,k) ((i)+(M)*(j) + (M)*(N)*(k)) 
//#define VNEXT_I(id) (id+1)
//#define VNEXT_J(id) (id+M)
//#define VNEXT_K(id) (id+M*N)

#define VID(i,j,k) ((i)+(M+2)*(j) + (M+2)*(N+2)*(k)) 
#define VNEXT_I(id) (id+1)
#define VNEXT_J(id) (id+M+2)
#define VNEXT_K(id) (id+(M+2)*(N+2))

#define IX(i,j,k) ((i)+(M+2)*(j) + (M+2)*(N+2)*(k)) 
#define MAX(a,b)            (((a) > (b)) ? (a) : (b))

static boolean addforce[3] = {FALSE, FALSE, FALSE};
static boolean addsource = FALSE;

static float * u, * v, *w, * u_prev, * v_prev, * w_prev;
static float * dens, * dens_prev;

osg::ref_ptr<osg::Geometry> s_volmesh;

static void free_data ( void )
{
    if ( u ) free ( u );
    if ( v ) free ( v );
    if ( w ) free ( w );
    if ( u_prev ) free ( u_prev );
    if ( v_prev ) free ( v_prev );
    if ( w_prev ) free ( w_prev );
    if ( dens ) free ( dens );
    if ( dens_prev ) free ( dens_prev );
}

static void clear_data ( void )
{
    int i, size=(M+2)*(N+2)*(O+2);

    for ( i=0 ; i<size ; i++ ) {
        u[i] = v[i] = w[i] = u_prev[i] = v_prev[i] =w_prev[i] = dens[i] = dens_prev[i] = 0.0f;
    }

    addforce[0] = addforce[1] = addforce[2] = FALSE;
}

static int allocate_data ( void )
{
    int size = (M+2)*(N+2)*(O+2);

    u            = (float *) malloc ( size*sizeof(float) );
    v            = (float *) malloc ( size*sizeof(float) );
    w            = (float *) malloc ( size*sizeof(float) );
    u_prev        = (float *) malloc ( size*sizeof(float) );
    v_prev        = (float *) malloc ( size*sizeof(float) );
    w_prev        = (float *) malloc ( size*sizeof(float) );
    dens        = (float *) malloc ( size*sizeof(float) );    
    dens_prev    = (float *) malloc ( size*sizeof(float) );

    if ( !u || !v || !w || !u_prev || !v_prev || !w_prev || !dens || !dens_prev ) {
        fprintf ( stderr, "cannot allocate data\n" );
        return ( 0 );
    }

    return ( 1 );
}

osg::Geode* buildVolumeMesh(int m, int n, int o, float cellh)
{
    osg::Geode* geod = new osg::Geode;
    s_volmesh = new osg::Geometry;
    geod->addDrawable(s_volmesh);
    s_volmesh->setUseDisplayList(false);
    s_volmesh->setUseVertexBufferObjects(true);

    osg::ref_ptr<osg::Vec3Array> pointsVec = new osg::Vec3Array();
    osg::ref_ptr<osg::Vec4Array> colorVec = new osg::Vec4Array();
    pointsVec->reserve(o*n*m);
    colorVec->assign(o*n*m, osg::Vec4(0.0,0.0,0.0,0.05));
    for (int k = 0; k < o; k++)
    {
        for (int j = 0; j < n; j++)
        {
            for (int i = 0; i < m; i++)
            {
                pointsVec->push_back(osg::Vec3(i*cellh,j*cellh,k*cellh));
            }
        }
    }

    s_volmesh->setVertexArray(pointsVec);
    s_volmesh->setColorArray(colorVec, osg::Array::BIND_PER_VERTEX);

    std::vector<unsigned int> indices;

    for (int k = 0; k < o; k++)
    {
        for (int j = 0; j < (n-1); j++)
        {
            for (int i = 0; i < (m-1); i++)
            {
                //indices.push_back();
                // 3 2
                // 0 1
                unsigned int id0 = VID(i,j,k);
                unsigned int id1 = VNEXT_I(id0);
                unsigned int id3 = VNEXT_J(id0);
                unsigned int id2 = VNEXT_I(id3);

                indices.push_back(id0);
                indices.push_back(id1);
                indices.push_back(id2);
                indices.push_back(id0);
                indices.push_back(id2);
                indices.push_back(id3);
            }
        }
    }


   for (int i = 0; i < m; i++)
    {
        for (int k = 0; k < (o-1); k++)
        {
            for (int j = 0; j < (n-1); j++)
            {
                unsigned int id0 = VID(i,j,k);
                unsigned int id1 = VNEXT_J(id0);
                unsigned int id3 = VNEXT_K(id0);
                unsigned int id2 = VNEXT_J(id3);

                indices.push_back(id0);
                indices.push_back(id1);
                indices.push_back(id2);
                indices.push_back(id0);
                indices.push_back(id2);
                indices.push_back(id3);
            }
        }
    }

    for (int j = 0; j < n; j++)
    {
        for (int i = 0; i < (m-1); i++)
        {
            for (int k = 0; k < (o-1); k++)
            {

                unsigned int id0 = VID(i,j,k);
                unsigned int id1 = VNEXT_K(id0);
                unsigned int id3 = VNEXT_I(id0);
                unsigned int id2 = VNEXT_K(id3);

                indices.push_back(id0);
                indices.push_back(id1);
                indices.push_back(id2);
                indices.push_back(id0);
                indices.push_back(id2);
                indices.push_back(id3);

            }
        }
    }

    s_volmesh->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, indices.size(), (unsigned int*)&indices[0]));
    
    geod->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
    geod->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
    geod->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
    geod->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
    geod->getOrCreateStateSet()->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA),osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
    
    return geod;
}

static void get_force_source ( float * d, float * u, float * v, float * w )
{
    int i, j, k, size=(M+2)*(N+2)*(O+2);;

    for ( i=0 ; i<size ; i++ ) {
        u[i] = v[i] = w[i]= d[i] = 0.0f;
    }

    if(addforce[0]) /*x axis*/
    {
        i=2,
            j=N/2;
        k=O/2;

        if ( i<1 || i>M || j<1 || j>N || k <1 || k>O) return;
        u[IX(i,j,k)] = force*10;
        addforce[0] = FALSE;
    }    

    if(addforce[1])
    {
        i=M/2,
            j=2;
        k=O/2;

        if ( i<1 || i>M || j<1 || j>N || k <1 || k>O) return;
        v[IX(i,j,k)] = force*10;
        addforce[1] = FALSE;
    }    

    if(addforce[2]) /* z-axis*/
    {
        i=M/2,
            j=N/2;
        k=2;

        if ( i<1 || i>M || j<1 || j>N || k <1 || k>O) return;
        w[IX(i,j,k)] = force*10;     
        addforce[2] = FALSE;
    }    

    if(addsource)
    {
        i=M/2,
            j=N/2;
        k=O/2;
        d[IX(i,j,k)] = source;
        addsource = FALSE;
    }

    return;
}

int Game_Init(void)
{
    /*init grid size, temp step, diffuse factor, viscous factor, force and source added each time*/
    /*M = 16;
    N = 16;
    O= 16;
    dt = 0.4f;
    diff = 0.0f;
    visc = 0.0f;
    force = 10.0f;
    source = 200.0f;*/

    /*init rot*/

    if ( !allocate_data () ) 
        return (0);
    clear_data ();

    //init_dens_offs();

    return (1);
}

void display()
{
    osg::Vec4Array* cols = dynamic_cast<osg::Vec4Array*>(s_volmesh->getColorArray());
    for (int i = 0; i < (int)cols->size(); i++)
    {
        float d = dens[i];
        cols->at(i)._v[0] = d;
        cols->at(i)._v[1] = d;
        cols->at(i)._v[2] = d;

        if (d >0.f)
        {
            d *= 0.999f;
        }
        else
        {
            d = 0.f;
        }
        dens[i] = d;
    }

    cols->dirty();
}

int Game_Main(void)
{
    /* compute fluids*/
    get_force_source( dens_prev, u_prev, v_prev, w_prev );
    vel_step ( M,N,O, u, v, w, u_prev, v_prev,w_prev, visc, dt );
    dens_step ( M,N,O, dens, dens_prev, u, v, w, diff, dt );

    /* render fluids*/
    display();    

    return (1);
}

int Game_Shutdown(void)
{
    /* this function is where you shutdown your game and release all resources that you allocated*/
    free_data ();

    /* return success*/
    return(1);
} 

void Game_Reset()
{
    clear_data();
}

class KeyMouseHandler : public osgGA::GUIEventHandler
{
public:
    KeyMouseHandler(){};

    ~KeyMouseHandler(){};

    bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
    {
        if (osgGA::GUIEventAdapter::KEYDOWN == ea.getEventType())
        {
            if (osgGA::GUIEventAdapter::KEY_D == ea.getKey())
            {
                addsource = TRUE;
            }
            else if (osgGA::GUIEventAdapter::KEY_G == ea.getKey())
            {
                addforce[1] = TRUE;
            }
            else if (osgGA::GUIEventAdapter::KEY_H == ea.getKey())
            {
                addforce[0] = TRUE;
            }
            else if (osgGA::GUIEventAdapter::KEY_T == ea.getKey())
            {
                addforce[2] = TRUE;
            }
            else if (osgGA::GUIEventAdapter::KEY_C == ea.getKey())
            {
                Game_Reset();
            }
        }
        else if (osgGA::GUIEventAdapter::FRAME == ea.getEventType())
        {
            Game_Main();
        }
        return false;
    }
};

float GetMidHeight(int i, int stride, std::vector<osg::Vec3>& points)
{
    return 0.5f * (points[i - stride].y() + points[i + stride].y());
}

int CalculateArrayLenght(int iterateTime)
{
    unsigned long base = 0x1;
    unsigned int c = base << iterateTime;
    return c+1;
}

float getRand(float lowb, float upb)
{
    float t = rand() / double(RAND_MAX);
    return lowb*(1.f-t)+upb*t;
}

std::vector<osg::Vec3> Generater1DLineIterative(osg::Vec3 start, osg::Vec3 end, int iterateTime, float heightScale, float h)
{
    srand((unsigned)time(0));
    
    int length = CalculateArrayLenght(iterateTime);
    std::vector<osg::Vec3> points;
    points.assign(length, osg::Vec3(0,0,0));
    points[0] = start;
    points[length - 1] = end;
    float gap = fabs(end.x() - start.x()) / length;
    //Debug.Log("gap: " + gap);
    for(int i=0; i< length; i++)
    {
        points[i] = osg::Vec3(start.x() + i*gap, 0.f, 0.f);
    }
    float ratio, scale;
    ratio = (float)pow(2.0f, -h);
    scale = heightScale;// * ratio;
    int stride = length / 2;
    while(stride != 0)
    {
        for (int i = stride; i < length; i += stride)
        {
            float rd = getRand(-h, h);
            points[i].y() = scale * rd + GetMidHeight(i, stride, points);
            i += stride;
        }
        scale *= ratio;
        //Debug.Log("Stride: " + stride);
        stride >>= 1;
    }
    //       DumpAllPoint(points);
    return points;
}

void Generate1DLineIter(std::vector<osg::Vec3>& points, osg::Vec3 start, osg::Vec3 end, int iterateTime, float roughless)
{
    if (iterateTime > 0)
    {
        float rand = getRand(-2.999f, 2.999f) * roughless;
        osg::Vec3 mid = osg::Vec3(0.5f * start.x() + 0.5f * end.x(), 0.5f * start.y() + 0.5f * end.y() + rand, 0);
        --iterateTime;
        Generate1DLineIter(points, start, mid, iterateTime, roughless*0.5/* * iterateTime * iterateTime*/);
        points.push_back(mid);
        Generate1DLineIter(points, mid, end, iterateTime, roughless*0.5/* * iterateTime * iterateTime*/);
    }
}

std::vector<osg::Vec3> Generate1DLine(osg::Vec3 start, osg::Vec3 end, int iterateTime, float roughless)
{
    srand((unsigned)time(0)); 

    std::vector<osg::Vec3> pts;
    pts.push_back(start);
    Generate1DLineIter(pts, start, end, iterateTime, roughless);
    pts.push_back(end);
    return pts;
}

osg::Geode* testRandStrip()
{
    //std::vector<osg::Vec3> pts = Generater1DLineIterative(osg::Vec3(0,0,0),osg::Vec3(10,0,0),3,2.0,5);
    std::vector<osg::Vec3> pts = Generate1DLine(osg::Vec3(0,0,0),osg::Vec3(10,0,0),12,1.5);

    osg::Geode* geod = new osg::Geode;
    osg::Geometry* geo = new osg::Geometry;
    geod->addDrawable(geo);
    geo->setUseDisplayList(false);
    geo->setUseVertexBufferObjects(true);

    geo->setVertexArray(new osg::Vec3Array(pts.begin(),pts.end()));
    osg::Vec4Array* colorVec = new osg::Vec4Array;
    colorVec->push_back(osg::Vec4(1,1,1,1));
    geo->setColorArray(colorVec, osg::Array::BIND_OVERALL);

    std::vector<unsigned int> indices;
    for (int i = 1; i < pts.size(); i++)
    {
        indices.push_back(i-1);
        indices.push_back(i);
    }
    geo->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::LINES, indices.size(), (unsigned int*)&indices[0]));
    return geod;
}

int main(void)
{
    osgViewer::Viewer myViewer;

    

    //myViewer.setSceneData(BuildScene());
    osg::Group* root = new osg::Group;

    float h = 1.0f/MAX(MAX((M+2), (N+2)), MAX((N+2), (O+2)));
    root->addChild(buildVolumeMesh(M+2,N+2,O+2,h));

    //root->addChild(testRandStrip());

    myViewer.setSceneData(root);
    myViewer.addEventHandler(new KeyMouseHandler);

    myViewer.addEventHandler(new osgGA::StateSetManipulator(myViewer.getCamera()->getOrCreateStateSet()));
    myViewer.addEventHandler(new osgViewer::StatsHandler);
    myViewer.addEventHandler(new osgViewer::WindowSizeHandler);
    myViewer.setCameraManipulator(new osgGA::TrackballManipulator);

    Game_Init();
    myViewer.realize();

    while (!myViewer.done())
    {
        Game_Main();
        myViewer.frame();
    }
    //return myViewer.run();

    return 0;
}