CCloudSceneNode - clouds with levels of detail

Announce new projects or updates of Irrlicht Engine related tools, games, and applications.
Also check the Wiki
3ddev
Posts: 169
Joined: Tue Sep 19, 2006 6:51 am
Contact:

Great Work!

Post by 3ddev »

Great Work Bitplane! This is just what I have been looking for... I will use it for my Azura Racer game. Maybe this could be included into the svn version of Irrlicht? I think it is a really useful addition which many other 3d engines already have.
needforhint
Posts: 322
Joined: Tue Aug 30, 2005 10:34 am
Location: slovakia

Post by needforhint »

wow, I run the exe and I was floating round the clouds like a little kid for 3 minutes. :lol: Cool work
what is this thing...
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

How do I compile this? Dev-cpp is set up for Irrlicht, but I get the following error when I try to compile:

[Linker error] undefined reference to `_imp___ZN3irr12createDeviceENS_5video13E_DRIVER_TYPEERKNS_4core11dimension2dIiEEjbbbPNS_14IEventReceiverEPKc'

EDIT- Nevermind, I had gotten one of the directories wrong. However, I'm not seeing any clouds.
lug
Posts: 79
Joined: Tue May 02, 2006 5:15 am
Contact:

Post by lug »

Baiame wrote:How do I compile this? Dev-cpp is set up for Irrlicht, but I get the following error when I try to compile:

[Linker error] undefined reference to `_imp___ZN3irr12createDeviceENS_5video13E_DRIVER_TYPEERKNS_4core11dimension2dIiEEjbbbPNS_14IEventReceiverEPKc'

EDIT- Nevermind, I had gotten one of the directories wrong. However, I'm not seeing any clouds.
Yes, I don't see any clouds either. If you change the material type from EMT_TRANSPARENT_APLHA_CHANNEL to EMT_TRANSPARENT_ADD_COLOR, you'll see dense, white clouds instead of the normal gray clouds. I've tried out the other EMT_TRANSPARENT_* with hit or miss (either see black borders and square billboard clouds or nothing at all).

Image

Or you can change the texture from "cloud4.png" to either "cloud2.png" or "cloud3.png" to see tiny sparse cloud formations. I've tried this with the SVN rev 276 of irrlicht but I suspect you'll get a similar affect if using the release v1.1 of irrlicht.

Image
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

hmm just spotted this.. i'll have a play with it tomorrow evening
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

works for me in 1.1 svn, didn't try in vanilla 1.1 though.
i made a small update, but the code is still ugly. (you can tell it was the 2nd thing i ever made with irrlicht!)
i'm in no hurry to tidy it up though, if anyone else wants to try they're welcome to it :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
n00b
Posts: 58
Joined: Tue Sep 05, 2006 3:00 pm
Location: Earth
Contact:

Post by n00b »

why doesn't it work with irrlicht 1.1?
i don't see any clouds.
GrigoriosSokratis
Posts: 34
Joined: Wed Apr 25, 2007 3:48 am

Post by GrigoriosSokratis »

Hi, I made it work in Irrlicht 1.3.1 with some changes.

First I moved the whole class and functions definitions from the cpp file to the header file.

Then I replaced the OnPrerender() function with the OnRegisterSceneNode()

Finally changed the s32 getMaterialCount() to u32 and I did the same with other s32 functions all now declared as u32.

It works fine.

Here is the code:
#define CLOUD_PARTICLE_LIMIT 2000

using namespace irr;
using namespace core;
using namespace io;
using namespace scene;
using namespace video;
using namespace gui;


//! Struct for holding particle data
struct SCloudParticle
{
//! distance from camera
f32 distance;

//! Position of the particle, or position relative to parent cloud
core::vector3d<f32> pos;

//! Cloud size
core::dimension2d<f32> size;

//! Cloud colour - (tsk tsk, AmEn)
video::SColor color;

// Number of children
s16 children;

// position of first child
s16 firstchild;

// how much children will be scaled
f32 childscale;
};
struct SCloudBuffer
{

};





