Building REDsdk materials

This book covers all the practicals aspects of material management in REDsdk. Materials are shapes attributes, as detailed by the Attributes of a shape page. A material defines the rendering look of a shape or of a tree of shapes below the node that owns the material, thanks to the material inheritance rules in REDsdk. Materials are shared among shapes: all shapes with the same rendering look should use the same material.

Terminology

A material defines the way a shape is rendered. A material is composed of shaders, that are organized in rendering passes. A shader is either dedicated to the rendering (a RED::RenderShader), or dedicated to configuring the rendering (a RED::StateShader).

A shader dedicated to the rendering is composed of programs executed on the graphics hardware or in software. Among these programs, we find the vertex program, the pixel program and the geometry program. These are also called vertex shaders, fragment shaders and geometry shaders in the literature.

A rendering pass consists in drawing the scene geometry once, for the purpose of a given effect.

Contents

This book contains two key parts:

And then we can review some other important topics in material management with REDsdk:

Using materials

REDsdk materials are created and destroyed by the cluster's resource manager. Materials are shared resources across all scene graphs defined in the application cluster. First, let's learn how to create or to destroy a given material. The task below illustrates the way to proceed:

task

Task: Creating and destroying materials

// First, get our resource manager and access its interface.
RED::Object* resmgr = RED::Factory::CreateInstance( CID_REDResourceManager );
RED::IResourceManager* iresmgr = resmgr->As< RED::IResourceManager >();

// Then, create a material from it:
RED::Object* material;
RC_TEST( iresmgr->CreateMaterial( material, iresmgr->GetState() ) );

// Release the material after use:
RC_TEST( iresmgr->DeleteMaterial( material, iresmgr->GetState() ) );

As you can see, material creation and destruction is simple using the RED::IResourceManager interface. However, attention must be paid to the fact that a material must not be used by any shape at the time it's destroyed. REDsdk does not invalidate possible references to the destroyed material that may exist in the calling application. This is the responsibility of the application to ensure that a material that is destroyed is no longer used by any shape being rendered. REDsdk will detect invalid materials used during a draw and will return a RED_SCG_DEAD_MATERIAL_ADDRESS error code if this happens.

It's also a common way to proceed to duplicate an existing material. For instance a material template is loaded from a .red file and duplicated to be modified later on by the application. In this case, the following task applies:

task

Task: Loading and duplicating a material

// Access our resource manager:
RED::Object* resmgr = RED::Factory::CreateInstance( CID_REDResourceManager );
RED::IResourceManager* iresmgr = resmgr->As< RED::IResourceManager >();

// Access the data manager:
RED::Object* datamgr = iresmgr->GetDataManager();
RED::IDataManager* idatamgr = datamgr->As< RED::IDataManager >();

// Load a material from a .red file:
RED::Object* redfile = RED::Factory::CreateInstance( CID_REDFile );
if( redfile == NULL )
  RC_TEST( RED_ALLOC_FAILURE );

RED::IREDFile* ifile = redfile->As< RED::IREDFile >();

RED::StreamingPolicy policy;
RED::FileHeader header;
RED::FileInfo finfo;
RED::Vector< unsigned int > contexts;

RC_TEST( ifile->Load( "MyMaterial.red", iresmgr->GetState(), policy, header, finfo, contexts ) );

// Get the first material (assuming there's one in the file!):
RED::Object* material;
if( contexts.size() != 0 )
{
  unsigned int mcount = 0;
  RC_TEST( idatamgr->GetMaterialsCount( mcount, contexts[0] ) );

  if( mcount > 0 )
  {
    RC_TEST( idatamgr->GetMaterial( material, contexts[0], 0 ) );
  }
}

// Now, duplicate the material, without duplicating large images:
RED::Object* material_copy;
RC_TEST( iresmgr->CloneMaterial( material_copy, material, iresmgr->GetState(), false, true ) );

We must pinpoint the two boolean options of RED::IResourceManager::CloneMaterial in this task: A material generally uses a lot of images. Among them, we find tiny 1x1 pixel images used by REDsdk shaders that perform texturing (for consistency, a built-in REDsdk shader generally uses either no texture to source its parameters, or all its parameters are turned into textures; therefore, we have many tiny 1x1 textures that may be used as replacement for colors if we're using texturing); and we have large images that are generally the source images used for the material.

The RED::IResourceManager::CloneMaterial method lets you clone or share all images in the material. This is important from both a memory management perspective and also for edition needs. If a cloned material shares all its images, then any change in the material parameter will probably modify an image that is shared by both materials. If a cloned material duplicates tiny images and share other images, then modifying a small image (generally a color that was set with no texture) will modify only the cloned material.