From c144977b6e38129633690bde77d020d3ecd65505 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 21 Apr 2006 19:39:05 +0000 Subject: [PATCH] Added new precipitation nodes. --- examples/osgprecipitation/GNUmakefile | 2 + .../PrecipitationDrawable.cpp | 94 ++ .../osgprecipitation/PrecipitationDrawable.h | 112 +++ .../osgprecipitation/PrecipitationEffect.cpp | 778 +++++++++++++++ .../osgprecipitation/PrecipitationEffect.h | 120 +++ .../PrecipitationParameters.cpp | 13 + .../PrecipitationParameters.h | 100 ++ examples/osgprecipitation/line_rain.vert | 2 +- .../osgprecipitation/osgprecipitation.cpp | 896 +----------------- examples/osgprecipitation/point_rain.frag | 2 +- 10 files changed, 1253 insertions(+), 866 deletions(-) create mode 100644 examples/osgprecipitation/PrecipitationDrawable.cpp create mode 100644 examples/osgprecipitation/PrecipitationDrawable.h create mode 100644 examples/osgprecipitation/PrecipitationEffect.cpp create mode 100644 examples/osgprecipitation/PrecipitationEffect.h create mode 100644 examples/osgprecipitation/PrecipitationParameters.cpp create mode 100644 examples/osgprecipitation/PrecipitationParameters.h diff --git a/examples/osgprecipitation/GNUmakefile b/examples/osgprecipitation/GNUmakefile index 2a5df2185..b6348bfc5 100644 --- a/examples/osgprecipitation/GNUmakefile +++ b/examples/osgprecipitation/GNUmakefile @@ -2,6 +2,8 @@ TOPDIR = ../.. include $(TOPDIR)/Make/makedefs CXXFILES =\ + PrecipitationEffect.cpp\ + PrecipitationDrawable.cpp\ osgprecipitation.cpp\ LIBS += -losgProducer -lProducer -losgText -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) diff --git a/examples/osgprecipitation/PrecipitationDrawable.cpp b/examples/osgprecipitation/PrecipitationDrawable.cpp new file mode 100644 index 000000000..932f07ba2 --- /dev/null +++ b/examples/osgprecipitation/PrecipitationDrawable.cpp @@ -0,0 +1,94 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include "PrecipitationDrawable.h" + +#include +#include + +using namespace osgParticle; + +PrecipitationDrawable::PrecipitationDrawable() +{ + setSupportsDisplayList(false); +} + +PrecipitationDrawable::PrecipitationDrawable(const PrecipitationDrawable& copy, const osg::CopyOp& copyop): + Drawable(copy,copyop) +{ +} + +void PrecipitationDrawable::setParameters(PrecipitationParameters* parameters) +{ + _parameters = parameters; +} + + +void PrecipitationDrawable::compileGLObjects(osg::State& state) const +{ + osg::notify(osg::NOTICE)<<"PrecipitationDrawable::compileGLObjects()"<glMultiTexCoord1f(GL_TEXTURE0+1, _startTime); + + // load cells current modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadMatrix(itr->second.ptr()); + + + CellMatrixMap::const_iterator pitr = _previousCellMatrixMap.find(itr->first); + if (pitr != _previousCellMatrixMap.end()) + { + // load previous frame modelview matrix for motion blurr effect + glMatrixMode( GL_TEXTURE ); + glLoadMatrix(pitr->second.ptr()); + } + else + { + // use current modelview matrix as "previous" frame value, cancelling motion blurr effect + glMatrixMode( GL_TEXTURE ); + glLoadMatrix(itr->second.ptr()); + } + + _geometry->draw(state); + + } + + // restore OpenGL matrices + glMatrixMode( GL_TEXTURE ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + + +} diff --git a/examples/osgprecipitation/PrecipitationDrawable.h b/examples/osgprecipitation/PrecipitationDrawable.h new file mode 100644 index 000000000..5edc5932d --- /dev/null +++ b/examples/osgprecipitation/PrecipitationDrawable.h @@ -0,0 +1,112 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGPARTICLE_PRECIPITATIODRAWABLE +#define OSGPARTICLE_PRECIPITATIODRAWABLE + +#include +#include + +#include "PrecipitationParameters.h" + +namespace osgParticle +{ + + class OSGPARTICLE_EXPORT PrecipitationDrawable : public osg::Drawable + { + public: + + PrecipitationDrawable(); + PrecipitationDrawable(const PrecipitationDrawable& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(osgParticle, PrecipitationDrawable); + + virtual bool supports(const osg::PrimitiveFunctor&) const { return false; } + virtual void accept(osg::PrimitiveFunctor&) const {} + virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return false; } + virtual void accept(osg::PrimitiveIndexFunctor&) const {} + + void setParameters(PrecipitationParameters* parameters); + PrecipitationParameters* getParameters() { return _parameters.get(); } + const PrecipitationParameters* getParameters() const { return _parameters.get(); } + + void setGeometry(osg::Geometry* geom) { _geometry = geom; } + osg::Geometry* getGeometry() { return _geometry.get(); } + const osg::Geometry* getGeometry() const { return _geometry.get(); } + + virtual void compileGLObjects(osg::State& state) const; + + virtual void drawImplementation(osg::State& state) const; + + + + struct Cell + { + Cell(int in_i, int in_j, int in_k): + i(in_i), j(in_j), k(in_k) {} + + + inline bool operator == (const Cell& rhs) const + { + return i==rhs.i && j==rhs.j && k==rhs.k; + } + + inline bool operator != (const Cell& rhs) const + { + return i!=rhs.i || j!=rhs.j || k!=rhs.k; + } + + inline bool operator < (const Cell& rhs) const + { + if (irhs.i) return false; + if (jrhs.j) return false; + if (krhs.k) return false; + return false; + } + + int i; + int j; + int k; + }; + + typedef std::map< Cell, osg::Matrix > CellMatrixMap; + + CellMatrixMap& getCurrentCellMatrixMap() { return _currentCellMatrixMap; } + CellMatrixMap& getPreviousCellMatrixMap() { return _previousCellMatrixMap; } + + inline void newFrame() + { + _previousCellMatrixMap.swap(_currentCellMatrixMap); + _currentCellMatrixMap.clear(); + } + + protected: + + virtual ~PrecipitationDrawable() {} + + osg::ref_ptr _parameters; + + osg::ref_ptr _geometry; + + + mutable CellMatrixMap _currentCellMatrixMap; + mutable CellMatrixMap _previousCellMatrixMap; + + }; + +} + +#endif diff --git a/examples/osgprecipitation/PrecipitationEffect.cpp b/examples/osgprecipitation/PrecipitationEffect.cpp new file mode 100644 index 000000000..b1973f215 --- /dev/null +++ b/examples/osgprecipitation/PrecipitationEffect.cpp @@ -0,0 +1,778 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include "PrecipitationEffect.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace osgParticle; + +#define USE_LOCAL_SHADERS + +static float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; } + +static void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power) +{ + float mid = (float(size)-1.0f)*0.5f; + float div = 2.0f/float(size); + for(unsigned int r=0;rdata(0,r,0); + for(unsigned int c=0;cdata(0,0,0); + fillSpotLightImage(ptr, centerColour, backgroudColour, size, power); + + return image; +#else + osg::Image* image = new osg::Image; + osg::Image::MipmapDataType mipmapData; + unsigned int s = size; + unsigned int totalSize = 0; + unsigned i; + for(i=0; s>0; s>>=1, ++i) + { + if (i>0) mipmapData.push_back(totalSize); + totalSize += s*s*4; + } + + unsigned char* ptr = new unsigned char[totalSize]; + image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1); + + image->setMipmapLevels(mipmapData); + + s = size; + for(i=0; s>0; s>>=1, ++i) + { + fillSpotLightImage(ptr, centerColour, backgroudColour, s, power); + ptr += s*s*4; + } + + return image; +#endif +} + + +PrecipitationEffect::PrecipitationEffect() +{ + setParameters(new PrecipitationParameters); + update(); +} + +PrecipitationEffect::PrecipitationEffect(const PrecipitationEffect& copy, const osg::CopyOp& copyop): + osg::Group(copy,copyop) +{ + setParameters(const_cast(copy._parameters.get())); + update(); +} + +void PrecipitationEffect::compileGLObjects(osg::State& state) const +{ + osg::notify(osg::NOTICE)<<"PrecipitationEffect::compileGLObjects()"<compileGLObjects(state); + if (_quadGeometry->getStateSet()) _quadGeometry->getStateSet()->compileGLObjects(state); + } + + if (_lineGeometry.valid()) + { + _lineGeometry->compileGLObjects(state); + if (_lineGeometry->getStateSet()) _lineGeometry->getStateSet()->compileGLObjects(state); + } + + if (_pointGeometry.valid()) + { + _pointGeometry->compileGLObjects(state); + if (_pointGeometry->getStateSet()) _pointGeometry->getStateSet()->compileGLObjects(state); + } +} + + +void PrecipitationEffect::traverse(osg::NodeVisitor& nv) +{ + if (nv.getVisitorType() == osg::NodeVisitor::NODE_VISITOR) + { + osgUtil::GLObjectsVisitor* globjVisitor = dynamic_cast(&nv); + if (globjVisitor) + { + if (globjVisitor->getMode() & osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES) + { + compileGLObjects(*(globjVisitor->getState())); + } + } + + Group::traverse(nv); + return; + } + + + if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR) + { + Group::traverse(nv); + return; + } + + osgUtil::CullVisitor* cv = dynamic_cast(&nv); + if (!cv) + { + Group::traverse(nv); + return; + } + + ViewIdenitifier viewIndentifier(cv, nv.getNodePath()); + + { + OpenThreads::ScopedLock lock(_mutex); + PrecipitationDrawableSet& precipitationDrawableSet = _viewDrawableMap[viewIndentifier]; + + if (!precipitationDrawableSet._quadPrecipitationDrawable) + { + precipitationDrawableSet._quadPrecipitationDrawable = new PrecipitationDrawable; + precipitationDrawableSet._quadPrecipitationDrawable->setGeometry(_quadGeometry.get()); + precipitationDrawableSet._quadPrecipitationDrawable->setStateSet(_quadStateSet.get()); + + precipitationDrawableSet._linePrecipitationDrawable = new PrecipitationDrawable; + precipitationDrawableSet._linePrecipitationDrawable->setGeometry(_lineGeometry.get()); + precipitationDrawableSet._linePrecipitationDrawable->setStateSet(_lineStateSet.get()); + + precipitationDrawableSet._pointPrecipitationDrawable = new PrecipitationDrawable; + precipitationDrawableSet._pointPrecipitationDrawable->setGeometry(_pointGeometry.get()); + precipitationDrawableSet._pointPrecipitationDrawable->setStateSet(_pointStateSet.get()); + + precipitationDrawableSet.setParameters(_parameters.get()); + } + + cull(precipitationDrawableSet, cv); + + cv->pushStateSet(_precipitationStateSet.get()); + float depth = 0.0f; + + if (!precipitationDrawableSet._quadPrecipitationDrawable->getCurrentCellMatrixMap().empty()) + { + cv->pushStateSet(precipitationDrawableSet._quadPrecipitationDrawable->getStateSet()); + cv->addDrawableAndDepth(precipitationDrawableSet._quadPrecipitationDrawable.get(),&cv->getModelViewMatrix(),depth); + cv->popStateSet(); + } + + if (!precipitationDrawableSet._linePrecipitationDrawable->getCurrentCellMatrixMap().empty()) + { + cv->pushStateSet(precipitationDrawableSet._linePrecipitationDrawable->getStateSet()); + cv->addDrawableAndDepth(precipitationDrawableSet._linePrecipitationDrawable.get(),&cv->getModelViewMatrix(),depth); + cv->popStateSet(); + } + + if (!precipitationDrawableSet._pointPrecipitationDrawable->getCurrentCellMatrixMap().empty()) + { + cv->pushStateSet(precipitationDrawableSet._pointPrecipitationDrawable->getStateSet()); + cv->addDrawableAndDepth(precipitationDrawableSet._pointPrecipitationDrawable.get(),&cv->getModelViewMatrix(),depth); + cv->popStateSet(); + } + + cv->popStateSet(); + + } + + Group::traverse(nv); +} + +void PrecipitationEffect::setParameters(PrecipitationParameters* parameters) +{ + if (_parameters==parameters) return; + + _parameters = parameters; + + // inform the PrecipitationDrawable about the change. + OpenThreads::ScopedLock lock(_mutex); + for(ViewDrawableMap::iterator itr=_viewDrawableMap.begin(); + itr!=_viewDrawableMap.end(); + ++itr) + { + (itr->second).setParameters(parameters); + } +} + +void PrecipitationEffect::update() +{ + osg::notify(osg::NOTICE)<<"PrecipitationEffect::update()"<fogExponent<1.0) + { + _fog->setMode(osg::Fog::LINEAR); + } + else if (_parameters->fogExponent<2.0) + { + _fog->setMode(osg::Fog::EXP); + } + else + { + _fog->setMode(osg::Fog::EXP2); + } + + _fog->setDensity(_parameters->fogDensity); + _fog->setStart(0.0f); + _fog->setEnd(_parameters->fogEnd); + _fog->setColor(_parameters->fogColour); + } + + if (_clearNode.valid()) + { + _clearNode->setClearColor(_parameters->clearColour); + } + + + float length_u = _parameters->cellSizeX; + float length_v = _parameters->cellSizeY; + float length_w = _parameters->cellSizeZ; + + // volume of a single cell + float cellVolume = length_u*length_v*length_w; + + // time taken to get from start to the end of cycle + float period = fabsf(_parameters->cellSizeZ / _parameters->particleVelocity.z()); + + _du.set(length_u, 0.0f, 0.0f); + _dv.set(0.0f, length_v, 0.0f); + _dw.set(0.0f, 0.0f, length_w); + + _inverse_du.set(1.0f/length_u, 0.0f, 0.0f); + _inverse_dv.set(0.0f, 1.0f/length_v, 0.0f); + _inverse_dw.set(0.0f, 0.0f, 1.0f/length_w); + + osg::notify(osg::NOTICE)<<"Cell size X="<addUniform(inversePeriodUniform); // float + //stateset->addUniform(startTime); // float + + _precipitationStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + _precipitationStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); + _precipitationStateSet->addUniform(baseTextureSampler); + + osg::Texture2D* texture = new osg::Texture2D(createSpotLightImage(osg::Vec4(1.0f,1.0f,1.0f,1.0f),osg::Vec4(1.0f,1.0f,1.0f,0.0f),32,1.0)); + _precipitationStateSet->setTextureAttribute(0, texture); + + _precipitationStateSet->addUniform(new osg::Uniform("particleColour", _parameters->particleColour)); + _precipitationStateSet->addUniform(new osg::Uniform("particleSize", _parameters->particleSize)); + + } + +} + +void PrecipitationEffect::createGeometry(unsigned int numParticles, + osg::Geometry* quad_geometry, + osg::Geometry* line_geometry, + osg::Geometry* point_geometry) +{ + // particle corner offsets + osg::Vec2 offset00(0.0f,0.0f); + osg::Vec2 offset10(1.0f,0.0f); + osg::Vec2 offset01(0.0f,1.0f); + osg::Vec2 offset11(1.0f,1.0f); + + osg::Vec2 offset0(0.5f,0.0f); + osg::Vec2 offset1(0.5f,1.0f); + + osg::Vec2 offset(0.5f,0.5f); + + + // configure quad_geometry; + osg::Vec3Array* quad_vertices = 0; + osg::Vec2Array* quad_offsets = 0; + if (quad_geometry) + { + quad_geometry->setName("quad"); + + quad_vertices = new osg::Vec3Array(numParticles*4); + quad_offsets = new osg::Vec2Array(numParticles*4); + + quad_geometry->setVertexArray(quad_vertices); + quad_geometry->setTexCoordArray(0, quad_offsets); + quad_geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4)); + } + + // configure line_geometry; + osg::Vec3Array* line_vertices = 0; + osg::Vec2Array* line_offsets = 0; + if (line_geometry) + { + line_geometry->setName("line"); + + line_vertices = new osg::Vec3Array(numParticles*2); + line_offsets = new osg::Vec2Array(numParticles*2); + + line_geometry->setVertexArray(line_vertices); + line_geometry->setTexCoordArray(0, line_offsets); + line_geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numParticles*2)); + } + + // configure point_geometry; + osg::Vec3Array* point_vertices = 0; + osg::Vec2Array* point_offsets = 0; + if (point_geometry) + { + point_geometry->setName("point"); + + point_vertices = new osg::Vec3Array(numParticles); + point_offsets = new osg::Vec2Array(numParticles); + + point_geometry->setVertexArray(point_vertices); + point_geometry->setTexCoordArray(0, point_offsets); + point_geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles)); + } + + // set up vertex attribute data. + for(unsigned int i=0; i< numParticles; ++i) + { + osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f)); + + // quad particles + if (quad_vertices) + { + (*quad_vertices)[i*4] = pos; + (*quad_vertices)[i*4+1] = pos; + (*quad_vertices)[i*4+2] = pos; + (*quad_vertices)[i*4+3] = pos; + (*quad_offsets)[i*4] = offset00; + (*quad_offsets)[i*4+1] = offset01; + (*quad_offsets)[i*4+2] = offset11; + (*quad_offsets)[i*4+3] = offset10; + } + + // line particles + if (line_vertices) + { + (*line_vertices)[i*2] = pos; + (*line_vertices)[i*2+1] = pos; + (*line_offsets)[i*2] = offset0; + (*line_offsets)[i*2+1] = offset1; + } + + // point particles + if (point_vertices) + { + (*point_vertices)[i] = pos; + (*point_offsets)[i] = offset; + } + } +} + +void PrecipitationEffect::setUpGeometries(unsigned int numParticles) +{ + unsigned int renderBin = 11; + + osg::notify(osg::NOTICE)<<"setUpGeometries("<setUseVertexBufferObjects(true); + + _quadStateSet = new osg::StateSet; + + osg::Program* program = new osg::Program; + _quadStateSet->setAttribute(program); + _quadStateSet->setRenderBinDetails(renderBin,"DepthSortedBin"); + +#ifdef USE_LOCAL_SHADERS + char vertexShaderSource[] = + "uniform float inversePeriod;\n" + "uniform vec4 particleColour;\n" + "uniform float particleSize;\n" + "\n" + "uniform float osg_FrameTime;\n" + "uniform float osg_DeltaFrameTime;\n" + "\n" + "varying vec4 colour;\n" + "varying vec2 texCoord;\n" + "\n" + "void main(void)\n" + "{\n" + " float offset = gl_Vertex.z;\n" + " float startTime = gl_MultiTexCoord1.x;\n" + " texCoord = gl_MultiTexCoord0.xy;\n" + "\n" + " vec4 v_previous = gl_Vertex;\n" + " v_previous.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" + " \n" + " vec4 v_current = v_previous;\n" + " v_current.z += (osg_DeltaFrameTime*inversePeriod);\n" + " \n" + "\n" + " colour = particleColour;\n" + " \n" + " vec4 v1 = gl_ModelViewMatrix * v_current;\n" + " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" + " \n" + " vec3 dv = v2.xyz - v1.xyz;\n" + " \n" + " vec2 dv_normalized = normalize(dv.xy);\n" + " dv.xy += dv_normalized * particleSize;\n" + " vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize;\n" + " \n" + " float area = length(dv.xy);\n" + " colour.a = 0.05+(particleSize)/area;\n" + " \n" + "\n" + " v1.xyz += dv*texCoord.y;\n" + " v1.xy += dp*texCoord.x;\n" + " \n" + " gl_Position = gl_ProjectionMatrix * v1;\n" + "}\n"; + + char fragmentShaderSource[] = + "uniform sampler2D baseTexture;\n" + "varying vec2 texCoord;\n" + "varying vec4 colour;\n" + "\n" + "void main (void)\n" + "{\n" + " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" + "}\n"; + + program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); + program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); +#else + // get shaders from source + program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert"))); + program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); +#endif + } + + + { + _lineGeometry = new osg::Geometry; + _lineGeometry->setUseVertexBufferObjects(true); + + _lineStateSet = new osg::StateSet; + + osg::Program* program = new osg::Program; + _lineStateSet->setAttribute(program); + _lineStateSet->setRenderBinDetails(renderBin,"DepthSortedBin"); + +#ifdef USE_LOCAL_SHADERS + char vertexShaderSource[] = + "uniform float inversePeriod;\n" + "uniform vec4 particleColour;\n" + "uniform float particleSize;\n" + "\n" + "uniform float osg_FrameTime;\n" + "uniform float osg_DeltaFrameTime;\n" + "uniform mat4 previousModelViewMatrix;\n" + "\n" + "varying vec4 colour;\n" + "varying vec2 texCoord;\n" + "\n" + "void main(void)\n" + "{\n" + " float offset = gl_Vertex.z;\n" + " float startTime = gl_MultiTexCoord1.x;\n" + " texCoord = gl_MultiTexCoord0.xy;\n" + "\n" + " vec4 v_previous = gl_Vertex;\n" + " v_previous.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" + " \n" + " vec4 v_current = v_previous;\n" + " v_current.z += (osg_DeltaFrameTime*inversePeriod);\n" + " \n" + " colour = particleColour;\n" + " \n" + " vec4 v1 = gl_ModelViewMatrix * v_current;\n" + " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" + " \n" + " vec3 dv = v2.xyz - v1.xyz;\n" + " \n" + " vec2 dv_normalized = normalize(dv.xy);\n" + " dv.xy += dv_normalized * particleSize;\n" + " \n" + " float area = length(dv.xy);\n" + " colour.a = (particleSize)/area;\n" + " \n" + " v1.xyz += dv*texCoord.y;\n" + " \n" + " gl_Position = gl_ProjectionMatrix * v1;\n" + "}\n"; + + char fragmentShaderSource[] = + "uniform sampler2D baseTexture;\n" + "varying vec2 texCoord;\n" + "varying vec4 colour;\n" + "\n" + "void main (void)\n" + "{\n" + " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" + "}\n"; + + program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); + program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); +#else + // get shaders from source + program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert"))); + program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); +#endif + } + + + { + _pointGeometry = new osg::Geometry; + _pointGeometry->setUseVertexBufferObjects(true); + + _pointStateSet = new osg::StateSet; + + osg::Program* program = new osg::Program; + _pointStateSet->setAttribute(program); + +#ifdef USE_LOCAL_SHADERS + char vertexShaderSource[] = + "uniform float inversePeriod;\n" + "uniform vec4 particleColour;\n" + "uniform float particleSize;\n" + "\n" + "uniform float osg_FrameTime;\n" + "\n" + "varying vec4 colour;\n" + "\n" + "void main(void)\n" + "{\n" + " float offset = gl_Vertex.z;\n" + " float startTime = gl_MultiTexCoord1.x;\n" + "\n" + " vec4 v_current = gl_Vertex;\n" + " v_current.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" + " \n" + " colour = particleColour;\n" + "\n" + " gl_Position = gl_ModelViewProjectionMatrix * v_current;\n" + "\n" + " float pointSize = abs(1280.0*particleSize / gl_Position.w);\n" + "\n" + " //gl_PointSize = max(ceil(pointSize),2);\n" + " gl_PointSize = ceil(pointSize);\n" + " \n" + " colour.a = 0.05+(pointSize*pointSize)/(gl_PointSize*gl_PointSize);\n" + "}\n"; + + char fragmentShaderSource[] = + "uniform sampler2D baseTexture;\n" + "varying vec4 colour;\n" + "\n" + "void main (void)\n" + "{\n" + " gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0].xy);\n" + "}\n"; + + program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); + program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); +#else + // get shaders from source + program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert"))); + program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("point_rain.frag"))); +#endif + + /// Setup the point sprites + osg::PointSprite *sprite = new osg::PointSprite(); + _pointStateSet->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON); + + _pointStateSet->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON); + _pointStateSet->setRenderBinDetails(renderBin,"DepthSortedBin"); + } + + createGeometry(numParticles, _quadGeometry.get(), _lineGeometry.get(), _pointGeometry.get()); + +} + +void PrecipitationEffect::cull(PrecipitationDrawableSet& pds, osgUtil::CullVisitor* cv) const +{ + osg::Timer_t startTick = osg::Timer::instance()->tick(); + + pds._quadPrecipitationDrawable->newFrame(); + pds._linePrecipitationDrawable->newFrame(); + pds._pointPrecipitationDrawable->newFrame(); + + osg::Matrix inverse_modelview; + inverse_modelview.invert(cv->getModelViewMatrix()); + + osg::Vec3 eyeLocal = osg::Vec3(0.0f,0.0f,0.0f) * inverse_modelview; + //osg::notify(osg::NOTICE)<<" eyeLocal "<getProjectionMatrix()); + frustum.transformProvidingInverse(cv->getModelViewMatrix()); + + float i_delta = _parameters->farTransition * _inverse_du.x(); + float j_delta = _parameters->farTransition * _inverse_dv.y(); + float k_delta = 1;//_parameters->nearTransition * _inverse_dw.z(); + + int i_min = (int)floor(eye_i - i_delta); + int j_min = (int)floor(eye_j - j_delta); + int k_min = (int)floor(eye_k - k_delta); + + int i_max = (int)ceil(eye_i + i_delta); + int j_max = (int)ceil(eye_j + j_delta); + int k_max = (int)ceil(eye_k + k_delta); + + //osg::notify(osg::NOTICE)<<"i_delta="<delta_m(startTick,endTick)<<"ms numTested="<getCurrentCellMatrixMap().size()<<" lines "<getCurrentCellMatrixMap().size()<<" points "<getCurrentCellMatrixMap().size()<nearTransition) + { + mymodelview = &(pds._quadPrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)]); + } + else if (distance <= _parameters->farTransition) + { + if (_parameters->useFarLineSegments) + { + mymodelview = &(pds._linePrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)]); + } + else + { + mymodelview = &(pds._pointPrecipitationDrawable->getCurrentCellMatrixMap()[PrecipitationDrawable::Cell(i,k,j)]); + } + } + else + { + return false; + } + + *mymodelview = cv->getModelViewMatrix(); + mymodelview->preMult(osg::Matrix::translate(position)); + mymodelview->preMult(osg::Matrix::scale(scale)); + + return true; +} diff --git a/examples/osgprecipitation/PrecipitationEffect.h b/examples/osgprecipitation/PrecipitationEffect.h new file mode 100644 index 000000000..c9ba630d3 --- /dev/null +++ b/examples/osgprecipitation/PrecipitationEffect.h @@ -0,0 +1,120 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGPARTICLE_PRECIPITATIONEFFECT +#define OSGPARTICLE_PRECIPITATIONEFFECT + +#include +#include +#include +#include + +#include + +#include + +#include "PrecipitationDrawable.h" + +namespace osgParticle +{ + + class OSGPARTICLE_EXPORT PrecipitationEffect : public osg::Group + { + public: + + PrecipitationEffect(); + PrecipitationEffect(const PrecipitationEffect& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + virtual const char* libraryName() const { return "osgParticle"; } + virtual const char* className() const { return "PrecipitationEffect"; } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj) != 0; } + virtual void accept(osg::NodeVisitor& nv) { if (nv.validNodeMask(*this)) { nv.pushOntoNodePath(this); nv.apply(*this); nv.popFromNodePath(); } } + + virtual void traverse(osg::NodeVisitor& nv); + + void setParameters(PrecipitationParameters* parameters); + + PrecipitationParameters* getParameters() { return _parameters.get(); } + + const PrecipitationParameters* getParameters() const { return _parameters.get(); } + + void compileGLObjects(osg::State& state) const; + + void update(); + + protected: + + virtual ~PrecipitationEffect() {} + + void createGeometry(unsigned int numParticles, + osg::Geometry* quad_geometry, + osg::Geometry* line_geometry, + osg::Geometry* point_geometry); + + void setUpGeometries(unsigned int numParticles); + + struct PrecipitationDrawableSet + { + void setParameters(PrecipitationParameters* parameters) + { + if (_quadPrecipitationDrawable.valid()) _quadPrecipitationDrawable->setParameters(parameters); + if (_linePrecipitationDrawable.valid()) _linePrecipitationDrawable->setParameters(parameters); + if (_pointPrecipitationDrawable.valid()) _pointPrecipitationDrawable->setParameters(parameters); + } + + osg::ref_ptr _quadPrecipitationDrawable; + osg::ref_ptr _linePrecipitationDrawable; + osg::ref_ptr _pointPrecipitationDrawable; + }; + + void cull(PrecipitationDrawableSet& pds, osgUtil::CullVisitor* cv) const; + bool build(const osg::Vec3 eyeLocal, int i, int j, int k, PrecipitationDrawableSet& pds, osg::Polytope& frustum, osgUtil::CullVisitor* cv) const; + + osg::ref_ptr _parameters; + + // elements for the subgraph + osg::ref_ptr _clearNode; + osg::ref_ptr _fog; + + + typedef std::pair< osg::NodeVisitor*, osg::NodePath > ViewIdenitifier; + typedef std::map< ViewIdenitifier, PrecipitationDrawableSet > ViewDrawableMap; + + OpenThreads::Mutex _mutex; + ViewDrawableMap _viewDrawableMap; + + osg::ref_ptr _precipitationStateSet; + + osg::ref_ptr _quadGeometry; + osg::ref_ptr _quadStateSet; + + osg::ref_ptr _lineGeometry; + osg::ref_ptr _lineStateSet; + + osg::ref_ptr _pointGeometry; + osg::ref_ptr _pointStateSet; + + + osg::Vec3 _origin; + osg::Vec3 _du; + osg::Vec3 _dv; + osg::Vec3 _dw; + osg::Vec3 _inverse_du; + osg::Vec3 _inverse_dv; + osg::Vec3 _inverse_dw; + + }; + +} + +#endif diff --git a/examples/osgprecipitation/PrecipitationParameters.cpp b/examples/osgprecipitation/PrecipitationParameters.cpp new file mode 100644 index 000000000..543f95220 --- /dev/null +++ b/examples/osgprecipitation/PrecipitationParameters.cpp @@ -0,0 +1,13 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + diff --git a/examples/osgprecipitation/PrecipitationParameters.h b/examples/osgprecipitation/PrecipitationParameters.h new file mode 100644 index 000000000..68767290a --- /dev/null +++ b/examples/osgprecipitation/PrecipitationParameters.h @@ -0,0 +1,100 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGPARTICLE_PRECIPITATIONPARAMETERS +#define OSGPARTICLE_PRECIPITATIONPARAMETERS + +#include + +namespace osgParticle +{ + + struct PrecipitationParameters : public osg::Referenced + { + PrecipitationParameters(): + particleVelocity(0.0,0.0,-5.0), + particleSize(0.02), + particleColour(0.6, 0.6, 0.6, 1.0), + particleDensity(8.0), + cellSizeX(10.0f), + cellSizeY(10.0f), + cellSizeZ(10.0f), + nearTransition(25.0), + farTransition(100.0), + fogExponent(1.0), + fogDensity(0.001), + fogEnd(1000.0), + fogColour(0.5, 0.5, 0.5, 1.0), + clearColour(0.5, 0.5, 0.5, 1.0), + useFarLineSegments(false) + { + rain(0.5); + } + + void rain (float intensity) + { + particleVelocity = osg::Vec3(0.0,0.0,-2.0) + osg::Vec3(0.0,0.0,-10.0)*intensity; + particleSize = 0.01 + 0.02*intensity; + particleColour = osg::Vec4(0.6, 0.6, 0.6, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0)* intensity; + particleDensity = intensity * 8.5f; + cellSizeX = 5.0f / (0.25f+intensity); + cellSizeY = 5.0f / (0.25f+intensity); + cellSizeZ = 5.0f; + farTransition = 100.0f - 60.0f*sqrtf(intensity); + fogExponent = 1.0f; + fogDensity = 0.005f*intensity; + fogEnd = 250/(0.01 + intensity); + fogColour.set(0.5, 0.5, 0.5, 1.0); + clearColour.set(0.5, 0.5, 0.5, 1.0); + useFarLineSegments = false; + } + + void snow(float intensity) + { + particleVelocity = osg::Vec3(0.0,0.0,-1.0) + osg::Vec3(0.0,0.0,-0.5)*intensity; + particleSize = 0.02 + 0.03*intensity; + particleColour = osg::Vec4(0.85f, 0.85f, 0.85f, 1.0f) - osg::Vec4(0.1f, 0.1f, 0.1f, 1.0f)* intensity; + particleDensity = intensity * 8.2f; + cellSizeX = 5.0f / (0.25f+intensity); + cellSizeY = 5.0f / (0.25f+intensity); + cellSizeZ = 5.0f; + farTransition = 100.0f - 60.0f*sqrtf(intensity); + fogExponent = 1.0f; + fogDensity = 0.02f*intensity; + fogEnd = 150.0f/(0.01f + intensity); + fogColour.set(0.6, 0.6, 0.6, 1.0); + clearColour.set(0.6, 0.6, 0.6, 1.0); + useFarLineSegments = false; + } + + osg::BoundingBox boundingBox; + osg::Vec3 particleVelocity; + float particleSize; + osg::Vec4 particleColour; + float particleDensity; + float cellSizeX; + float cellSizeY; + float cellSizeZ; + float nearTransition; + float farTransition; + float fogExponent; + float fogDensity; + float fogEnd; + osg::Vec4 fogColour; + osg::Vec4 clearColour; + bool useFarLineSegments; + }; + +} + +#endif diff --git a/examples/osgprecipitation/line_rain.vert b/examples/osgprecipitation/line_rain.vert index 25cf8c248..19072258f 100644 --- a/examples/osgprecipitation/line_rain.vert +++ b/examples/osgprecipitation/line_rain.vert @@ -4,7 +4,6 @@ uniform float particleSize; uniform float osg_FrameTime; uniform float osg_DeltaFrameTime; -uniform mat4 previousModelViewMatrix; varying vec4 colour; varying vec2 texCoord; @@ -21,6 +20,7 @@ void main(void) vec4 v_current = v_previous; v_current.z += (osg_DeltaFrameTime*inversePeriod); + colour = particleColour; vec4 v1 = gl_ModelViewMatrix * v_current; diff --git a/examples/osgprecipitation/osgprecipitation.cpp b/examples/osgprecipitation/osgprecipitation.cpp index e15a5f1b9..2d8d817f3 100644 --- a/examples/osgprecipitation/osgprecipitation.cpp +++ b/examples/osgprecipitation/osgprecipitation.cpp @@ -25,850 +25,10 @@ #include #include -#define USE_LOCAL_SHADERS 1 - -float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; } - -struct PrecipatationParameters : public osg::Referenced -{ - PrecipatationParameters(): - particleVelocity(0.0,0.0,-5.0), - particleSize(0.02), - particleColour(0.6, 0.6, 0.6, 1.0), - numberOfParticles(10000000), - numberOfCellsX(100), - numberOfCellsY(100), - numberOfCellsZ(1), - nearTransition(25.0), - farTransition(100.0), - fogExponent(1.0), - fogDensity(0.001), - fogEnd(1000.0), - fogColour(0.5, 0.5, 0.5, 1.0), - clearColour(0.5, 0.5, 0.5, 1.0), - useFarLineSegments(false) - { - rain(0.5); - } - - void rain (float intensity) - { - particleVelocity = osg::Vec3(0.0,0.0,-2.0) + osg::Vec3(0.0,0.0,-10.0)*intensity; - particleSize = 0.01 + 0.02*intensity; - particleColour = osg::Vec4(0.6, 0.6, 0.6, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0)* intensity; - numberOfParticles = (int)(intensity * 85000000.0f); - numberOfCellsX = 100 + (int)(100.0f*intensity); - numberOfCellsY = 100 + (int)(100.0f*intensity); - farTransition = 140.0f - 100.0f*intensity; - fogExponent = 1.0f; - fogDensity = 0.005f*intensity; - fogEnd = 250/(0.01 + intensity); - fogColour.set(0.5, 0.5, 0.5, 1.0); - clearColour.set(0.5, 0.5, 0.5, 1.0); - useFarLineSegments = false; - } - - void snow(float intensity) - { - particleVelocity = osg::Vec3(0.0,0.0,-1.0) + osg::Vec3(0.0,0.0,-0.5)*intensity; - particleSize = 0.02 + 0.03*intensity; - particleColour = osg::Vec4(0.85f, 0.85f, 0.85f, 1.0f) - osg::Vec4(0.1f, 0.1f, 0.1f, 1.0f)* intensity; - numberOfParticles = (int)(intensity * 82000000.0f); - numberOfCellsX = 100 + (int)(100.0f*intensity); - numberOfCellsY = 100 + (int)(100.0f*intensity); - farTransition = 140.0f - 100.0f*intensity; - fogExponent = 1.0f; - fogDensity = 0.02f*intensity; - fogEnd = 150.0f/(0.01f + intensity); - fogColour.set(0.6, 0.6, 0.6, 1.0); - clearColour.set(0.6, 0.6, 0.6, 1.0); - useFarLineSegments = false; - } - - osg::BoundingBox boundingBox; - osg::Vec3 particleVelocity; - float particleSize; - osg::Vec4 particleColour; - unsigned int numberOfParticles; - unsigned int numberOfCellsX; - unsigned int numberOfCellsY; - unsigned int numberOfCellsZ; - float nearTransition; - float farTransition; - float fogExponent; - float fogDensity; - float fogEnd; - osg::Vec4 fogColour; - osg::Vec4 clearColour; - bool useFarLineSegments; -}; +#include "PrecipitationEffect.h" #if 0 -struct PrecipitationCullCallback : public virtual osg::Drawable::CullCallback -{ - PrecipitationCullCallback() {} - - PrecipitationCullCallback(const PrecipitationCullCallback&,const osg::CopyOp&) {} - - META_Object(osg,PrecipitationCullCallback); - - /** do customized cull code, return true if drawable should be culled.*/ - virtual bool cull(osg::NodeVisitor* nodeVisitor, osg::Drawable* drawable, osg::State* state) const - { - return false; - } -}; -#endif - -class PrecipitationGeometry : public osg::Geometry -{ -public: - - PrecipitationGeometry() - { - setSupportsDisplayList(false); - - // setCullCallback(new PrecipitationCullCallback()); - } - - virtual bool supports(const osg::PrimitiveFunctor&) const { return false; } - virtual void accept(osg::PrimitiveFunctor&) const {} - virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return false; } - virtual void accept(osg::PrimitiveIndexFunctor&) const {} - - void setInternalGeometry(osg::Geometry* geometry) { _internalGeometry = geometry; } - - osg::Geometry* getInternalGeometry() { return _internalGeometry.get(); } - - void setPosition(const osg::Vec3& position) { _position = position; } - const osg::Vec3& getPosition() const { return _position; } - - void setScale(const osg::Vec3& scale) { _scale = scale; } - const osg::Vec3& getScale() const { return _scale; } - - void setStartTime(float time) { _startTime = time; } - float getStartTime() const { return _startTime; } - - - virtual void compileGLObjects(osg::State& state) const - { - if (!_internalGeometry) return; - - static bool s_interalGeometryCompiled = false; - if (!s_interalGeometryCompiled) - { - _internalGeometry->compileGLObjects(state); - s_interalGeometryCompiled = true; - } - } - - virtual void drawImplementation(osg::State& state) const - { - if (!_internalGeometry) return; - - const Extensions* extensions = getExtensions(state.getContextID(),true); - - glNormal3fv(_position.ptr()); - extensions->glMultiTexCoord1f(GL_TEXTURE0+1, _startTime); - - glPushMatrix(); - - osg::Matrix modelview = state.getModelViewMatrix(); - modelview.preMult(osg::Matrix::translate(_position)); - modelview.preMult(osg::Matrix::scale(_scale)); - - bool isPoint = (_internalGeometry->getName()=="point"); - - glLoadMatrix(modelview.ptr()); - - if (!isPoint) - { - state.setActiveTextureUnit(0); - glMatrixMode( GL_TEXTURE ); - - glPushMatrix(); - - glLoadMatrix(_previousModelView.ptr()); - - _previousModelView = modelview; - } -#if 0 - else - { - state.setActiveTextureUnit(0); - glMatrixMode( GL_TEXTURE ); - - glPushMatrix(); - - glLoadIdentity(); - - _previousModelView = modelview; - } -#endif - _internalGeometry->draw(state); - - - static int s_frameNumber = 0xffffffff; - static unsigned int s_NumberQuads = 0; - static unsigned int s_NumberQuadsVertices = 0; - static unsigned int s_NumberLines = 0; - static unsigned int s_NumberLinesVertices = 0; - static unsigned int s_NumberPoints = 0; - static unsigned int s_NumberPointsVertices = 0; - - if (s_frameNumber != state.getFrameStamp()->getFrameNumber()) - { - // std::cout<<"Frame "<< s_frameNumber<<"\tquads "<getFrameNumber(); - } - - - if (_internalGeometry->getName()=="quad") - { - s_NumberQuads++; - s_NumberQuadsVertices+= _internalGeometry->getVertexArray()->getNumElements(); - } - else if (_internalGeometry->getName()=="line") - { - s_NumberLines++; - s_NumberLinesVertices+= _internalGeometry->getVertexArray()->getNumElements(); - } - else if (_internalGeometry->getName()=="point") - { - s_NumberPoints++; - s_NumberPointsVertices+= _internalGeometry->getVertexArray()->getNumElements(); - } - - if (!isPoint) - { - glPopMatrix(); - glMatrixMode( GL_MODELVIEW ); - } - - glPopMatrix(); - } - - virtual osg::BoundingBox computeBound() const - { - return osg::BoundingBox(); - } - -protected: - - osg::Vec3 _position; - osg::Vec3 _scale; - float _startTime; - osg::ref_ptr _internalGeometry; - mutable osg::Matrix _previousModelView; - -}; - -class CullCallback : public osg::NodeCallback -{ -public: - - CullCallback(osg::Uniform* uniform): - _previousFrame(0), - _initialized(false), - _uniform(uniform) - { - } - - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = dynamic_cast(nv); - if (cv) - { - if (!_initialized) - { - _previousModelViewMatrix = cv->getModelViewMatrix(); - _previousFrame = nv->getFrameStamp()->getFrameNumber(); - _initialized = true; - } - - _uniform->set(_previousModelViewMatrix); - - // osg::notify(osg::NOTICE)<<"Updating uniform "<<_previousModelViewMatrix<getFrameStamp()->getFrameNumber()) - { - _previousModelViewMatrix = cv->getModelViewMatrix(); - _previousFrame = nv->getFrameStamp()->getFrameNumber(); - } - } - else - { - traverse(node, nv); - } - } - - int _previousFrame; - bool _initialized; - osg::Matrix _previousModelViewMatrix; - osg::ref_ptr _uniform; -}; - -void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power) -{ - float mid = (float(size)-1.0f)*0.5f; - float div = 2.0f/float(size); - for(unsigned int r=0;rdata(0,r,0); - for(unsigned int c=0;cdata(0,0,0); - fillSpotLightImage(ptr, centerColour, backgroudColour, size, power); - - return image; -#else - osg::Image* image = new osg::Image; - osg::Image::MipmapDataType mipmapData; - unsigned int s = size; - unsigned int totalSize = 0; - unsigned i; - for(i=0; s>0; s>>=1, ++i) - { - if (i>0) mipmapData.push_back(totalSize); - totalSize += s*s*4; - } - - unsigned char* ptr = new unsigned char[totalSize]; - image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1); - - image->setMipmapLevels(mipmapData); - - s = size; - for(i=0; s>0; s>>=1, ++i) - { - fillSpotLightImage(ptr, centerColour, backgroudColour, s, power); - ptr += s*s*4; - } - - return image; -#endif -} - -/** create quad, line and point geometry data all with consistent particle positions.*/ -void createGeometry(unsigned int numParticles, - osg::Geometry* quad_geometry, - osg::Geometry* line_geometry, - osg::Geometry* point_geometry) -{ - // particle corner offsets - osg::Vec2 offset00(0.0f,0.0f); - osg::Vec2 offset10(1.0f,0.0f); - osg::Vec2 offset01(0.0f,1.0f); - osg::Vec2 offset11(1.0f,1.0f); - - osg::Vec2 offset0(0.5f,0.0f); - osg::Vec2 offset1(0.5f,1.0f); - - osg::Vec2 offset(0.5f,0.5f); - - - // configure quad_geometry; - osg::Vec3Array* quad_vertices = 0; - osg::Vec2Array* quad_offsets = 0; - if (quad_geometry) - { - quad_geometry->setName("quad"); - - quad_vertices = new osg::Vec3Array(numParticles*4); - quad_offsets = new osg::Vec2Array(numParticles*4); - - quad_geometry->setVertexArray(quad_vertices); - quad_geometry->setTexCoordArray(0, quad_offsets); - quad_geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4)); - } - - // configure line_geometry; - osg::Vec3Array* line_vertices = 0; - osg::Vec2Array* line_offsets = 0; - if (line_geometry) - { - line_geometry->setName("line"); - - line_vertices = new osg::Vec3Array(numParticles*2); - line_offsets = new osg::Vec2Array(numParticles*2); - - line_geometry->setVertexArray(line_vertices); - line_geometry->setTexCoordArray(0, line_offsets); - line_geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numParticles*2)); - } - - // configure point_geometry; - osg::Vec3Array* point_vertices = 0; - osg::Vec2Array* point_offsets = 0; - if (point_geometry) - { - point_geometry->setName("point"); - - point_vertices = new osg::Vec3Array(numParticles); - point_offsets = new osg::Vec2Array(numParticles); - - point_geometry->setVertexArray(point_vertices); - point_geometry->setTexCoordArray(0, point_offsets); - point_geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles)); - } - - // set up vertex attribute data. - for(unsigned int i=0; i< numParticles; ++i) - { - osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f)); - - // quad particles - if (quad_vertices) - { - (*quad_vertices)[i*4] = pos; - (*quad_vertices)[i*4+1] = pos; - (*quad_vertices)[i*4+2] = pos; - (*quad_vertices)[i*4+3] = pos; - (*quad_offsets)[i*4] = offset00; - (*quad_offsets)[i*4+1] = offset01; - (*quad_offsets)[i*4+2] = offset11; - (*quad_offsets)[i*4+3] = offset10; - } - - // line particles - if (line_vertices) - { - (*line_vertices)[i*2] = pos; - (*line_vertices)[i*2+1] = pos; - (*line_offsets)[i*2] = offset0; - (*line_offsets)[i*2+1] = offset1; - } - - // point particles - if (point_vertices) - { - (*point_vertices)[i] = pos; - (*point_offsets)[i] = offset; - } - } -} - - -static osg::ref_ptr quad_geometry = 0; -static osg::ref_ptr quad_stateset = 0; - -static osg::ref_ptr line_geometry = 0; -static osg::ref_ptr line_stateset = 0; - -static osg::ref_ptr point_geometry = 0; -static osg::ref_ptr point_stateset = 0; - -void setUpGeometries(unsigned int numParticles) -{ - unsigned int renderBin = 11; - - { - quad_geometry = new osg::Geometry; - quad_geometry->setUseVertexBufferObjects(true); - - quad_stateset = new osg::StateSet; - osg::Program* program = new osg::Program; - quad_stateset->setAttribute(program); - quad_stateset->setRenderBinDetails(renderBin,"DepthSortedBin"); - -#ifdef USE_LOCAL_SHADERS - char vertexShaderSource[] = - "uniform float inversePeriod;\n" - "uniform vec4 particleColour;\n" - "uniform float particleSize;\n" - "\n" - "uniform float osg_FrameTime;\n" - "uniform float osg_DeltaFrameTime;\n" - "\n" - "varying vec4 colour;\n" - "varying vec2 texCoord;\n" - "\n" - "void main(void)\n" - "{\n" - " float offset = gl_Vertex.z;\n" - " float startTime = gl_MultiTexCoord1.x;\n" - " texCoord = gl_MultiTexCoord0.xy;\n" - "\n" - " vec4 v_previous = gl_Vertex;\n" - " v_previous.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" - " \n" - " vec4 v_current = v_previous;\n" - " v_current.z += (osg_DeltaFrameTime*inversePeriod);\n" - " \n" - "\n" - " colour = particleColour;\n" - " \n" - " vec4 v1 = gl_ModelViewMatrix * v_current;\n" - " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" - " \n" - " vec3 dv = v2.xyz - v1.xyz;\n" - " \n" - " vec2 dv_normalized = normalize(dv.xy);\n" - " dv.xy += dv_normalized * particleSize;\n" - " vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize;\n" - " \n" - " float area = length(dv.xy);\n" - " colour.a = 0.05+(particleSize)/area;\n" - " \n" - "\n" - " v1.xyz += dv*texCoord.y;\n" - " v1.xy += dp*texCoord.x;\n" - " \n" - " gl_Position = gl_ProjectionMatrix * v1;\n" - "}\n"; - - char fragmentShaderSource[] = - "uniform sampler2D baseTexture;\n" - "varying vec2 texCoord;\n" - "varying vec4 colour;\n" - "\n" - "void main (void)\n" - "{\n" - " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" - "}\n"; - - program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); - program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); -#else - // get shaders from source - program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert"))); - program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); -#endif - } - - - { - line_geometry = new osg::Geometry; - line_geometry->setUseVertexBufferObjects(true); - - line_stateset = new osg::StateSet; - - osg::Program* program = new osg::Program; - line_stateset->setAttribute(program); - line_stateset->setRenderBinDetails(renderBin,"DepthSortedBin"); - -#ifdef USE_LOCAL_SHADERS - char vertexShaderSource[] = - "uniform float inversePeriod;\n" - "uniform vec4 particleColour;\n" - "uniform float particleSize;\n" - "\n" - "uniform float osg_FrameTime;\n" - "uniform float osg_DeltaFrameTime;\n" - "uniform mat4 previousModelViewMatrix;\n" - "\n" - "varying vec4 colour;\n" - "varying vec2 texCoord;\n" - "\n" - "void main(void)\n" - "{\n" - " float offset = gl_Vertex.z;\n" - " float startTime = gl_MultiTexCoord1.x;\n" - " texCoord = gl_MultiTexCoord0.xy;\n" - "\n" - " vec4 v_previous = gl_Vertex;\n" - " v_previous.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" - " \n" - " vec4 v_current = v_previous;\n" - " v_current.z += (osg_DeltaFrameTime*inversePeriod);\n" - " \n" - " colour = particleColour;\n" - " \n" - " vec4 v1 = gl_ModelViewMatrix * v_current;\n" - " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" - " \n" - " vec3 dv = v2.xyz - v1.xyz;\n" - " \n" - " vec2 dv_normalized = normalize(dv.xy);\n" - " dv.xy += dv_normalized * particleSize;\n" - " \n" - " float area = length(dv.xy);\n" - " colour.a = (particleSize)/area;\n" - " \n" - " v1.xyz += dv*texCoord.y;\n" - " \n" - " gl_Position = gl_ProjectionMatrix * v1;\n" - "}\n"; - - char fragmentShaderSource[] = - "uniform sampler2D baseTexture;\n" - "varying vec2 texCoord;\n" - "varying vec4 colour;\n" - "\n" - "void main (void)\n" - "{\n" - " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" - "}\n"; - - program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); - program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); -#else - // get shaders from source - program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert"))); - program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); -#endif - } - - - { - point_geometry = new osg::Geometry; - point_geometry->setUseVertexBufferObjects(true); - - point_stateset = new osg::StateSet; - - osg::Program* program = new osg::Program; - point_stateset->setAttribute(program); - -#ifdef USE_LOCAL_SHADERS - char vertexShaderSource[] = - "uniform float inversePeriod;\n" - "uniform vec4 particleColour;\n" - "uniform float particleSize;\n" - "\n" - "uniform float osg_FrameTime;\n" - "\n" - "varying vec4 colour;\n" - "\n" - "void main(void)\n" - "{\n" - " float offset = gl_Vertex.z;\n" - " float startTime = gl_MultiTexCoord1.x;\n" - "\n" - " vec4 v_current = gl_Vertex;\n" - " v_current.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" - " \n" - " colour = particleColour;\n" - "\n" - " gl_Position = gl_ModelViewProjectionMatrix * v_current;\n" - "\n" - " float pointSize = abs(1280.0*particleSize / gl_Position.w);\n" - "\n" - " //gl_PointSize = max(ceil(pointSize),2);\n" - " gl_PointSize = ceil(pointSize);\n" - " \n" - " colour.a = 0.05+(pointSize*pointSize)/(gl_PointSize*gl_PointSize);\n" - "}\n"; - - char fragmentShaderSource[] = - "uniform sampler2D baseTexture;\n" - "varying vec4 colour;\n" - "\n" - "void main (void)\n" - "{\n" - " gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0]);\n" - "}\n"; - - program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); - program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); -#else - // get shaders from source - program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert"))); - program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("point_rain.frag"))); -#endif - - /// Setup the point sprites - osg::PointSprite *sprite = new osg::PointSprite(); - point_stateset->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON); - - point_stateset->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON); - point_stateset->setRenderBinDetails(renderBin,"DepthSortedBin"); - } - - createGeometry(numParticles, quad_geometry.get(), line_geometry.get(), point_geometry.get()); - -} - - -osg::Node* createRainEffect(const osg::BoundingBox& bb, const PrecipatationParameters& parameters) -{ - osg::LOD* lod = new osg::LOD; - - - // distance between start point and end of cyclce - osg::Vec3 position(bb.xMin(), bb.yMin(), bb.zMax()); - - // time taken to get from start to the end of cycle - float period = fabs((bb.zMax()-bb.zMin()) / parameters.particleVelocity.z()); - osg::Vec3 dv_i( bb.xMax()-bb.xMin(), 0.0f, 0.0f ); - osg::Vec3 dv_j( 0.0f, bb.yMax()-bb.yMin(), 0.0f ); - osg::Vec3 dv_k( parameters.particleVelocity * period ); - - osg::Vec3 scale( bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), parameters.particleVelocity.z() * period); - - float startTime = random(0, period); - - // high res LOD. - { - osg::Geode* highres_geode = new osg::Geode; - - PrecipitationGeometry* geometry = new PrecipitationGeometry; - - highres_geode->addDrawable(geometry); - - geometry->setName("highres"); - geometry->setPosition(position); - geometry->setScale(scale); - geometry->setStartTime(startTime); - geometry->setInitialBound(bb); - geometry->setInternalGeometry(quad_geometry.get()); - geometry->setStateSet(quad_stateset.get()); - - lod->addChild( highres_geode, 0.0f, parameters.nearTransition ); - } - - - if (parameters.useFarLineSegments) - { - osg::Geode* lowres_geode = new osg::Geode; - - - PrecipitationGeometry* geometry = new PrecipitationGeometry; - - lowres_geode->addDrawable(geometry); - - geometry->setName("lowres"); - geometry->setPosition(position); - geometry->setScale(scale); - geometry->setStartTime(startTime); - geometry->setInitialBound(bb); - geometry->setInternalGeometry(line_geometry.get()); - geometry->setStateSet(line_stateset.get()); - - lod->addChild( lowres_geode, parameters.nearTransition, parameters.farTransition ); - } - else - { - osg::Geode* lowres_geode = new osg::Geode; - - - PrecipitationGeometry* geometry = new PrecipitationGeometry; - - lowres_geode->addDrawable(geometry); - - geometry->setName("lowres"); - geometry->setPosition(position); - geometry->setScale(scale); - geometry->setStartTime(startTime); - geometry->setInitialBound(bb); - geometry->setInternalGeometry(point_geometry.get()); - geometry->setStateSet(point_stateset.get()); - - lod->addChild( lowres_geode, parameters.nearTransition, parameters.farTransition ); - } - - - return lod; -} - -osg::Node* createCellRainEffect(const PrecipatationParameters& parameters) -{ - - unsigned int numX = parameters.numberOfCellsX; - unsigned int numY = parameters.numberOfCellsY; - unsigned int numCells = numX*numY; - unsigned int numParticlesPerCell = parameters.numberOfParticles/numCells; - - setUpGeometries(numParticlesPerCell); - - const osg::BoundingBox& bb = parameters.boundingBox; - - std::cout<<"Effect total number of particles = "<addUniform(inversePeriodUniform); // float - //stateset->addUniform(startTime); // float - - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - - osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); - stateset->addUniform(baseTextureSampler); - - osg::Texture2D* texture = new osg::Texture2D(createSpotLightImage(osg::Vec4(1.0f,1.0f,1.0f,1.0f),osg::Vec4(1.0f,1.0f,1.0f,0.0f),32,1.0)); - stateset->setTextureAttribute(0, texture); - - stateset->addUniform(new osg::Uniform("particleColour", parameters.particleColour)); - stateset->addUniform(new osg::Uniform("particleSize", parameters.particleSize)); - - // osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix()); - // stateset->addUniform(previousModelViewUniform); - - // group->setCullCallback(new CullCallback(previousModelViewUniform)); - - - return group; -} - -osg::Node* createModel(osg::Node* loadedModel, PrecipatationParameters& parameters) +osg::Node* createModel(osg::Node* loadedModel, osgParticle::PrecipitationParameters& parameters) { osg::Group* group = new osg::Group; @@ -924,6 +84,7 @@ osg::Node* createModel(osg::Node* loadedModel, PrecipatationParameters& paramete return group; } +#endif int main( int argc, char **argv ) { @@ -957,7 +118,8 @@ int main( int argc, char **argv ) // get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(*arguments.getApplicationUsage()); - PrecipatationParameters parameters; + osg::ref_ptr precipitationEffect = new osgParticle::PrecipitationEffect; + osgParticle::PrecipitationParameters& parameters = *precipitationEffect->getParameters(); float intensity; while (arguments.read("--snow", intensity)) parameters.snow(intensity); @@ -973,11 +135,11 @@ int main( int argc, char **argv ) while (arguments.read("--nearTransition", parameters.nearTransition )) {} while (arguments.read("--farTransition", parameters.farTransition )) {} - while (arguments.read("--numberOfParticles", parameters.numberOfParticles )) {} + while (arguments.read("--particleDensity", parameters.particleDensity )) {} - while (arguments.read("--numberOfCellsX", parameters.numberOfCellsX )) {} - while (arguments.read("--numberOfCellsY", parameters.numberOfCellsY )) {} - while (arguments.read("--numberOfCellsZ", parameters.numberOfCellsZ )) {} + while (arguments.read("--cellSizeX", parameters.cellSizeX )) {} + while (arguments.read("--cellSizeY", parameters.cellSizeY )) {} + while (arguments.read("--cellSizeZ", parameters.cellSizeZ )) {} while (arguments.read("--boundingBox", parameters.boundingBox.xMin(), parameters.boundingBox.yMin(), @@ -994,8 +156,15 @@ int main( int argc, char **argv ) while (arguments.read("--useFarLineSegments")) { parameters.useFarLineSegments = true; } + + + viewer.setClearColor(parameters.clearColour); + // now force the effect to update all its internal state. + precipitationEffect->update(); + + // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { @@ -1013,31 +182,30 @@ int main( int argc, char **argv ) return 1; } - osg::Timer timer; - osg::Timer_t start_tick = timer.tick(); - // read the scene from the list of file specified commandline args. osg::ref_ptr loadedModel = osgDB::readNodeFiles(arguments); - - loadedModel = createModel(loadedModel.get(), parameters); - - // if no model has been successfully loaded report failure. if (!loadedModel) { std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; return 1; } - - osg::Timer_t end_tick = timer.tick(); - - std::cout << "Time to load = "< group = new osg::Group; + group->addChild(precipitationEffect.get()); + group->addChild(loadedModel.get()); + // set the scene to render - viewer.setSceneData(loadedModel.get()); + viewer.setSceneData(group.get()); + +#else + + loadedModel = createModel(loadedModel.get(), parameters); + + // set the scene to render + viewer.setSceneData(loadedModel.get()); +#endif // create the windows and run the threads. viewer.realize(); diff --git a/examples/osgprecipitation/point_rain.frag b/examples/osgprecipitation/point_rain.frag index 31cb2666e..d71594f05 100644 --- a/examples/osgprecipitation/point_rain.frag +++ b/examples/osgprecipitation/point_rain.frag @@ -3,5 +3,5 @@ varying vec4 colour; void main (void) { - gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0]); + gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0].xy); }