//! A particle system scene node.
class CCloudSceneNode : public ISceneNode
{
public:


//! constructor
CCloudSceneNode(ISceneNode* parent, ISceneManager* mgr, ITimer *devicetimer , s32 id,
const core::vector3df& position = core::vector3d<f32>(0,0,0),
const core::vector3df& rotation = core::vector3d<f32>(0,0,0),
const core::vector3df& scale = core::vector3d<f32>(1,1,1))
: ISceneNode(parent, mgr, id, position, rotation, scale)

{
ZOrdering = true;
IgnoreChildColor = true;
MaxDepth = 2;
LOD = 4;
timer = devicetimer;

// create static buffers if required
if (Particles.size() < CLOUD_PARTICLE_LIMIT)
{
Particles.set_used(CLOUD_PARTICLE_LIMIT);
ParticlesToDraw = CLOUD_PARTICLE_LIMIT;
reallocateBuffers();
ParticlesToDraw = 0;
}


#ifdef _DEBUG
setDebugName("CCloudSceneNode");
#endif

//addition by Greg to make alphas below 128 feasible.
Material.MaterialTypeParam = 0.01f;
this->setMaterialFlag(video::EMF_ZWRITE_ENABLE,false);
}

//! destructor
~CCloudSceneNode()
{

}

//! Adds new particle effector to the particle system.
void addAffector(IParticleAffector* affector)
{
affector->grab();
AffectorList.push_back(affector);
}

//! Removes all particle affectors in the particle system.
void removeAllAffectors()
{
core::list<IParticleAffector*>::Iterator it = AffectorList.begin();
while (it != AffectorList.end())
{
(*it)->drop();
it = AffectorList.erase(it);
}
}

//! Returns the material based on the zero based index i.
video::SMaterial& getMaterial(u32 i)
{
return Material;
}

//! Returns amount of materials used by this scene node.
u32 getMaterialCount()
{
return 1;
}

//! pre render event
void OnRegisterSceneNode()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this);
// make cloud particles

makeParticles();

lastcount = ParticlesToDraw;

// printf("built %d in %d\n", lastcount,lasttime);

// order them if needed
if (ZOrdering)
sortParticles();
// call iscenenode's pre-render
ISceneNode::OnRegisterSceneNode();
}
}

//! render
void render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();

if (!camera || !driver)
return;

// calculate vectors for letting particles look to camera
core::vector3df campos = camera->getAbsolutePosition();
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();

core::vector3df horizontal = up.crossProduct(view);
horizontal.normalize();

core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();

view *= -1.0f;

// reallocate arrays, if they are too small
reallocateBuffers();

u32 sp=0;

// if there's more particles that what's allowed, cull the back ones
if (ParticlesToDraw > CLOUD_PARTICLE_LIMIT)
{
sp = ParticlesToDraw - CLOUD_PARTICLE_LIMIT;
}

// lets not use niko's arrays, use a pointer instead
video::S3DVertex *p = Vertices.pointer();

// create particle vertex data
for (u32 i=sp; i<ParticlesToDraw; i++)
{
SCloudParticle& particle = Particles;

core::vector3df h = horizontal * 0.5f * particle.size.Width;
core::vector3df v = vertical * 0.5f * particle.size.Height;

s32 idx = (i-sp)*4;

//p[0+idx].Pos = particle.pos + h + v;
p[0+idx].Pos.X = particle.pos.X + h.X + v.X;
p[0+idx].Pos.Y = particle.pos.Y + h.Y + v.Y;
p[0+idx].Pos.Z = particle.pos.Z + h.Z + v.Z;
p[0+idx].Color = particle.color;
// p[0+idx].Color = particle.color;
p[0+idx].Normal.X = view.X;
p[0+idx].Normal.Y = view.Y;
p[0+idx].Normal.Z = view.Z;

//p[1+idx].Pos = particle.pos + h - v;
p[1+idx].Pos.X = particle.pos.X + h.X - v.X;
p[1+idx].Pos.Y = particle.pos.Y + h.Y - v.Y;
p[1+idx].Pos.Z = particle.pos.Z + h.Z - v.Z;
//p[1+idx].Color = particle.color;
p[1+idx].Normal.X = view.X;
p[1+idx].Normal.Y = view.Y;
p[1+idx].Normal.Z = view.Z;

//p[2+idx].Pos = particle.pos - h - v;
p[2+idx].Pos.X = particle.pos.X - h.X - v.X;
p[2+idx].Pos.Y = particle.pos.Y - h.Y - v.Y;
p[2+idx].Pos.Z = particle.pos.Z - h.Z - v.Z;
p[2+idx].Color = particle.color;
//p[2+idx].Normal = view;
p[2+idx].Normal.X = view.X;
p[2+idx].Normal.Y = view.Y;
p[2+idx].Normal.Z = view.Z;

// p[3+idx].Pos = particle.pos - h + v;
p[3+idx].Pos.X = particle.pos.X - h.X + v.X;
p[3+idx].Pos.Y = particle.pos.Y - h.Y + v.Y;
p[3+idx].Pos.Z = particle.pos.Z - h.Z + v.Z;
p[3+idx].Color = particle.color;
// p[3+idx].Normal = view;
p[3+idx].Normal.X = view.X;
p[3+idx].Normal.Y = view.Y;
p[3+idx].Normal.Z = view.Z;
}

