Build Better Software. Faster.
Visit our company site at: www.techsoft3d.com
 

White Papers Index

Controlling Drawing Order of 3D Objects
Reuben

Overlaying Objects on a 3D Scene

Overview

Software developers using HOOPS often ask how to add legends to their 3D scene. 3D objects by themselves are very useful in conveying information, but it may be necessary to add additional information such as what a color may indicate. Adding a legend often makes the scene more useful. This article focuses on adding a legend to a HOOPS scene.

Creating a legend is similar to creating any other object in a HOOPS scene. The key difference is that the legend is independent of transforms applied to the rest of the scene and it is always on top. Creating a segment with this property is as simple as setting a depth range and an explicit local camera. The depth range is simple. In order to have the legend always appear on top, set a depth range of (0.0,0.1). This effectively rescales the z values of the object in the segment to the set range. Setting a local camera in the segment keeps the objects in the segment static on the screen. Normally transforms, just as any other attributes, are inherited by subsegments in a hierarchical manner. Setting a camera explicitly, however, overrides these inherited transforms. Ideally, we'd like to insert the geometry of our legend around the origin, but have the legend drawn off to the edge of the screen. Setting the position and target of the camera accomplishes just that. The simplest way to set this is to set the x and y values of the camera position and target to the xy point on the screen where the legend should be centered. The z values should, of course, be different and the projection should be orthographic. The following code shows this setup.

Example:
static void
Open_Legend(char * name, float x, float y)
{
     float position[3], target[3], up[3], width, height;
     char projection[64];
                       
     HC_Open_Segment(name);
                       
        HC_Set_Rendering_Options("depth range=(0.0, 0.1)");
        HC_Show_Net_Camera(position, target, up, &width, &height, projection);
        position[0] = target[0] = x;
        position[1] = target[1] = -y;
        HC_Set_Camera(position, target, up, width, height, "Orthographic");
}
static void
Close_Legend()
{
      HC_Close_Segment();
}
                      

Ensuring that edges/lines are drawn on top of their associated faces

Overview

Another common issue is edge stitching. Typically, in a graphics system, polygons can be drawn shaded, wireframe or both at the same time. When drawing shaded and wireframe faces at the same time, edge stitching becomes a problem. Stitching, also known as z-fighting, is when objects in the scene are coplanar. Coplanar objects share the same space in the z-buffer. The coplanar objects will stitch as they obscure each other. HOOPS provides a built-in solution to the edge stitching problem using a technique called face displacement. Face displacement offsets faces in the z-buffer so they are drawn behind edges. This displacement insures that a polygon’s face will never stitch with its own edges.

In HOOPS, the face displacement value can be queried with a call to:

HC_Show_One_Rendering_Option(“face displacement”, (char*) value).

HOOPS normalizes the face displacement value so that it will have the same effect regardless of the z-buffer depth and sets a default face displacement value of 8. Internal testing has shown that this value provides a good result assuming the camera is setup reasonably. A reasonable camera's target is near the center of the geometry in the scene and the camera's distance from the target is roughly two and a half times the field of view.

Example:

Assuming a camera target of (0,0,0):

-If the field width and height are 300, a position of (0,0,1000) should be used.
-If the field width and height are 15, a position of (0,0,50) should be used.
-If the field width and height are 4, then a position of (0,0,12000) would produce a camera with an extreme projection.

The following two cubes have camera values (0,0,50), 14.4 and (0,0,12000), 4 respectively.

Sample Program:

The following sample program is a standalone demo that shows how to create a legend. A screen shot of the output follows.

#include <hc.h>

#define countof(array) sizeof(array)/sizeof(array[0])

static float const shell_points[][3] = {
       {-0.33f,-0.33f,0.33f}, {0.33f,-0.33f,0.33f},
       {0.33f,0.33f,0.33f}, {-0.33f,0.33f,0.33f},
       {0.33f,-0.33f,-0.33f}, {-0.33f,-0.33f,-0.33f},
       {-0.33f,0.33f,-0.33f}, {0.33f,0.33f,-0.33f},
};

