Use an effect for 3d clouds
This commit is contained in:
@@ -71,7 +71,6 @@ float SGCloudField::fieldSize = 50000.0f;
|
|||||||
double SGCloudField::timer_dt = 0.0;
|
double SGCloudField::timer_dt = 0.0;
|
||||||
float SGCloudField::view_distance = 20000.0f;
|
float SGCloudField::view_distance = 20000.0f;
|
||||||
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
||||||
SGCloudField::StateSetMap SGCloudField::cloudTextureMap;
|
|
||||||
|
|
||||||
// reposition the cloud layer at the specified origin and orientation
|
// reposition the cloud layer at the specified origin and orientation
|
||||||
bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
|
bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
|
||||||
|
|||||||
@@ -137,9 +137,6 @@ public:
|
|||||||
void applyCoverage(void);
|
void applyCoverage(void);
|
||||||
void applyVisRange(void);
|
void applyVisRange(void);
|
||||||
|
|
||||||
typedef std::map<std::string, osg::ref_ptr<osg::StateSet> > StateSetMap;
|
|
||||||
static StateSetMap cloudTextureMap;
|
|
||||||
|
|
||||||
static osg::Fog* getFog()
|
static osg::Fog* getFog()
|
||||||
{
|
{
|
||||||
return CloudFog::instance()->fog.get();
|
return CloudFog::instance()->fog.get();
|
||||||
|
|||||||
+25
-136
@@ -44,6 +44,7 @@
|
|||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/PathOptions.hxx>
|
#include <simgear/misc/PathOptions.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/scene/model/model.hxx>
|
#include <simgear/scene/model/model.hxx>
|
||||||
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||||
#include <simgear/scene/util/SGUpdateVisitor.hxx>
|
#include <simgear/scene/util/SGUpdateVisitor.hxx>
|
||||||
@@ -60,75 +61,14 @@
|
|||||||
using namespace simgear;
|
using namespace simgear;
|
||||||
using namespace osg;
|
using namespace osg;
|
||||||
|
|
||||||
typedef std::map<std::string, osg::ref_ptr<osg::StateSet> > StateSetMap;
|
namespace
|
||||||
|
{
|
||||||
|
typedef std::map<std::string, osg::ref_ptr<Effect> > EffectMap;
|
||||||
|
EffectMap effectMap;
|
||||||
|
}
|
||||||
|
|
||||||
StateSetMap cloudTextureMap;
|
|
||||||
double SGNewCloud::sprite_density = 1.0;
|
double SGNewCloud::sprite_density = 1.0;
|
||||||
|
|
||||||
static char vertexShaderSource[] =
|
|
||||||
"#version 120\n"
|
|
||||||
"\n"
|
|
||||||
"varying float fogFactor;\n"
|
|
||||||
"attribute vec3 usrAttr1;\n"
|
|
||||||
"attribute vec3 usrAttr2;\n"
|
|
||||||
"float textureIndexX = usrAttr1.r;\n"
|
|
||||||
"float textureIndexY = usrAttr1.g;\n"
|
|
||||||
"float wScale = usrAttr1.b;\n"
|
|
||||||
"float hScale = usrAttr2.r;\n"
|
|
||||||
"float shade = usrAttr2.g;\n"
|
|
||||||
"float cloud_height = usrAttr2.b;\n"
|
|
||||||
"void main(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndexX, textureIndexY, 0.0, 0.0);\n"
|
|
||||||
" vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0);\n"
|
|
||||||
" vec4 l = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0);\n"
|
|
||||||
" vec3 u = normalize(ep.xyz - l.xyz);\n"
|
|
||||||
// Find a rotation matrix that rotates 1,0,0 into u. u, r and w are
|
|
||||||
// the columns of that matrix.
|
|
||||||
" vec3 absu = abs(u);\n"
|
|
||||||
" vec3 r = normalize(vec3(-u.y, u.x, 0));\n"
|
|
||||||
" vec3 w = cross(u, r);\n"
|
|
||||||
// Do the matrix multiplication by [ u r w pos]. Assume no
|
|
||||||
// scaling in the homogeneous component of pos.
|
|
||||||
" gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
|
|
||||||
" gl_Position.xyz = gl_Vertex.x * u * wScale;\n"
|
|
||||||
" gl_Position.xyz += gl_Vertex.y * r * hScale;\n"
|
|
||||||
" gl_Position.xyz += gl_Vertex.z * w;\n"
|
|
||||||
" gl_Position.xyz += gl_Color.xyz;\n"
|
|
||||||
// Determine a lighting normal based on the vertex position from the
|
|
||||||
// center of the cloud, so that sprite on the opposite side of the cloud to the sun are darker.
|
|
||||||
" float n = dot(normalize(gl_LightSource[0].position.xyz), normalize(mat3x3(gl_ModelViewMatrix) * gl_Position.xyz));\n"
|
|
||||||
// Determine the position - used for fog and shading calculations
|
|
||||||
" vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position);\n"
|
|
||||||
" float fogCoord = abs(ecPosition.z);\n"
|
|
||||||
" float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height);\n"
|
|
||||||
// Final position of the sprite
|
|
||||||
" gl_Position = gl_ModelViewProjectionMatrix * gl_Position;\n"
|
|
||||||
// Limit the normal range from [0,1.0], and apply the shading (vertical factor)
|
|
||||||
" n = min(smoothstep(-0.5, 0.5, n), shade * (1.0 - fract) + fract);\n"
|
|
||||||
// This lighting normal is then used to mix between almost pure ambient (0) and diffuse (1.0) light
|
|
||||||
" vec4 backlight = 0.9 * gl_LightSource[0].ambient + 0.1 * gl_LightSource[0].diffuse;\n"
|
|
||||||
" gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n);\n"
|
|
||||||
" gl_FrontColor += gl_FrontLightModelProduct.sceneColor;\n"
|
|
||||||
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
|
|
||||||
" gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1 - smoothstep(15000.0, 20000.0, fogCoord));\n"
|
|
||||||
" gl_BackColor = gl_FrontColor;\n"
|
|
||||||
// Fog doesn't affect clouds as much as other objects.
|
|
||||||
" fogFactor = exp( -gl_Fog.density * fogCoord * 0.5);\n"
|
|
||||||
" fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
static char fragmentShaderSource[] =
|
|
||||||
"uniform sampler2D baseTexture; \n"
|
|
||||||
"varying float fogFactor;\n"
|
|
||||||
"\n"
|
|
||||||
"void main(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n"
|
|
||||||
" vec4 finalColor = base * gl_Color;\n"
|
|
||||||
" gl_FragColor.rgb = mix(gl_Fog.color.rgb, finalColor.rgb, fogFactor );\n"
|
|
||||||
" gl_FragColor.a = finalColor.a;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
SGNewCloud::SGNewCloud(string type,
|
SGNewCloud::SGNewCloud(string type,
|
||||||
const SGPath &tex_path,
|
const SGPath &tex_path,
|
||||||
@@ -160,75 +100,24 @@ SGNewCloud::SGNewCloud(string type,
|
|||||||
texture(tex),
|
texture(tex),
|
||||||
name(type)
|
name(type)
|
||||||
{
|
{
|
||||||
// Create a new StateSet for the texture, if required.
|
// Create a new Effect for the texture, if required.
|
||||||
StateSetMap::iterator iter = SGCloudField::cloudTextureMap.find(texture);
|
EffectMap::iterator iter = effectMap.find(texture);
|
||||||
|
if (iter == effectMap.end()) {
|
||||||
if (iter == SGCloudField::cloudTextureMap.end()) {
|
SGPropertyNode_ptr pcloudEffect = new SGPropertyNode;
|
||||||
stateSet = new osg::StateSet;
|
makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud");
|
||||||
|
setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"),
|
||||||
osg::ref_ptr<osgDB::ReaderWriter::Options> options = makeOptionsFromPath(tex_path);
|
"texture"),
|
||||||
|
"image"),
|
||||||
osg::Texture2D *tex = new osg::Texture2D;
|
texture);
|
||||||
tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
|
osg::ref_ptr<osgDB::ReaderWriter::Options> options
|
||||||
tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
|
= makeOptionsFromPath(tex_path);
|
||||||
tex->setImage(osgDB::readImageFile(texture, options.get()));
|
if ((effect = makeEffect(pcloudEffect, true, options)))
|
||||||
|
effectMap.insert(EffectMap::value_type(texture, effect));
|
||||||
StateAttributeFactory* attribFactory = StateAttributeFactory::instance();
|
|
||||||
|
|
||||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
|
||||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
|
||||||
|
|
||||||
// Fog handling
|
|
||||||
stateSet->setAttributeAndModes(attribFactory->getSmoothShadeModel());
|
|
||||||
stateSet->setAttributeAndModes(attribFactory->getStandardBlendFunc());
|
|
||||||
|
|
||||||
stateSet->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
|
|
||||||
stateSet->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN, "DepthSortedBin");
|
|
||||||
// Turn off z buffer writes. Standard hack for
|
|
||||||
// semi-transparent geometry to avoid sorting / flickering
|
|
||||||
// artifacts.
|
|
||||||
stateSet->setAttributeAndModes(attribFactory->getDepthWritesDisabled());
|
|
||||||
static ref_ptr<AlphaFunc> alphaFunc;
|
|
||||||
static ref_ptr<Program> program;
|
|
||||||
static ref_ptr<Uniform> baseTextureSampler;
|
|
||||||
static ref_ptr<Material> material;
|
|
||||||
|
|
||||||
// Generate the shader etc, if we don't already have one.
|
|
||||||
if (!program.valid()) {
|
|
||||||
alphaFunc = new AlphaFunc;
|
|
||||||
alphaFunc->setFunction(AlphaFunc::GREATER,0.05f);
|
|
||||||
program = new Program;
|
|
||||||
baseTextureSampler = new osg::Uniform("baseTexture", 0);
|
|
||||||
Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource);
|
|
||||||
program->addShader(vertex_shader);
|
|
||||||
program->addBindAttribLocation("usrAttr1", CloudShaderGeometry::USR_ATTR_1);
|
|
||||||
program->addBindAttribLocation("usrAttr2", CloudShaderGeometry::USR_ATTR_2);
|
|
||||||
Shader* fragment_shader = new Shader(Shader::FRAGMENT, fragmentShaderSource);
|
|
||||||
program->addShader(fragment_shader);
|
|
||||||
material = new Material;
|
|
||||||
// Don´t track vertex color
|
|
||||||
material->setColorMode(Material::OFF);
|
|
||||||
|
|
||||||
// We don't actually use the material information either - see shader.
|
|
||||||
material->setAmbient(Material::FRONT_AND_BACK,
|
|
||||||
Vec4(0.5f, 0.5f, 0.5f, 1.0f));
|
|
||||||
material->setDiffuse(Material::FRONT_AND_BACK,
|
|
||||||
Vec4(0.5f, 0.5f, 0.5f, 1.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
stateSet->setAttributeAndModes(alphaFunc.get());
|
|
||||||
stateSet->setAttribute(program.get());
|
|
||||||
stateSet->addUniform(baseTextureSampler.get());
|
|
||||||
stateSet->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON);
|
|
||||||
stateSet->setAttribute(material.get());
|
|
||||||
|
|
||||||
// Add the newly created texture to the map for use later.
|
|
||||||
SGCloudField::cloudTextureMap.insert(StateSetMap::value_type(texture, stateSet));
|
|
||||||
} else {
|
} else {
|
||||||
stateSet = iter->second.get();
|
effect = iter->second.get();
|
||||||
}
|
}
|
||||||
|
quad = createOrthQuad(min_sprite_width, min_sprite_height,
|
||||||
quad = createOrthQuad(min_sprite_width, min_sprite_height, num_textures_x, num_textures_y);
|
num_textures_x, num_textures_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
SGNewCloud::~SGNewCloud() {
|
SGNewCloud::~SGNewCloud() {
|
||||||
@@ -285,9 +174,9 @@ static float Rnd(float n) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
osg::ref_ptr<Geode> SGNewCloud::genCloud() {
|
osg::ref_ptr<EffectGeode> SGNewCloud::genCloud() {
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> geode = new Geode;
|
osg::ref_ptr<EffectGeode> geode = new EffectGeode;
|
||||||
|
|
||||||
CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y, max_width, max_height);
|
CloudShaderGeometry* sg = new CloudShaderGeometry(num_textures_x, num_textures_y, max_width, max_height);
|
||||||
|
|
||||||
@@ -365,7 +254,7 @@ osg::ref_ptr<Geode> SGNewCloud::genCloud() {
|
|||||||
sg->setGeometry(quad);
|
sg->setGeometry(quad);
|
||||||
geode->addDrawable(sg);
|
geode->addDrawable(sg);
|
||||||
geode->setName("3D cloud");
|
geode->setName("3D cloud");
|
||||||
geode->setStateSet(stateSet.get());
|
geode->setEffect(effect.get());
|
||||||
|
|
||||||
return geode;
|
return geode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
#include "bbcache.hxx"
|
#include "bbcache.hxx"
|
||||||
|
|
||||||
|
#include <simgear/scene/material/Effect.hxx>
|
||||||
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ public:
|
|||||||
~SGNewCloud();
|
~SGNewCloud();
|
||||||
|
|
||||||
// Generate a Cloud
|
// Generate a Cloud
|
||||||
osg::ref_ptr<osg::Geode> genCloud ();
|
osg::ref_ptr<simgear::EffectGeode> genCloud ();
|
||||||
|
|
||||||
static double getDensity(void)
|
static double getDensity(void)
|
||||||
{
|
{
|
||||||
@@ -90,7 +93,7 @@ private:
|
|||||||
const string texture;
|
const string texture;
|
||||||
const string name;
|
const string name;
|
||||||
osg::Geometry* quad;
|
osg::Geometry* quad;
|
||||||
osg::ref_ptr<osg::StateSet> stateSet;
|
osg::ref_ptr<simgear::Effect> effect;
|
||||||
static double sprite_density;
|
static double sprite_density;
|
||||||
|
|
||||||
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
|
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
|
||||||
|
|||||||
Reference in New Issue
Block a user