core::matrix4 mat;
driver->setTransform(video::ETS_WORLD, mat);

// driver->draw3DBox( Box, video::SColor(0,255,255,255));

driver->setMaterial(Material);

// get the time
u32 t = timer->getTime();

// draw the mesh
driver->drawIndexedTriangleList(Vertices.pointer(), (ParticlesToDraw-sp)*4,
Indices.pointer(), (ParticlesToDraw-sp)*2);

// get the time taken, so we can cull far clouds next loop
lasttime = timer->getTime()-t;
lastcount = ParticlesToDraw;

//printf("drew %d in %d\n", lastcount,lasttime);

// for debug purposes only:
if (DebugDataVisible)
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(Box, video::SColor(0,255,255,255));
}
}

//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}


// gets the current number of clouds on screen
s16 getCurrentCloudCount()
{
return ParticlesToDraw;
}

void makeRandomCloud(s16 count)
{
// this sets the number of top level clouds
ParticleCount = count;
// ParticleData[<ParticleCount] = top level cloud data
// ParticleData[>=ParticleCount] = child node data

if (ParticleData.size() < count+50)
ParticleData.set_used(count+50);

u32 i;

// make particles
for (i=1; i<count+25; i++)
{
f32 a,b,c;
// random position
if (i < count)
{
a = rand() / 10 - (rand() / 10);
c = rand() / 10 - (rand() / 10);
b = rand() / 500 - (rand() / 500);
}
else
{
a = rand() / 100 - (rand() / 100);
c = rand() / 100 - (rand() / 100);
b = rand() / 100 - (rand() / 100);
}
ParticleData.pos = core::vector3d<f32>(a,b,c);

f32 f = rand() / 50;
if (f < 0) f = -f;

// set the size
ParticleData.size = core::dimension2d<f32>(200+f,200+f);
// distance to dark spot
int f2 = int(rand())%128;
f2+=1;
ParticleData.color = video::SColor(255,255-f2,255-f2,255-f2);
ParticleData.children = 0;
if (rand()/500 > 20) ParticleData.children = int(rand()) %3;
int j = int(rand()) %10;
ParticleData.firstchild = count +j;
ParticleData.childscale = 0.5;
}

// a recursive pattern here-
/*
f32 f = 100.0;
f32 cs = 0.5;
f32 d = rand()/1500;
f32 e = rand()/1500;
//1
ParticleData.color = video::SColor(255,0,0,0);
ParticleData.children = 0;
ParticleData[i].firstchild = 50+4;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(d,0,e);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;

//2
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 0;
ParticleData[i].firstchild = 50+4;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(-d,0,e);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;

//3
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 4;
ParticleData[i].firstchild = 50+4;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(d,0,-e);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;

//4
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 4;
ParticleData[i].firstchild = 50+4;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(-d,0,-e);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;

d = rand()/1500;
e = rand()/1500;

//1
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 0;
ParticleData[i].firstchild = 50;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(d,e,0);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;

//2
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 0;
ParticleData[i].firstchild = 50;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(-d,e,0);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;
d = rand()/1500;
//3
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 4;
ParticleData[i].firstchild = 50;
ParticleData[i].childscale =cs;
ParticleData[i].pos = core::vector3d<f32>(d,-e,0);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;

//4
ParticleData[i].color = video::SColor(255,0,0,0);
ParticleData[i].children = 4;
ParticleData[i].firstchild = 50;
ParticleData[i].childscale = cs;
ParticleData[i].pos = core::vector3d<f32>(-d,-e,0);
ParticleData[i].size = core::dimension2d<f32>(f,f);
i++;
d = rand()/1500;
*/
}

//! turns z sorting on or off.
//! speed increase for alpha blend clouds, or clouds that are one colour
void setZOrdering(bool zo)
{
ZOrdering = zo;
}

//! decides whether child nodes are the same colour as their parents
void setIgnoreChildColor(bool b)
{
IgnoreChildColor = b;
}

//! sets the maximum detail depth to draw
void setMaxDepth(s16 maxdepth)
{
MaxDepth = maxdepth;
}

//! sets the level of detail ("distance/size" - scale of 1 to 10 works well)
void setLOD(f32 levelofdetail)
{
LOD = levelofdetail;
}

//! sets the maximum time allowed to draw the screen.
void setMaxTimePerFrame(u32 t)
{
MaxTimePerFrame = t;
}

