Background Clouds

This tutorial is about adding clouds to the background sky texture. Before starting, I suggest you to first read another tutorial about sky creation: Rendering Skies.

Sky Creation

Before adding clouds, we have to create the sky. Sky and clouds functions are all grouped in the RED::ISkyLightShape interface. The simplest way is to call the RED::ISkyLightShape::SetPhysicalModel function. More details about this function can be found in the tutorials and books about sky model.

// Create the sky light.
oSky = RED::Factory::CreateInstance( CID_REDLightShape );
if( g_sky == NULL )
RC_TEST( RED_ALLOC_FAILURE );

RED::ISkyLightShape* isky = oSky->As< RED::ISkyLightShape >();

// Set parameters to the sky model.
RC_TEST( isky->SetPhysicalModel( 1.0, g_height, 1.0, g_turbidity, g_albedo, g_aerosols_albedo, g_asymmtery_factor,
                                g_sun_direction, g_sun_radius_scale, g_sun_mult,
                                moon_dir, g_moon_radius_scale, g_moon_mult,
                                g_stars_mult, g_saturation, iresmgr->GetState() ) );

Adding the Clouds

Adding clouds is really simple: just call the RED::ISkyLightShape::AddClouds function. This function adds one layer of clouds to the sky. You can call it several time to add as many layer as you need in your scene.

// Add clouds layers to the sky model.
RC_TEST( isky->AddClouds( g_cumulus_cloud_layer, g_cumulus_altitude, g_cumulus_density, g_cumulus_intensity, g_cumulus_opacity,
                        RED::CT_CUMULUS, 18081986, iresmgr->GetState() ) );

RC_TEST( isky->AddClouds( g_stratus_cloud_layer, g_stratus_altitude, g_stratus_density, g_stratus_intensity, g_stratus_opacity,
                        RED::CT_STRATUS, 18081986, iresmgr->GetState() ) );

// No need to set the altitude and density of the cirrus layer: it is simply a texture so always on top.
RC_TEST( isky->AddClouds( g_cirrus_cloud_layer, 0.0, 0.0, g_cirrus_intensity, g_cirrus_opacity,
                        RED::CT_CIRRUS_3, 18081986, iresmgr->GetState() ) );

In the tutorial, we created a layer for each type of clouds provided by the API:

  • Cumulus for big puffy clouds

  • Stratus for flat uniform clouds

  • Cirrus for high altitude clouds

HOOPS Luminate allows to define several parameters for each layer like altitude, density, opacity or lighting intensity. The tutorial application lets you play dynamically with them.

../../../_images/wf_BackgroundClouds01.jpg

Different kind of clouds: cirrus, stratus, cumulus and all three cumulated

Composite or Regular Texture?

Once the sky and clouds are created, we need to create the background texture that will show them. This is done with the RED::ISkyLightShape::CreatePhysicalSkyTexture function.

We have two choices here: create a regular texture or a composite texture.

A regular texture has fixed size and is computed right when we call the function. It can be saved and reloaded and is suitable for real-time rendering. The negative point is that the background texture must be sampled reducing its overall rendering quality unless it has a very big resolution. See the following example for regular background texture:

// Create the sky texture to apply to the background.
// Not a composite texture: it is computed here.
RED::Object* bg_tex = NULL;
RC_TEST( isky->CreatePhysicalSkyTexture( bg_tex, false, 1024, false, true, iresmgr->GetState() ) );

// Retrieve info about the texture.
RED::IImage2D* iback = bg_tex->As< RED::IImage2D >();
RC_TEST( iback->GetPixels() );
RED::FORMAT pix_format = iback->GetLocalFormat();
int pix_width, pix_height;
iback->GetLocalSize( pix_width, pix_height );
unsigned char* pixels = iback->GetLocalPixels();

// Create a cube map from the texture
RED::Object* bg_cube = NULL;
RC_TEST( iresmgr->CreateImageCube( bg_cube, iresmgr->GetState() ) );

RED::IImageCube* ibg_cube = bg_cube->As< RED::IImageCube >();
RC_TEST( ibg_cube->CreateEnvironmentMap( RED::FMT_FLOAT_RGB, RED::ENV_SPHERICAL,
                                        512, pixels, pix_width, pix_height, pix_format,
                                        RED::WM_CLAMP_TO_BORDER, RED::WM_CLAMP_TO_BORDER, RED::Color::BLACK,
                                        RED::Matrix::IDENTITY, RED::Matrix::IDENTITY, iresmgr->GetState() ) );

// Setup the background image.
RED::Object* vrl;
RC_TEST( iwindow->GetDefaultVRL( vrl ) );
RED::IViewpointRenderList* ivrl = vrl->As< RED::IViewpointRenderList >();
RC_TEST( ivrl->SetBackgroundImages( bg_cube, RED::Matrix::IDENTITY, NULL, RED::Matrix::IDENTITY, true, 1.0, 1.0, iresmgr->GetState() ) );

With a composite texture on the other hand, the sky and clouds are not computed immediately but at the rendering time. This allows to have a perfect texture because no sampling is done. This is the preferred method for cpu rendering.

// Create a composite sky texture to apply to the background.
// It will be computed dynamically at rendering time.
RED::Object* bg_tex = NULL;
RC_TEST( isky->CreatePhysicalSkyTexture( bg_tex, true, 0, false, true, true, iresmgr->GetState() ) );

// Setup the background image.
RED::Object* vrl;
RC_TEST( iwindow->GetDefaultVRL( vrl ) );
RED::IViewpointRenderList* ivrl = vrl->As< RED::IViewpointRenderList >();
RC_TEST( ivrl->SetBackgroundImages( NULL, RED::Matrix::IDENTITY, bg_tex, RED::Matrix::IDENTITY, true, 1.0, 1.0, iresmgr->GetState() ) );

Updating the Clouds Parameters

To modify the clouds, there are two solutions: either we want to change the density of the layers. In this case we must delete the clouds and recreate new ones by calling RED::ISkyLightShape::ClearClouds. Or we only want to change other layer parameters and we can call RED::ISkyLightShape::UpdateClouds.

// If the cloud layers do not need to be recomputed, just update the parameters.
RC_TEST( isky->UpdateClouds( g_cumulus_cloud_layer, g_cumulus_altitude, g_cumulus_intensity, g_cumulus_opacity, iresmgr->GetState() ) );
RC_TEST( isky->UpdateClouds( g_stratus_cloud_layer, g_stratus_altitude, g_stratus_intensity, g_stratus_opacity, iresmgr->GetState() ) );
RC_TEST( isky->UpdateClouds( g_cirrus_cloud_layer, 0.0, g_cirrus_intensity, g_cirrus_opacity, iresmgr->GetState() ) );

This last function allows to update the parameters without having to recompute the whole clouds shape. It is faster than rebuilding everything from scratch and does not modify the clouds shape, only its appearance.