static int const shell_face_list[] = {
       4, 0,1,2,3, 4, 4,5,6,7,
       4, 1,4,7,2, 4, 5,0,3,6,
       4, 3,2,7,6, 4, 5,4,1,0,
};

static void Open_Legend(char * name, float x, float y);
static void Close_Legend(void);

int
main(int argc, char * argv[])
{
  HC_Open_Segment("?picture");{
    char color[64];

    HC_Set_Handedness("right");
    HC_Set_Visibility("everything=off, windows=on");
    HC_Set_Color("text=black");

    HC_Open_Segment("model");{
        HC_KEY key;
        int i;

        HC_Set_Visibility("faces=on, edges=on");
        key = HC_KInsert_Shell(countof(shell_points), shell_points,
                              countof(shell_face_list), shell_face_list);
        HC_Open_Geometry(key);{
        for(i=0; i<countof(shell_points); ++i){
        snprintf(color, sizeof(color), "r=%f g=%f b=%f", i/7.0, 1-i/7.0, 0.0);
               HC_Open_Vertex(i);{
                      HC_Set_Color(color);
               }HC_Close_Vertex();
        }
        }HC_Close_Geometry();
     }HC_Close_Segment();

     /* insert our legend at (1,0) */
     Open_Legend("legend", 1, 0);{
        float mesh_points[9][2][3], xfrac, yfrac;
        HC_KEY mesh_key;
        int row, col, i;

        HC_Set_Visibility("text=on, faces=on");
        HC_Set_Text_Font("name=stroked, size=0.035 oru");
        HC_Set_Text_Alignment("<");
        HC_Compute_Text_Extent(".","Ap", &xfrac, &yfrac);
        yfrac *= 1.50;

        /* Insert the text in out legend. */
        HC_Insert_Text(0,5*yfrac,0,"Legend");
        HC_Insert_Text(0,4*yfrac,0,"7.00e-01");
        HC_Insert_Text(0,3*yfrac,0,"6.00e-01");
        HC_Insert_Text(0,2*yfrac,0,"5.00e-01");
        HC_Insert_Text(0,1*yfrac,0,"4.00e-01");
        HC_Insert_Text(0,0*yfrac,0,"3.00e-01");
        HC_Insert_Text(0,-1*yfrac,0,"2.00e-01");
        HC_Insert_Text(0,-2*yfrac,0,"1.00e-01");
        HC_Insert_Text(0,-3*yfrac,0,"0.00e-01");

        /* Create and Insert out scale for the legend. */
        for(row = 0; row < 9; ++row){
             for(col = 0; col < 2; ++col){
                    mesh_points[row][col][0] = (col*0.1)+0.025;
                    mesh_points[row][col][1] = row * yfrac - (3.5 * yfrac);
                    mesh_points[row][col][2] = 0;
            }
        }
        mesh_key = HC_KInsert_Mesh(9, 2, mesh_points);

        /* Set the color on the scale */
        HC_Open_Geometry(mesh_key);{
        for(i=0; i<18; ++i){
        snprintf(color, sizeof(color),"r=%f g=%f b=%f",i/17.0,1-i/17.0,0.0);
                HC_Open_Vertex(i);{
                        HC_Set_Color(color);
                }HC_Close_Vertex();
        }
        }HC_Close_Geometry();

      }Close_Legend();
    }HC_Close_Segment();

    HC_Write_Metafile("?picture","legend","");

    HC_Pause();
    return 0;
}


static void
Open_Legend(char * name, float x, float y)
{
    float position[3], target[3], up[3], width, height;
    char projection[64];

    HC_Open_Segment(name);

    HC_Set_Rendering_Options("depth range=(0.0, 0.1)");
    HC_Show_Net_Camera(position, target, up, &width, &height, projection);
    position[0] = target[0] = x;
    position[1] = target[1] = -y;
    HC_Set_Camera(position, target, up, width, height, "Orthographic");
}

static void
Close_Legend()
{
    HC_Close_Segment();
}

 
 

 

 

 

 

©2004-06 Tech Soft 3D All Rights Reserved. Privacy | Legal