private:

// functions
void reallocateBuffers()
{
if (ParticlesToDraw * 4 > Vertices.size() ||
ParticlesToDraw * 6 > Indices.size())
{
s32 oldSize = Vertices.size();
Vertices.set_used(ParticlesToDraw * 4);

u32 i;

// fill remaining vertices
for (i=oldSize; i<Vertices.size(); i+=4)
{
Vertices[0+i].TCoords.set(0.0f, 0.0f);
Vertices[1+i].TCoords.set(0.0f, 1.0f);
Vertices[2+i].TCoords.set(1.0f, 1.0f);
Vertices[3+i].TCoords.set(1.0f, 0.0f);
}

// fill remaining indices
s32 oldIdxSize = Indices.size();
s32 oldvertices = oldSize;
Indices.set_used(ParticlesToDraw * 6);

for (i=oldIdxSize; i<Indices.size(); i+=6)
{
Indices[0+i] = 0+oldvertices;
Indices[1+i] = 2+oldvertices;
Indices[2+i] = 1+oldvertices;
Indices[3+i] = 0+oldvertices;
Indices[4+i] = 3+oldvertices;
Indices[5+i] = 2+oldvertices;
oldvertices += 4;
}
}
}

void sortParticles()
{
u32 i,j, increment;

// because copying particles around in the shell sort was showing up as 99% of
// all cpu time, we'll deal with a list of pointers instead.

// init arrays
if (tmppointers.size() < ParticlesToDraw) tmppointers.set_used(ParticlesToDraw);
if (tmpclouds.size() < ParticlesToDraw) tmpclouds.set_used(ParticlesToDraw);

SCloudParticle *temp = Particles.pointer();

// copy pointers
for (i=0;i<ParticlesToDraw;i++)
tmppointers[i] = temp +i;

// sort the list (shell sort)

// Niko's arrays make function calls, so we'll use a double pointer
SCloudParticle **tp = tmppointers.pointer();

increment = 3;
while (increment > 0)
{
for (i=0; i < ParticlesToDraw; i++)
{
j = i;
temp = tp[i];
while ((j >= increment) && (tp[j-increment]->distance < temp->distance))
{
tp[j] = tp[j - increment];
j = j - increment;
}
tp[j] = temp;
}
if (increment/2 != 0)
increment = increment/2;
else if (increment == 1)
increment = 0;
else
increment = 1;
}

// take list to temp buffer
for (i=0;i<ParticlesToDraw;i++)
tmpclouds[i] = tp[i][0];

// memcopy back to particles
memcpy( Particles.pointer(),tmpclouds.const_pointer() , sizeof(SCloudParticle)*ParticlesToDraw);
// for (i=0;i<ParticlesToDraw;i++)
// Particles[i] = tmpclouds[i];
}

//! makes particle list for rendering/sorting
void makeParticles()
{
core::vector3df rot = getRotation();
core::vector3df pos = getPosition();
// printf("pos = %f, %f, %f\n", pos.X,pos.Y,pos.Z);
core::vector3df campos = SceneManager->getActiveCamera()->getAbsolutePosition();
core::vector3df camrot = SceneManager->getActiveCamera()->getRotation();
//f32 far;
//far = SceneManager->getActiveCamera()->getFarValue();
core::matrix4 m;
core::matrix4 m2;
s16 i,c=0;
m.setInverseRotationDegrees(rot);
m2.setInverseRotationDegrees(camrot);
core::vector3df t;

// reset bounding box
Box.reset(getPosition());

// make each particle
for (i=0; i < ParticleCount; i++)
{

core::vector3df tmppos = ParticleData[i].pos;

// rotate
m.transformVect(tmppos);

// move globally
tmppos += pos;

// set distance from camera
f64 tmpdist = campos.getDistanceFrom(tmppos);

// level of detail culled?
f32 lod = f32(tmpdist) / ParticleData[i].size.Width;

// cull if it's behind the camera
bool cull=false;

// far plane culled
/*if(far < tmpdist)
cull = true;*/

if (lod < LOD*5 && !cull)
{

// copy particle (swap for mem copy?)
Particles[c] = ParticleData[i];

// set it up
Particles[c].pos = tmppos;
Particles[c].distance = tmpdist;

// expand the box
Box.addInternalPoint(Particles[c].pos);

if (lod < LOD && Particles[c].children > 0 && c < CLOUD_PARTICLE_LIMIT)
{
// we add child nodes
depth = 0;
c+= makeChildClouds(Particles[c],c+1,m,campos);
}

if (Particles.size() < c+10)
{
// grow buffer
Particles.set_used(Particles.size()+50);
}

// we added at least one
c+=1;
}
}
ParticlesToDraw = c;
core::matrix4 absinv = AbsoluteTransformation;
absinv.makeInverse();
absinv.transformBox(Box);
}

