Added quad based rain effect

This commit is contained in:
Robert Osfield
2006-04-07 18:24:52 +00:00
parent 761a3b43ac
commit 5335b45146
3 changed files with 156 additions and 21 deletions

View File

@@ -12,6 +12,7 @@
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgUtil/Optimizer>
#include <osgUtil/CullVisitor>
#include <osgProducer/Viewer>
#include <osg/Point>
@@ -19,12 +20,74 @@
#include <osg/Texture2D>
#include <osg/PointSprite>
#include <osg/Program>
#include <osg/Fog>
#include <osg/io_utils>
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<osgUtil::CullVisitor*>(nv);
if (cv)
{
if (!_initialized)
{
_previousModelViewMatrix = cv->getModelViewMatrix();
_previousFrame = nv->getFrameStamp()->getFrameNumber();
_initialized = true;
}
_uniform->set(_previousModelViewMatrix);
// osg::notify(osg::NOTICE)<<"Updating uniform "<<_previousModelViewMatrix<<std::endl;
traverse(node, nv);
if (_previousFrame != nv->getFrameStamp()->getFrameNumber())
{
_previousModelViewMatrix = cv->getModelViewMatrix();
_previousFrame = nv->getFrameStamp()->getFrameNumber();
}
}
else
{
traverse(node, nv);
}
}
int _previousFrame;
bool _initialized;
osg::Matrix _previousModelViewMatrix;
osg::ref_ptr<osg::Uniform> _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));

View File

@@ -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);
}

View File

@@ -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;
}