From 5335b45146252ac446ea0df8bb63971394cd517d Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 7 Apr 2006 18:24:52 +0000 Subject: [PATCH] Added quad based rain effect --- .../osgprecipitation/osgprecipitation.cpp | 141 +++++++++++++++--- examples/osgprecipitation/rain.frag | 4 +- examples/osgprecipitation/rain.vert | 32 +++- 3 files changed, 156 insertions(+), 21 deletions(-) diff --git a/examples/osgprecipitation/osgprecipitation.cpp b/examples/osgprecipitation/osgprecipitation.cpp index 57aa2bf72..35da4568b 100644 --- a/examples/osgprecipitation/osgprecipitation.cpp +++ b/examples/osgprecipitation/osgprecipitation.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -19,12 +20,74 @@ #include #include #include +#include +#include float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; } +class PrecipitationGeometry : public osg::Geometry +{ +public: + 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 {} + +}; + +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; +}; + osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocity, unsigned int numParticles, bool useShaders) { - osg::Geometry* geometry = new osg::Geometry; + osg::Geode* geode = new osg::Geode; + + osg::Geometry* geometry = new PrecipitationGeometry; + geode->addDrawable(geometry); osg::StateSet* stateset = geometry->getOrCreateStateSet(); @@ -32,17 +95,30 @@ osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocit { // per vertex properties - osg::Vec3Array* vertices = new osg::Vec3Array(numParticles*2); - osg::FloatArray* offsets = new osg::FloatArray(numParticles*2); + osg::Vec3Array* vertices = new osg::Vec3Array(numParticles*4); + osg::Vec3Array* offsets = new osg::Vec3Array(numParticles*4); osg::Vec3 frameDelta = velocity*(2.0f/60.0f); + float size = 1.0; for(unsigned int i=0; i< numParticles; ++i) { - (*vertices)[i*2].set(random(bb.xMin(), bb.xMax()), random(bb.yMin(),bb.yMax()), bb.zMax()); - (*vertices)[i*2+1] = (*vertices)[i*2] + frameDelta; - (*offsets)[i*2] = random(0.0, 1.0); - (*offsets)[i*2+1] = (*offsets)[i*2]; + (*vertices)[i*4].set(random(bb.xMin(), bb.xMax()), random(bb.yMin(),bb.yMax()), bb.zMax()); + (*vertices)[i*4+1] = (*vertices)[i*4]; + (*vertices)[i*4+2] = (*vertices)[i*4]; + (*vertices)[i*4+3] = (*vertices)[i*4]; + (*offsets)[i*4].z() = random(0.0, 1.0); + (*offsets)[i*4+1].z() = (*offsets)[i*4].z(); + (*offsets)[i*4+2].z() = (*offsets)[i*4].z(); + (*offsets)[i*4+3].z() = (*offsets)[i*4].z(); + (*offsets)[i*4].x() = 0.0; + (*offsets)[i*4].y() = 0.0; + (*offsets)[i*4+1].x() = 0.0; + (*offsets)[i*4+1].y() = 1.0; + (*offsets)[i*4+2].x() = 1.0; + (*offsets)[i*4+2].y() = 1.0; + (*offsets)[i*4+3].x() = 1.0; + (*offsets)[i*4+3].y() = 0.0; } geometry->setVertexArray(vertices); @@ -50,11 +126,11 @@ osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocit // overall attributes osg::Vec4Array* colours = new osg::Vec4Array(1); - (*colours)[0].set(0.5f,0.5f,0.5f,0.5f); + (*colours)[0].set(0.5f,0.5f,0.5f,1.0f); geometry->setColorArray(colours); geometry->setColorBinding(osg::Geometry::BIND_OVERALL); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numParticles)); + geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4)); } // set up state. @@ -83,15 +159,25 @@ osg::Node* createRainEffect(const osg::BoundingBox& bb, const osg::Vec3& velocit stateset->addUniform(deltaUniform); stateset->addUniform(inversePeriodUniform); stateset->addUniform(startTime); + + osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); + stateset->addUniform(baseTextureSampler); + + osg::Texture2D* texture = new osg::Texture2D(osgDB::readImageFile("Images/particle.rgb")); + stateset->setTextureAttribute(0, texture); + + // make it render after the normal transparent bin + stateset->setRenderBinDetails(11,"DepthSortedBin"); + + osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix()); + stateset->addUniform(previousModelViewUniform); + geode->setCullCallback(new CullCallback(previousModelViewUniform)); + } geometry->setUseVertexBufferObjects(true); geometry->setInitialBound(bb); - - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - return geode; } /* @@ -168,16 +254,37 @@ osg::Node* createModel(osg::Node* loadedModel, bool useShaders) osg::BoundingBox bb(0.0, 0.0, 0.0, 100.0, 100.0, 100.0); osg::Vec3 velocity(0.0,0.0,-2.0); - unsigned int numParticles = 100000; + unsigned int numParticles = 150000; if (loadedModel) { group->addChild(loadedModel); osg::BoundingSphere bs = loadedModel->getBound(); - bs.radius() *= 0.75; - bb.init(); - bb.expandBy(bs); + + bb.set( -100, -100, 0, +100, +100, 10); + + osg::StateSet* stateset = loadedModel->getOrCreateStateSet(); + + osg::Fog* fog = new osg::Fog; + fog->setMode(osg::Fog::LINEAR); + fog->setDensity(0.1f); + fog->setStart(0.0f); + fog->setEnd(1000.0f); + fog->setColor(osg::Vec4(0.5f,0.5f,0.5f,1.0f)); + stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); + + osg::LightSource* lightSource = new osg::LightSource; + group->addChild(lightSource); + + osg::Light* light = lightSource->getLight(); + light->setLightNum(0); + light->setPosition(osg::Vec4(0.0f,0.0f,1.0f,0.0f)); // directional light from above + light->setAmbient(osg::Vec4(0.8f,0.8f,0.8f,1.0f)); + light->setDiffuse(osg::Vec4(0.2f,0.2f,0.2f,1.0f)); + light->setSpecular(osg::Vec4(0.2f,0.2f,0.2f,1.0f)); + + } group->addChild(createRainEffect(bb, velocity, numParticles, useShaders)); diff --git a/examples/osgprecipitation/rain.frag b/examples/osgprecipitation/rain.frag index 3396939e5..7f7be861b 100644 --- a/examples/osgprecipitation/rain.frag +++ b/examples/osgprecipitation/rain.frag @@ -1,6 +1,8 @@ +uniform sampler2D baseTexture; +varying vec2 texCoord; varying vec4 colour; void main (void) { - gl_FragColor = colour; + gl_FragColor = colour * texture2D( baseTexture, texCoord); } diff --git a/examples/osgprecipitation/rain.vert b/examples/osgprecipitation/rain.vert index dcd3b3cf1..0ada2b113 100644 --- a/examples/osgprecipitation/rain.vert +++ b/examples/osgprecipitation/rain.vert @@ -2,14 +2,40 @@ uniform vec3 delta; uniform float inversePeriod; uniform float startTime; uniform float osg_FrameTime; +uniform float osg_DeltaFrameTime; +uniform mat4 previousModelViewMatrix; + varying vec4 colour; +varying vec2 texCoord; void main(void) { - float offset = gl_MultiTexCoord0.x; + const float particleSize = 0.01; + const float particleSize2 = 0.0001;//particleSize*particleSize; - vec3 v = gl_Vertex.xyz + delta * fract( (osg_FrameTime - startTime)*inversePeriod - offset); + float offset = gl_MultiTexCoord0.z; + texCoord = gl_MultiTexCoord0.xy; + + vec3 v_previous = gl_Vertex.xyz + delta * fract( (osg_FrameTime - startTime)*inversePeriod - offset); + vec3 v_current = v_previous + delta * (osg_DeltaFrameTime*inversePeriod); colour = gl_Color; - gl_Position = gl_ModelViewProjectionMatrix * vec4(v,1.0); + + vec4 v1 = gl_ModelViewMatrix * vec4(v_current,1.0); + vec4 v2 = previousModelViewMatrix * vec4(v_previous,1.0); + + vec3 dv = v2.xyz - v1.xyz; + + vec2 dv_normalized = normalize(dv.xy); + dv.xy += dv_normalized * particleSize; + vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize; + + float area = length(dv.xy)*length(dp); + colour.a = 0.2+(particleSize2)/area; + + + v1.xyz += dv*texCoord.y; + v1.xy += dp*texCoord.x; + + gl_Position = gl_ProjectionMatrix * v1; }