// adds child clouds to the particle buffer
s16 makeChildClouds(SCloudParticle &parent,s16 start,core::matrix4 &m, core::vector3df &campos )
{
depth+=1;

if (depth>MaxDepth)
{
return (0);
}
if (Particles.size() < start+parent.children)
{
// grow buffer
Particles.set_used(Particles.size()+50);

// buffer too big?
if (start+parent.children > CLOUD_PARTICLE_LIMIT)
{
return (0);
}
}
s16 count;
s16 c = start;

for(count=0;count<parent.children;count++)
{
// copy
Particles[c] = ParticleData[ parent.firstchild + count ];

// scale
Particles[c].pos.X *= parent.childscale;
Particles[c].pos.Y *= parent.childscale;
Particles[c].pos.Z *= parent.childscale;
Particles[c].size.Width *= parent.childscale;
Particles[c].size.Height *= parent.childscale;
Particles[c].childscale *= parent.childscale;

// same colour?
if (IgnoreChildColor)
Particles[c].color = parent.color;

// rotate
m.transformVect(Particles[c].pos);
// position
Particles[c].pos += parent.pos;

// expand the box
Box.addInternalPoint(Particles[c].pos);

// set distance from camera
Particles[c].distance = campos.getDistanceFrom(Particles[c].pos);

// level of detail
f32 lod = f32(Particles[c].distance) / Particles[c].size.Width;
if (lod < LOD && Particles[c].children > 0)
{
// we add child nodes
c+= makeChildClouds(Particles[c],c+1,m,campos);
depth-=1;
// grow buffer?
if (Particles.size() < c+Particles[c].children)
{
Particles.set_used(c+Particles[c].children);
}

if (c > CLOUD_PARTICLE_LIMIT)
{
return (0);
}
}
// we added at least one
c+=1;
}
return (c-start);
}
// shared variables
core::array<SCloudParticle> Particles; //
core::array<video::S3DVertex> Vertices; // 4 vertices per particle
core::array<u16> Indices; // 6 indices per particle

// instance variables
core::list<IParticleAffector*> AffectorList;


core::array<SCloudParticle> ParticleData;
s16 ParticleCount;
s16 ParticlesToDraw;

s16 depth; // for max depth

bool ZOrdering;
bool IgnoreChildColor;
s16 MaxDepth;
f32 LOD;

ITimer *timer;
u32 MaxTimePerFrame; // maximum time allowed to render
u32 lasttime; // last time to draw frame
u32 lastcount; // last number of polys

video::SMaterial Material;
core::aabbox3d<f32> Box;

core::array<SCloudParticle*> tmppointers;
core::array<SCloudParticle> tmpclouds;

};






Now my question is how can I change the size of the clouds to something huge covering my...36sq miles terrain!!!![/quote]
Klasker
Posts: 230
Joined: Thu May 20, 2004 8:53 am
Contact:

Post by Klasker »

First I moved the whole class and functions definitions from the cpp file to the header file.
Le *GASP*!! :shock:
(unindented code block)
Le *GASP* x2!! :shock:
It works fine.
Le *G.. oh wait, good job!
GrigoriosSokratis
Posts: 34
Joined: Wed Apr 25, 2007 3:48 am

Post by GrigoriosSokratis »

Thank you Klasker for the sarcasm, good for u, seems u have plenty of time for it.
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

I moved the class a while back, over to here:

http://irrlicht-plugins.googlecode.com/ ... SceneNode/

if you want access to change and make additions, just let me know by pm or email and i'll give you access :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

But please only when doing useful stuff, not just putting everything into header files :!:
This does not make sense for scene nodes. It's only useful for small time-critical methods!
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Is it v1.4 compatible?
DavidR
Posts: 34
Joined: Sat Jul 15, 2006 5:12 pm

Post by DavidR »

I got this working in 1.3, but I have a strange problem - when the camera is at a certain angle, the clouds totally disappear. I'm not entirely sure why :/
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

It's probably the bounding box being wrong. I've got a new shader based idea for clouds with volumetric lighting, different cloud types (bought "the cloudspotter's guide" last week :D) as well as the recursive detail levels.. It will probably be several months by the time I get round to coding it though.
I'm probably not gonna have time to fix this for 1.4 for a while, so if anyone else wants to have a go, feel free :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Post Reply