The skydome function below is now part of Irrlicht 1.1 and obviously the subsequent SVN updates. Thus, use this instead of the code below. Sry about the missing pictures, but I do clean my http drive occasionally.
---------------
I've made a sky dome construction similar to the sky box for my current project. I think it looks better than the sky box (it does not have the box-look that you tend to get with skybox), and you can use those really nice 360 degrees panorama shots available on the net.
So, guess what, I though I'd share it
It is based on the sky box code in the engine; I've simply replaced the box mesh with a dome mesh based on standard spherical coordinates.
To ease the use, here's a step-by-step list to implement it in your project (you can also add it to the engine if you want to, however, I prefer to have it separately for when the engine is upgraded).
1) Add the following code in one of you header files:
Code: Select all
class CSkyDomeSceneNode : public ISceneNode
{
public:
CSkyDomeSceneNode(video::ITexture*, int, int, double, double, ISceneNode*, ISceneManager*, s32);
virtual ~CSkyDomeSceneNode();
virtual void OnPreRender();
virtual void render();
virtual const core::aabbox3d<f32>& getBoundingBox() const;
virtual video::SMaterial& getMaterial(s32 i);
virtual s32 getMaterialCount();
virtual ESCENE_NODE_TYPE getType() { return ESNT_SKY_BOX; }
private:
core::aabbox3d<f32> Box;
u16 *Indices;
video::S3DVertex *Vertices;
video::SMaterial Material;
u16 NumOfVertices;
u16 NumOfFaces;
};
Code: Select all
/* hori_res and vert_res:
Controls the number of faces along the horizontal axis (30 is a good value)
and the number of faces along the vertical axis (8 is a good value).
image_percentage:
Only the top image_percentage of the image is used, e.g. 0.8 uses the top 80% of the image,
1.0 uses the entire image. This is useful as some landscape images have a small banner
at the bottom that you don't want.
half_sphere_fraction:
This controls how far around the sphere the sky dome goes. For value 1.0 you get exactly the upper
hemisphere, for 1.1 you get slightly more, and for 2.0 you get a full sphere. It is sometimes useful
to use a value slightly bigger than 1 to avoid a gap between some ground place and the sky. This
parameters stretches the image to fit the chosen "sphere-size". */
CSkyDomeSceneNode::CSkyDomeSceneNode(video::ITexture* sky, int hori_res, int vert_res,
double image_percentage, double half_sphere_fraction, ISceneNode* parent, ISceneManager* mgr, s32 id)
: ISceneNode(parent, mgr, id)
{
double radius = 1000; /* Adjust this to get more or less perspective distorsion. */
double azimuth, azimuth_step;
double elevation, elevation_step;
int k, j, c;
S3DVertex vtx;
AutomaticCullingEnabled = false;
Material.Lighting = false;
Material.ZBuffer = false;
Material.ZWriteEnable = false;
Material.BilinearFilter = true;
Material.Texture1 = sky;
azimuth_step = 2.*pi/(double)hori_res;
elevation_step = half_sphere_fraction*pi/2./(double)vert_res;
NumOfVertices = (hori_res+1)*(vert_res+1);
NumOfFaces = (2*vert_res-1)*hori_res;
Vertices = new S3DVertex[NumOfVertices];
Indices = new u16[3*NumOfFaces];
vtx.Color.set(255,255,255,255);
vtx.Normal.set(0,0,0);
c = 0;
for (k = 0, azimuth = 0; k <= hori_res; k++, azimuth += azimuth_step)
{
for (j = 0, elevation = pi/2.; j <= vert_res; j++, elevation -= elevation_step)
{
vtx.Pos.set(radius*cos(elevation)*sin(azimuth),radius*sin(elevation)+50,radius*cos(elevation)*cos(azimuth));
vtx.TCoords.set((f32)k/(f32)hori_res, (f32)j/(f32)vert_res*image_percentage);
Vertices[c++] = vtx;
}
}
c = 0;
for (k = 0; k < hori_res; k++)
{
Indices[c++] = vert_res+2+(vert_res+1)*k;
Indices[c++] = 1+(vert_res+1)*k;
Indices[c++] = 0+(vert_res+1)*k;
for (j = 1; j < vert_res; j++)
{
Indices[c++] = vert_res+2+(vert_res+1)*k+j;
Indices[c++] = 1+(vert_res+1)*k+j;
Indices[c++] = 0+(vert_res+1)*k+j;
Indices[c++] = vert_res+1+(vert_res+1)*k+j;
Indices[c++] = vert_res+2+(vert_res+1)*k+j;
Indices[c++] = 0+(vert_res+1)*k+j;
}
}
}
//! destructor
CSkyDomeSceneNode::~CSkyDomeSceneNode()
{
}
//! renders the node.
void CSkyDomeSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
if ( !camera->isOrthogonal() )
{
core::matrix4 mat;
mat.setTranslation(camera->getAbsolutePosition());
driver->setTransform(video::ETS_WORLD, mat);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(Vertices, NumOfVertices, Indices, NumOfFaces);
}
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CSkyDomeSceneNode::getBoundingBox() const
{
return Box;
}
void CSkyDomeSceneNode::OnPreRender()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this, ESNRP_SKY_BOX);
ISceneNode::OnPreRender();
}
//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hirachy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
video::SMaterial& CSkyDomeSceneNode::getMaterial(s32 i)
{
return Material;
}
//! returns amount of materials used by this scene node.
s32 CSkyDomeSceneNode::getMaterialCount()
{
return 1;
}
Code: Select all
ISceneNode* node = new CSkyDomeSceneNode(driver->getTexture("filename"),30,8,0.96f,2.f,smgr->getRootSceneNode(),smgr,0);
node->drop();
Note that the dome uses a triangular mesh (doh!) and that all faces in the dome are actualy made up of squares from two triangles, except for the the top-most part of the dome, which is constructed directly from triangles. This gives a nice look at zenith. This feature is not implemented at the bottom of the sphere (as I figured that this is not so often used), so you MIGHT get a slightly off-looking pattern a the very bottom.
Note also that as skybox this is implemented as a static mesh that always renders around your current camera position (this gives an impression of the box/dome not moving). Consequently, you cannot shift the horizon down by moving the scene upwards in order to hide any potential gap between your ground and the bottom end of the sky image. Instead, you should use the half_sphere_fraction value in the constructor to adjust this.
Here are a couple of examples (I through in a helicopter from my project to add at least some other than just the dome):
This first one is a galactic thing using this
as panorama view. This gives you your well-known "helicopter leaving the galaxy" kind of look.
This second screen shot of the same scene is directly towards the top of the dome to show that it looks quite nice.
The second example is more earthlike. This is used as panorama:
Notice how the not so circular rings around the sun becomes circular in the screen shot (well, almost, but the distorsion comes from the perspective mapping in Irrlicht, not from the dome itself).
Then I found this scenery somewhere on the net
and you get this sky dome look
This last example is my favorite:
which gives a scene looking like this (notice how the banner at the bottom is not visible, see the explanation above).
and looking directly to the top
Notice that the panorama views above are all found somewhere on the net, and are only small versions of the original used here to illustrate the sky dome technique. Obviously, you should get the originals to get a proper resolution. A good place to start is
http://lfgrafix.com/grafix/3dSkyInMot/SIMdex.html
or google for 'panorama 360 sky' or similar.
Have fun with it.