##################################################
Applying Polygon Offset to See Edges of a Geometry
##################################################


This tutorial covers two topics:

    * The edges building
    * The polygon offset option of the ``RED::StateShader``

We will create a simple scene with a cube and then build edges from it. Finally a polygon offset will be added in order to correctly see the edges over the geometry.

.. figure:: wf_ApplyingPolygonOffsetToSeeEdges01.jpg
    :align: center
    
    **The final cube with edges**

The creation of the cube is simply a call to the ``RED::IMeshShape::Box`` function. Its material is a generic one and is created with the ``RED::IMaterial::SetupGenericDiffuseMaterial`` function. Nothing new here...

**************
Building Edges
**************

The edges are in fact a ``RED::ILineShape`` built from the cube. It exists three way to create edges shapes in HOOPS Luminate:

    * The ``RED::IMeshShape::BuildEdges`` creates edges around all triangles of the shape
    * The ``RED::IMeshShape::BuildBorderEdges`` creates border edges; a border edge belongs to a single triangle in the mesh
    * The ``RED::IMeshShape::BuildContourEdges`` is like the first one but adds contour extraction data. They have to be rendered with a ``RED::RenderShaderEdges`` shader

.. code:: cpp

    // Create the edge shape from the cube:
    RED::Object* edge;
    edge = RED::Factory::CreateInstance( CID_REDLineShape );
    if( edge == NULL )
        return RED_ALLOC_FAILURE;

    RC_TEST( icube->BuildEdges( edge, RED::MCL_VERTEX, RED::MCL_VERTEX, state ) );

    // Add the edge shape to the scene:
    RC_TEST( icamera->AddShape( edge, state ) );


The ``RED::ILineShape`` created with the three methods can be rendered using a classical render shader like a ``RED::RenderShaderSolid``. Some line options can be changed using a ``RED::StateShader``: line width, line smoothing, line stipples.

.. code:: cpp

    // Create the edge material:
    // The edge material is composed of a simple solid shader in the RED::MTL_POSTLIT pass.
    // The blending is disabled as we want the edges to be drawn over the geometry.
    RED::Object* mat;
    RC_TEST( iresmgr->CreateMaterial( mat, state ) );
    RED::IMaterial* imat = mat->As< RED::IMaterial >();

    // State shader:
    RED::StateShader ssh;
    RC_TEST( ssh.SetBlendingMode( RED::StateShader::NO_BLENDING ) );

    RC_TEST( imat->RegisterShader( ssh, state ) );
    RC_TEST( imat->AddShaderToPass( ssh.GetID(), RED::MTL_POSTLIT, RED::LIST_LAST, RED::LayerSet::ALL_LAYERS, state ) );

    // Solid shader:
    RED::RenderShaderSolid solid( RED::MTL_POSTLIT,
                                RED::Color::WHITE, NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0,
                                RED::Color::WHITE, NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0,
                                resmgr, rc );
    RC_TEST( rc );

    RC_TEST( imat->RegisterShader( solid, state ) );
    RC_TEST( imat->AddShaderToPass( solid.GetID(), RED::MTL_POSTLIT, RED::LIST_LAST, RED::LayerSet::ALL_LAYERS, state ) );

    // Apply the material to the shape:
    RED::IShape* ishape = edge->As< RED::IShape >();
    RC_TEST( ishape->SetMaterial( mat, state ) );


The solid shader is added to the ``RED::MTL_POSTLIT`` rendering pass because we want our edges to be drawn last. The blending is also disabled in the state shader.

.. figure:: wf_ApplyingPolygonOffsetToSeeEdges02.jpg
    :align: center
    
    **The final cube with border edges**

*********************
Adding Polygon Offset
*********************

Unfortunately, simply adding edges shape is not sufficient to have nice edges over a geometry. Indeed both the cube and the edges are drawn at the same position; it could result on z-fighting, visual artefacts or edges not drawn completely.

One way to handle this could be to add a small depth offset when rendering the lines. The API provides functions to do this in the state shader:

    * ``RED::StateShader::SetPolygonOffset`` enables the polygon offsetting for all the following render shaders in the pipeline
    * ``RED::StateShader::SetPolygonOffsetValue`` sets the value of the offset

The polygon offsetting works only on meshes (``RED::IMeshShape``) and therefore can not be applied on our edges because they are in a line shape (``RED::ILineShape``). The solution is to offset all the scene geometry instead, i.e. the cube and the grid. A state shader is added at the beginning of each pass of the materials to handle the polygon offset:

.. code:: cpp

    // Add the polygon offset state shader at the beginning of each pass
    // of each material of the scene.
    RED::StateShader ssh;
    RC_TEST( ssh.SetPolygonOffset( true ) );
    RC_TEST( ssh.SetPolygonOffsetValue( 2.0f, 2.0f ) );

    // Add it to the grid material:
    RC_TEST( igridmat->RegisterShader( ssh, state ) );
    RC_TEST( igridmat->AddShaderToPass( ssh.GetID(), RED::MTL_PRELIT,  RED::LIST_FIRST, RED::LayerSet::ALL_LAYERS, state ) );
    RC_TEST( igridmat->AddShaderToPass( ssh.GetID(), RED::MTL_LIT,     RED::LIST_FIRST, RED::LayerSet::ALL_LAYERS, state ) );
    RC_TEST( igridmat->AddShaderToPass( ssh.GetID(), RED::MTL_POSTLIT, RED::LIST_FIRST, RED::LayerSet::ALL_LAYERS, state ) );

    // Make sure the grid is rendered before edges
    RC_TEST( igridmat->SetPriority( 0, state ) );

    // Add it to the cube material:
    RC_TEST( icubemat->RegisterShader( ssh, state ) );
    RC_TEST( icubemat->AddShaderToPass( ssh.GetID(), RED::MTL_PRELIT,  RED::LIST_FIRST, RED::LayerSet::ALL_LAYERS, state ) );
    RC_TEST( icubemat->AddShaderToPass( ssh.GetID(), RED::MTL_LIT,     RED::LIST_FIRST, RED::LayerSet::ALL_LAYERS, state ) );
    RC_TEST( icubemat->AddShaderToPass( ssh.GetID(), RED::MTL_POSTLIT, RED::LIST_FIRST, RED::LayerSet::ALL_LAYERS, state ) );

    // Make sure the cube is rendered before edges
    RC_TEST( icubemat->SetPriority( 1, state ) );


As you can see, the materials priority is changed to be sure that the edges material is rendered at last in the pipeline. The edges material kept the default priority: it is rendered last.

.. figure:: wf_ApplyingPolygonOffsetToSeeEdges03.jpg
    :align: center
    
    **The edges without polygon offset on the left and with polygon offset on the right**
