3D Tutorial: Managing 3D Text

This step reviews how to work with text in a 3D scene, as well as how to enable full 3D transformed text. However, you should first review the 'Managing 2D Text' section of the 2D Tutorial. (If not the whole tutorial.)

 

Screen-Space Oriented 3D Text

The 2D tutorial reviewed how to insert basic 2D text. It was considered 2D text because the z values were set to zero. In a 3D scene, text will commonly need to be positioned such that it annotates a 3d object, thus it's z-values will need to be non-zero.

In most cases, it is desirable to only have the reference position of the text be transformed in 3D, and for the plane of the text string to remain parallel to the viewing plane so that the user can still easily read the text. This is referred to as 'screen space' text, and is the default behavior for text in HOOPS/3dGS. The way the text is transformed is controlled by the 'transforms' option of ::Text_Font, with the default being 'transforms = off'.

If you need to define a model that already contains annotation text, you would insert the text using ::Insert_Text, passing in the desired x, y, z values. Any additional annotation geometry (such as a connector arrow, border, etc...) would be represented via HOOPS/3dGS 'lines', 'polygons', etc... If you wish to dynamically let the user annotation objects that already exist in the view, you can the HOOPS/MVO annotation operator.

HOpMarkupAnnotate

This operator that let's you easily annotate an object, and also handles the connecting-arrow/border. After creating and making this the current operator, you click and drag, and a text box containing a default text string will be drawn. You can then select the text string and enter the text that you desire. (The text will be drawn in screen space.) Let's hook up this operator by adding a new GUI button that calls the following function:

void CSpheresView::OnAnnotate()
{
LocalSetOperator(new HOpMarkupAnnotate(m_pHView));
}

Create a sphere and test out the operator by selecting it on your GUI toolbar, and then clicking/dragging on the sphere, entering some text, and hitting <return>.

 

<4>Markup Colors

Let's change the colors used for the annotation text. HOpMarkupAnnotate creates the text using the HMarkupManager class, discussed in themarkup manager section of the HOOPS/MVO Programming Guide. While the HMarkupManager class provides methods for setting annotation text color, those methods only apply if the text was created as part of a markup 'layer' (it will set the text color in one of the 'layer' segments depicted in the MarkupManager's segment-hierarchy diagram). However, our sample application has not previously setup markup layers, so we'll just set the markup text color in the top level 'markup' segment. We access that segment by getting a pointer to the HMarkupManager object, and then accessing the 'markup' segment key. Let's make the color setting in HBaseView::Init():

HMarkupManager * mgr = GetMarkupManager();
HC_Open_Segment_By_Key(mgr->GetMarkupKey());
HC_Set_Color("text = green");
HC_Close_Segment();

Note that setting the color (or any other attributes) in the top level 'markup' segment would be a way to have annotations in all sub 'layers' get drawn with the same attributes, since the 'layer' segments will inherit their parent's attributes. However, there is a caveat to this that we'll touch on next.

The note actually has a light gray border (around the dark gray background), but it contrasts poorly against the while background. We could change the background color, but let's chagne the note's border instead. We can enhance the color setting in the code block above to include 'lines = red', for example. But nothing happens! This is becaue the 'note geometry' is in a sugsegment of the 'markup' segment, and has it's own explicit color setting. You may be aware that having an attribute override attributes in subsegments (to 'force' the attribute down the tree), is achieved by setting an attribute lock on that attribute using ::Set_Rendering_Options. Let's also change the note background to 'light blue' while we're at it:

HC_Open_Segment_By_Key(mgr->GetMarkupKey());
HC_Set_Color("text = green, lines = red, faces = light blue");
HC_Set_Rendering_Options("attribute lock = color");
HC_Close_Segment();

 

Markup Scaling

By default, the markup text doesn't scale as you zoom in and out, since it inherits the HBaseView defaults. Since you've already reviewed the 2D Tutorial, you should recall what text attribute to set so that it will scale:

void HSpheresView::Init()
{
.
.
HC_Open_Segment_By_Key(m_SceneKey);
HC_Set_Text_Font("size = .02 oru");
HC_Close_Segment();
.
.
}

 

