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;
|
||||
float SGCloudField::view_distance = 20000.0f;
|
||||
sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
|
||||
SGCloudField::StateSetMap SGCloudField::cloudTextureMap;
|
||||
|
||||
// reposition the cloud layer at the specified origin and orientation
|
||||
bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
|
||||
|
||||
@@ -137,9 +137,6 @@ public:
|
||||
void applyCoverage(void);
|
||||
void applyVisRange(void);
|
||||
|
||||
typedef std::map<std::string, osg::ref_ptr<osg::StateSet> > StateSetMap;
|
||||
static StateSetMap cloudTextureMap;
|
||||
|
||||
static osg::Fog* getFog()
|
||||
{
|
||||
return CloudFog::instance()->fog.get();
|
||||
|
||||
+25
-136
@@ -44,6 +44,7 @@
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/PathOptions.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||
#include <simgear/scene/util/SGUpdateVisitor.hxx>
|
||||
@@ -60,75 +61,14 @@
|
||||
using namespace simgear;
|
||||
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;
|
||||
|
||||
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,
|
||||
const SGPath &tex_path,
|
||||
@@ -160,75 +100,24 @@ SGNewCloud::SGNewCloud(string type,
|
||||
texture(tex),
|
||||
name(type)
|
||||
{
|
||||
// Create a new StateSet for the texture, if required.
|
||||
StateSetMap::iterator iter = SGCloudField::cloudTextureMap.find(texture);
|
||||
|
||||
if (iter == SGCloudField::cloudTextureMap.end()) {
|
||||
stateSet = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osgDB::ReaderWriter::Options> options = makeOptionsFromPath(tex_path);
|
||||
|
||||
osg::Texture2D *tex = new osg::Texture2D;
|
||||
tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
|
||||
tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
|
||||
tex->setImage(osgDB::readImageFile(texture, options.get()));
|
||||
|
||||
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));
|
||||
// Create a new Effect for the texture, if required.
|
||||
EffectMap::iterator iter = effectMap.find(texture);
|
||||
if (iter == effectMap.end()) {
|
||||
SGPropertyNode_ptr pcloudEffect = new SGPropertyNode;
|
||||
makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud");
|
||||
setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"),
|
||||
"texture"),
|
||||
"image"),
|
||||
texture);
|
||||
osg::ref_ptr<osgDB::ReaderWriter::Options> options
|
||||
= makeOptionsFromPath(tex_path);
|
||||
if ((effect = makeEffect(pcloudEffect, true, options)))
|
||||
effectMap.insert(EffectMap::value_type(texture, effect));
|
||||
} else {
|
||||
stateSet = iter->second.get();
|
||||
effect = iter->second.get();
|
||||
}
|
||||
|
||||
quad = createOrthQuad(min_sprite_width, min_sprite_height, num_textures_x, num_textures_y);
|
||||
quad = createOrthQuad(min_sprite_width, min_sprite_height,
|
||||
num_textures_x, num_textures_y);
|
||||
}
|
||||
|
||||
SGNewCloud::~SGNewCloud() {
|
||||
@@ -285,9 +174,9 @@ static float Rnd(float n) {
|
||||
}
|
||||
#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);
|
||||
|
||||
@@ -365,7 +254,7 @@ osg::ref_ptr<Geode> SGNewCloud::genCloud() {
|
||||
sg->setGeometry(quad);
|
||||
geode->addDrawable(sg);
|
||||
geode->setName("3D cloud");
|
||||
geode->setStateSet(stateSet.get());
|
||||
geode->setEffect(effect.get());
|
||||
|
||||
return geode;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
|
||||
#include "bbcache.hxx"
|
||||
|
||||
#include <simgear/scene/material/Effect.hxx>
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
@@ -59,7 +62,7 @@ public:
|
||||
~SGNewCloud();
|
||||
|
||||
// Generate a Cloud
|
||||
osg::ref_ptr<osg::Geode> genCloud ();
|
||||
osg::ref_ptr<simgear::EffectGeode> genCloud ();
|
||||
|
||||
static double getDensity(void)
|
||||
{
|
||||
@@ -90,7 +93,7 @@ private:
|
||||
const string texture;
|
||||
const string name;
|
||||
osg::Geometry* quad;
|
||||
osg::ref_ptr<osg::StateSet> stateSet;
|
||||
osg::ref_ptr<simgear::Effect> effect;
|
||||
static double sprite_density;
|
||||
|
||||
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
|
||||
|
||||
Reference in New Issue
Block a user