Configuring the Sky for a Y-Up Application

For a complete overview of physical sky, sun and moon lights, please refer to the following tutorial: Outdoor Lighting.

By default, HOOPS Luminate physical sky model is built with the Z axis as up vector. This means that the sun and moon directions must be Z-up.

The first step is to convert the Y-up application sun and moon directions to Z-up.

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

// Matrix transforming Y-up to Z-up.
RED::Matrix y_up_to_z_up;
y_up_to_z_up.RotationAngleMatrix( RED::Vector3::ZERO, RED_PI2, 0.f, 0.f );

// sun_direction_y is a Y-up sun direction. Transform it to Z-up. Same for moon.
sun_direction_z = y_up_to_z_up.RotateNormalize( sun_direction_y );
moon_direction_z = y_up_to_z_up.RotateNormalize( moon_direction_y );

// Setup the sky model.
// This function only takes Z-up directions.
RC_TEST( isky->SetPhysicalModel( 1.0, view_height, 1.0, 3, 0.1, 0.8, 0.7,
                                sun_direction_z, 1.0, 1.0,
                                moon_direction_z, 1.0, 1.0,
                                1.0, 0.6, iresmgr->GetState() ) );

// Create and set the sky texture. The up vector is RED::Vector3::YAXIS.
RED::Object* sky_tex = NULL;
RC_TEST( isky->CreatePhysicalSkyTexture( sky_tex, false, 256, true, false, true, iresmgr->GetState() ) );
RC_TEST( isky->SetSkyTexture( sky_tex, true, RED::Vector3::XAXIS, RED::Vector3::YAXIS, iresmgr->GetState() ) );

// Setup the sun and moon lights.
// After calling these methods, sun and moon will be in Z-up.
RC_TEST( isky->SetSunLight( sun, iresmgr->GetState() ) );
RC_TEST( isky->SetMoonLight( moon, iresmgr->GetState() ) );

Please note that RED::ISkyLightShape::SetSkyTexture have the option to set the up direction. It has been set to RED::Vector3::YAXIS.

From now on, the sun and moon directions are Z-up. This will not fit with the Y-up application. We have to transform them back to Y-up. This is done in the scene graph using a RED::ITransformShape.

// Matrix transforming Z-up to Y-up.
RED::Matrix z_up_to_y_up;
z_up_to_y_up.RotationAngleMatrix( RED::Vector3::ZERO, -RED_PI2, 0.f, 0.f );

// Create a transform shape to handle the sun and moon.
RED::Object* transform = RED::Factory::CreateInstance( CID_REDTransformShape );
if( transform == NULL )
    RC_TEST( RED_ALLOC_FAILURE );

RED::ITransformShape* itransform = transform->As< RED::ITransformShape >();
RC_TEST( itransform->AddChild( sun, RED_SHP_DAG_NO_UPDATE, iresmgr->GetState() ) );
RC_TEST( itransform->AddChild( moon, RED_SHP_DAG_NO_UPDATE, iresmgr->GetState() ) );

// Set the correct matrix to bring back the Y-up data.
RC_TEST( itransform->SetMatrix( &z_up_to_y_up, iresmgr->GetState() ) );

// Add the shapes to the graph.
// iparent is the RED::ITransformShape parent of the sky, sun and moon.
RC_TEST( iparent->AddChild( sky, RED_SHP_DAG_NO_UPDATE, iresmgr->GetState() ) );
RC_TEST( iparent->AddChild( transform, RED_SHP_DAG_NO_UPDATE, iresmgr->GetState() ) );

Note

Sky should not be transformed! It is already Y-up!

One last thing to note: if the sky is used for a VRL background texture, the correct transform matrix must be set to the RED::IViewpointRenderList::SetBackgroundImages method. Once again the up direction is set to RED::Vector3::YAXIS.

// Get the background matrix from the sky and apply it when setting the background.
RED::Matrix bg_matrix;
RC_TEST( isky->GetBackgroundMatrixFromSky( bg_matrix, RED::Vector3::XAXIS, RED::Vector3::YAXIS ) );
RC_TEST( ivrl->SetBackgroundImages( bg_cube, bg_matrix, NULL, RED::Matrix::IDENTITY, true, 1.0, 1.0, iresmgr->GetState() ) );