Hiding Overlapped Text

Manually insert some text into the scene in HSpheresView::Init() For, example:

HC_Open_Segment_By_Key(m_SceneKey);
HC_Insert_Text(0.0, -0.1, 0.0, "text1");
HC_Insert_Text(0.0, 0.0, 0.0, "text2");
HC_Insert_Text(0.0, 0.1, 0.0, "text3");
HC_Close_Segment();

Run the app and create a new window. (You may have to zoom out a bit to see all the text, since only the text's insertion point is used by default when calculating the scene extents) Then, orbit the camera so that the text overlaps. (Remember that as you rotate, the reference positions of the text (which are 3d positions) get transformed in 3d space.) By default, all the text gets drawn. The default is of course to draw everything, unless it's visibility is turned off.

However, when there are complex 3D scenes which also contain large amounts of annotation text, drawing all of the text strings can make the scene quite messy and unreadable. HOOPS/MVO has a feature which let's you 'hide' overlapped text. Specificially, when this feature is enabled, any text which would be overlapped by other pieces of text will not get drawn. This is enabled by calling HBaseView::SetHideOverlappedText(true) Add this to HSpheresView::Init() and rerun the app. (Zoom out again to see all the text) Then, rotate the text so it would start to overlap, and see what happens.

This overlapped text feature currently does not apply to the annotation text reviewed above, but a future release of HOOPS/3dAF may have such support.

 

Fully Transformed 3D Text

As was reviewed in the 2D Tutorial, you can control whether text is fully 3D transformed by setting the transforms suboptions in ::Set_Text_Font. Setting transforms to off says that only the starting position of the text (as determined by the Text Alignment) is affected by the camera, the net modelling matrix, etc. After that, the text is drawn in the screen coordinate system, so it is always facing the screen. The annotation text discussed above is drawn with this setting.

Setting transforms to on tells the system that text should be subject to transformations just like regular geometry. In other words, a "transformable" font is subject to scaling, rotations, perspective transformations, etc. Let's make our sample text fully transformable:

HC_Open_Segment_By_Key(m_SceneKey);
HC_Set_Text_Font("size = .02 oru, transforms = on");
HC_Insert_Text(0.0, -0.1, 0.0, "text1");
HC_Insert_Text(0.0, 0.0, 0.0, "text2");
HC_Insert_Text(0.0, 0.1, 0.0, "text3");
HC_Close_Segment();

Rotate the camera and notice how the text is now fully transformed in 3D. Since the default HOOPS/3dGS font (sans serif) cannot be fully transformed, HOOPS/3dGS falls back to an internal 'stroked' font that consists of polylines. To see a more interesting font get transformed, let's choose 'arial.ttf'.

HC_Open_Segment_By_Key(m_SceneKey);
HC_Set_Text_Font("size = .02 oru, transforms = on, name = arial.ttf");
HC_Insert_Text(0.0, -0.1, 0.0, "text1");
HC_Insert_Text(0.0, 0.0, 0.0, "text2");
HC_Insert_Text(0.0, 0.1, 0.0, "text3");
HC_Close_Segment();

But there's one more thing you'll need to do for the arial font to show up. Recalling from the 2D Tutorial, we have to tell HOOPS/3dGS where to look for fonts. (Note: We're assuming that arial.ttf is available which is a pretty safe bet, but the right thing to do is to actually check the available fonts by performing a Begin_Font_Search, and choose from that list.)

BOOL CSpheresApp::InitInstance()
{
.
.
.
char fontDirectory[MAX_PATH+32];
::GetWindowsDirectory(fontDirectory, MAX_PATH);
strcat(fontDirectory, "\\Fonts");
char buf[MAX_PATH+64];
sprintf(buf, "font directory = %s", fontDirectory);
HC_Define_System_Options(buf);
.
.
.
}

Now try rotating the new font.

All of the text properties discussed above are reveiwed in Section 2.4 of the HOOPS/3dGS Programming Guide. The flylogo.c program is also a neat demo of 3D text capabilities that you should review.