6.2. Three-Dimensional Text

In contrast to 2D text, 3D text scales in size according to changes in distance from the camera and does not always stay parallel to the screen. Three-dimensional text has depth. The face of a 3D letter can join its sides at right angles (the default). Or you can bevel the edges of the letter by specifying your own text profile, as shown at the right of Figure 6.3, “ Defining a Customized Profile for 3D Text, which shows a beveled letter A.

The chief advantages of 2D text are that it is faster than 3D text and, because it remains parallel to the screen, is always readable. Advantages of 3D text are that it can be scaled and is generally prettier than 2D text.

Defining a Customized Profile for 3D Text

Figure 6.3.  Defining a Customized Profile for 3D Text


SoText3( C++ | Java | .NET ) has the following fields:

string (SoMFString)

the text string or strings to display. You can specify multiple strings.

spacing (SoSFFloat)

the spacing between lines of text. The default interval is 1.0. For a multiple-string field, the vertical distance from the top of one line to the top of the next line is equal to spacing times the font size.

justification (SoSFEnum)

alignment of the text strings relative to the text origin. Justification can be LEFT (the default), RIGHT, or CENTER. LEFT means that the bottom-left front of the first character in the first line is at (0.0, 0.0, 0.0). Successive lines start under the first character. RIGHT means that the bottom-right of the last character is at (0.0, 0.0, 0.0). Successive lines end under the last character of the first line. CENTER means that the center of each line is at (0.0, 0.0, 0.0).

parts (SoSFBitMask)

visible parts of the text (FRONT, SIDES, BACK, or ALL). The default is FRONT.

Three-dimensional text has three parts: front, sides, and back. Text uses the current material. If material binding is specified as PER_PART, the front uses the first material, the sides use the second material, and the back uses the third material.

[Tip]

Tip: Be aware that when you turn on SIDES and BACK of 3D text, you draw three times more polygons than with FRONT only, so performance is slower.

The profile describes the cross-section of the letter, as shown in Figure 6.3, “ Defining a Customized Profile for 3D Text. The profile is drawn in its own 2D plane. This plane is perpendicular to the face of the text, as shown in Figure 6.4, “ 2D Plane for Drawing a Text Profile. The origin of this plane is at the edge of the letter. In this coordinate system, capital letters are one unit high. The profile coordinates thus need to be in the range of 0.0 to about 0.3 or 0.4 times the size of the font.


Profiles are constructed from the current profile coordinates. If the profile is a collection of connected straight-line segments, use the SoLinearProfile( C++ | Java | .NET ) node to specify how the coordinates are connected. The profile coordinates are specified in an SoProfileCoordinate2( C++ | Java | .NET ) node, which precedes the SoLinearProfile( C++ | Java | .NET ) node in the scene graph (see Example 6.3, “ Creating Beveled 3D Text).

If the profile is curved, use the SoNurbsProfile( C++ | Java | .NET ) node to specify how the coordinates are used. If you are interested in creating curved profiles, first read Chapter 20, Curves and Surfaces for detailed conceptual information on NURBS curves. The coordinates themselves are specified in the SoProfileCoordinate2( C++ | Java | .NET ) node or the SoProfileCoordinate3( C++ | Java | .NET ) node, depending on whether the curve is nonrational or rational. (The terms nonrational and rational are also explained in Chapter 20, Curves and Surfaces.)

If your text profile is a combination of linear and curved lines, you can join the linear profile to the curved profile. The base profile class, SoProfile( C++ | Java | .NET ), includes a linkage field that is inherited by both SoLinearProfile( C++ | Java | .NET ) and SoNurbsProfile( C++ | Java | .NET ). This field indicates whether the profile is START_FIRST (begin the first profile for the text), START_NEW (begin a new profile; for NURBS trimming only), or ADD_TO_CURRENT (append this profile to the previous one).

Example 6.2, “ Using 3D Text illustrates a simple use of 3D text. It renders a globe and then uses 3D text to label the continents Africa and Asia. The SoFont( C++ | Java | .NET ) node specifies Times Roman as the current font. Figure 6.5, “ Scene Graph for Simple 3D Text Example shows the scene graph for this example. Figure 6.6, “ Simple 3D Text Example” shows the image produced by this program.



Example 6.2.  Using 3D Text


C++
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/nodes/SoFont.h>
#include <Inventor/nodes/SoGroup.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoMaterialBinding.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoText3.h>
#include <Inventor/nodes/SoTexture2.h>
#include <Inventor/nodes/SoTransform.h>


main(int, char **argv)
{
   Widget myWindow = SoXt::init(argv[0]);
   if(myWindow == NULL) exit(1);

   SoGroup *root = new SoGroup;
   root->ref();
   
   // Choose a font.
   SoFont *myFont = new SoFont;
   myFont->name.setValue("Times-Roman");
   myFont->size.setValue(.2);
   root->addChild(myFont);

   // We'll color the front of the text white, and the sides 
   // dark grey. So use a materialBinding of PER_PART and
   // two diffuseColor values in the material node.
   SoMaterial        *myMaterial = new SoMaterial;
   SoMaterialBinding *myBinding = new SoMaterialBinding;
   myMaterial->diffuseColor.set1Value(0,SbColor(1,1,1));
   myMaterial->diffuseColor.set1Value(1,SbColor(.1,.1,.1));
   myBinding->value = SoMaterialBinding::PER_PART;
   root->addChild(myMaterial);
   root->addChild(myBinding);

   // Create the globe.
   SoSeparator *sphereSep = new SoSeparator;
   SoTexture2  *myTexture2 = new SoTexture2;
   root->addChild(sphereSep);
   sphereSep->addChild(myTexture2);
   sphereSep->addChild(new SoSphere);
   myTexture2->filename = "globe.rgb";
   // Add Text3 for AFRICA, transformed to proper location.
   SoSeparator *africaSep = new SoSeparator;
   SoTransform *africaTransform = new SoTransform;
   SoText3 *africaText = new SoText3;
   africaTransform->rotation.setValue(SbVec3f(0,1,0),.4);
   africaTransform->translation.setValue(.25,.0,1.25);
   africaText->parts = SoText3::ALL;
   africaText->string = "AFRICA";
   root->addChild(africaSep);
   africaSep->addChild(africaTransform);
   africaSep->addChild(africaText);

   // Add Text3 for ASIA, transformed to proper location.
   SoSeparator *asiaSep = new SoSeparator;
   SoTransform *asiaTransform = new SoTransform;
   SoText3 *asiaText = new SoText3;
   asiaTransform->rotation.setValue(SbVec3f(0,1,0),1.5);
   asiaTransform->translation.setValue(.8,.6,.5);
   asiaText->parts = SoText3::ALL;
   asiaText->string = "ASIA";
   root->addChild(asiaSep);
   asiaSep->addChild(asiaTransform);
   asiaSep->addChild(asiaText);

   SoXtExaminerViewer *myViewer = 
            new SoXtExaminerViewer(myWindow);
   myViewer->setSceneGraph(root);
   myViewer->setTitle("3D Text");
   myViewer->setBackgroundColor(SbColor(0.35, 0.35, 0.35));
   myViewer->show();
   myViewer->viewAll();
   
   SoXt::show(myWindow);
   SoXt::mainLoop();
}
                       

.NET
using OIV.Inventor.Nodes;
using OIV.Inventor.Win;
using OIV.Inventor.Win.Viewers;
using OIV.Inventor;

namespace _06_2_Simple3DText
{
    public partial class MainForm : Form
    {
        SoWinExaminerViewer myViewer;

        public MainForm()
        {
            InitializeComponent();
            CreateSample();
        }

        String LOCALFONTNAME = "Times New Roman;Regular";

        public void CreateSample()
        {
            SoGroup root = new SoGroup();

            // Choose a font
            SoFont myFont = new SoFont();

            myFont.name.SetValue(LOCALFONTNAME);
            myFont.size.SetValue(0.2f);
            root.AddChild(myFont);

            // We'll color the front of the text white, and the sides 
            // dark grey. So use a materialBinding of PER_PART and
            // two diffuseColor values in the material node.
            SoMaterial myMaterial = new SoMaterial();
            SoMaterialBinding myBinding = new SoMaterialBinding();
            myMaterial.diffuseColor.Set1Value(0, new SbColor(1.0F, 1.0F, 1.0F));
            myMaterial.diffuseColor.Set1Value(1, new SbColor(0.1F, 0.1F, 0.1F));
            myMaterial.diffuseColor.Set1Value(2, new SbColor(1.0F, 1.0F, 1.0F));
            myBinding.value.SetValue((int)SoMaterialBinding.Bindings.PER_PART);
            root.AddChild(myMaterial);
            root.AddChild(myBinding);

            // Create the globe
            SoSeparator sphereSep = new SoSeparator();
            SoTexture2 myTexture2 = new SoTexture2();
            SoComplexity sphereComplexity = new SoComplexity();
            sphereComplexity.value.SetValue(0.55F);
            root.AddChild(sphereSep);
            sphereSep.AddChild(myTexture2);
            sphereSep.AddChild(sphereComplexity);
            sphereSep.AddChild(new SoSphere());
            myTexture2.filename.SetValue("../../../../../data/globe.png");

            // Add Text3 for AFRICA, transformed to proper location.
            SoSeparator africaSep = new SoSeparator();
            SoTransform africaTransform = new SoTransform();
            SoText3 africaText = new SoText3();
            africaTransform.rotation.SetValue(new SbVec3f(0, 1, 0), 0.4F);
            africaTransform.translation.SetValue(0.25F, 0.0F, 1.25F);
            africaText.parts.SetValue((int)SoText3.PartType.ALL);
            africaText.stringField.SetValue("AFRICA");
            root.AddChild(africaSep);
            africaSep.AddChild(africaTransform);
            africaSep.AddChild(africaText);

            // Add Text3 for ASIA, transformed to proper location.
            SoSeparator asiaSep = new SoSeparator();
            SoTransform asiaTransform = new SoTransform();
            SoText3 asiaText = new SoText3();
            asiaTransform.rotation.SetValue(new SbVec3f(0.0F, 1.0F, 0.0F), 1.5F);
            asiaTransform.translation.SetValue(0.8F, 0.6F, 0.5F);
            asiaText.parts.SetValue((int)SoText3.PartType.ALL);
            asiaText.stringField.SetValue("ASIA");
            root.AddChild(asiaSep);
            asiaSep.AddChild(asiaTransform);
            asiaSep.AddChild(asiaText);

            myViewer = new SoWinExaminerViewer(this, "", true,
                SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER);
            myViewer.SetSceneGraph(root);
            myViewer.SetTitle("3D Text");

            // In Inventor 2.1, if the machine does not have hardware texture
            // mapping, we must override the default drawStyle to display textures.
            myViewer.SetDrawStyle(SoWinViewer.DrawTypes.STILL,
                           SoWinViewer.DrawStyles.VIEW_AS_IS);
            myViewer.ViewAll();
        }
    }
}
                     

Java
import tools.*;

import java.awt.*;
import java.net.*;

import com.openinventor.inventor.*;
import com.openinventor.inventor.awt.*;
import com.openinventor.inventor.nodes.*;

public class Main extends DemoInventor
{
  private Panel panel;

  public static void main(String[] args)
  {
    Main applet = new Main();
    applet.isAnApplet = false;
    applet.start();
    demoMain(applet, "Simple 3D Text");
  }

  public void start()
  {
    super.start();

    // Choose a font
    SoFont myFont = new SoFont();
    myFont.name.setValue("Times-Roman");
    myFont.size.setValue(.2F);

    // We'll color the front of the text white, and the sides
    // dark grey. So use a materialBinding of PER_PART and
    // two diffuseColor values in the material node.
    SoMaterial myMaterial = new SoMaterial();
    SoMaterialBinding myBinding = new SoMaterialBinding();
    myMaterial.diffuseColor.set1Value(0, new SbColor(1, 1, 1));
    myMaterial.diffuseColor.set1Value(1, new SbColor(.1F, .1F, .1F));
    myBinding.value.setValue(SoMaterialBinding.Bindings.PER_PART);

    // Add the globe, a sphere with a texture map.
    // Put it within a separator.
    SoSeparator sphereSep = new SoSeparator();
    SoTexture2 myTexture2 = new SoTexture2();
    SoComplexity sphereComplexity = new SoComplexity();
    sphereComplexity.value.setValue(0.55F);
    {
      sphereSep.addChild(myTexture2);
      sphereSep.addChild(sphereComplexity);
      sphereSep.addChild(new SoSphere());
    }

    URL url_texture = getURL("../../../../data/textures/rgb/globe.rgb");
    if (url_texture == null)
      return;
    myTexture2.filename.setValue(url_texture.getFile());

    // Add Text3 for AFRICA, transformed to proper location.
    SoSeparator africaSep = new SoSeparator();
    SoTransform africaTransform = new SoTransform();
    SoText3 africaText = new SoText3();
    africaTransform.rotation.setValue(new SbVec3f(0.0F, 1.0F, 0.0F), .4F);
    africaTransform.translation.setValue(.25F, 0F, 1.25F);
    africaText.parts.setValue(SoText3.PartType.ALL);
    africaText.string.setValue("AFRICA");
    {
      africaSep.addChild(africaTransform);
      africaSep.addChild(africaText);
    }

    // Add Text3 for ASIA, transformed to proper location.
    SoSeparator asiaSep = new SoSeparator();
    SoTransform asiaTransform = new SoTransform();
    SoText3 asiaText = new SoText3();
    asiaTransform.rotation.setValue(new SbVec3f(0.0F, 1.0F, 0.0F), 1.5F);
    asiaTransform.translation.setValue(.8F, .6F, .5F);
    asiaText.parts.setValue(SoText3.PartType.ALL);
    asiaText.string.setValue("ASIA");
    {
      asiaSep.addChild(asiaTransform);
      asiaSep.addChild(asiaText);
    }

    SoGroup root = new SoGroup();
    { // assemble scene graph
      root.addChild(myFont);
      root.addChild(myMaterial);
      root.addChild(myBinding);
      root.addChild(sphereSep);
      root.addChild(africaSep);
      root.addChild(asiaSep);
    }

    SwSimpleViewer myViewer = new SwSimpleViewer(SwSimpleViewer.EXAMINER);
    myViewer.setSceneGraph(root);
    myViewer.setName("3D Text");

    // In Inventor 2.1, if the machine does not have hardware texture
    // mapping, we must override the default drawStyle to display textures.
    myViewer.getArea().setDrawStyle(SwScene.STILL,
                                    com.openinventor.util.Scene.DrawStyle.VIEW_AS_IS);
    myViewer.viewAll();

    setLayout(new BorderLayout());
    panel = new Panel(new BorderLayout());

    panel.add(myViewer);
    add(panel);
  }

  public void stop()
  {
    remove(panel);
    panel = null;
    super.stop();
  }
}
                     

Example 6.3, “ Creating Beveled 3D Text illustrates additional features available with 3D text. It specifies a beveled cross-section for the text using the SoProfile-Coordinate2 and SoLinearProfile( C++ | Java | .NET ) nodes. The text uses two different materials— one for the front of the text, and one for the back and sides. The font node specifies the Times Roman font. Figure 6.7, “ Scene Graph for Advanced 3D Text Example shows the scene graph for this figure. Figure 6.8, “ Advanced 3D Text Example” shows the rendered image.



Example 6.3.  Creating Beveled 3D Text


C++
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/nodes/SoFont.h>
#include <Inventor/nodes/SoGroup.h>
#include <Inventor/nodes/SoLinearProfile.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoMaterialBinding.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Inventor/nodes/SoProfileCoordinate2.h>
#include <Inventor/nodes/SoText3.h>

main(int argc, char **argv)
{

   Widget myWindow = SoXt::init(argv[0]);
   if(myWindow == NULL) exit(1);

   SoGroup *root = new SoGroup;
   root->ref();

   // Set up camera. 
   SoPerspectiveCamera	*myCamera = new SoPerspectiveCamera;
   myCamera->position.setValue(0, -(argc - 1) / 2, 10);
   myCamera->nearDistance.setValue(5.0);
   myCamera->farDistance.setValue(15.0);
   root->addChild(myCamera);

   // Let's make the front of the text white, 
   // and the sides and back yellow.
   SoMaterial *myMaterial = new SoMaterial;
   SbColor colors[3];
   // diffuse
   colors[0].setValue(1, 1, 1);
   colors[1].setValue(1, 1, 0);
   colors[2].setValue(1, 1, 0);
   myMaterial->diffuseColor.setValues(0, 3, colors);
   // specular
   colors[0].setValue(1, 1, 1);
   colors[1].setValue(1, 1, 0);
   colors[2].setValue(1, 1, 0);
   myMaterial->specularColor.setValues(0, 3, colors);
   myMaterial->shininess.setValue(.1);
   root->addChild(myMaterial);

   // Choose a font.
   SoFont *myFont = new SoFont;
   myFont->name.setValue("Times-Roman");
   root->addChild(myFont);

   // Specify a beveled cross-section for the text.
   SoProfileCoordinate2 *myProfileCoords = 
            new SoProfileCoordinate2;
   SbVec2f coords[4];
   coords[0].setValue(.00, .00);
   coords[1].setValue(.25, .25);
   coords[2].setValue(1.25, .25);
   coords[3].setValue(1.50, .00);
   myProfileCoords->point.setValues(0, 4, coords);
   root->addChild(myProfileCoords);

   SoLinearProfile *myLinearProfile = new SoLinearProfile;
   long	   index[4] ;
   index[0] = 0;
   index[1] = 1;
   index[2] = 2;
   index[3] = 3;
   myLinearProfile->index.setValues(0, 4, index);
   root->addChild(myLinearProfile);

   // Set the material binding to PER_PART.
   SoMaterialBinding *myMaterialBinding = new SoMaterialBinding;
   myMaterialBinding->
            value.setValue(SoMaterialBinding::PER_PART);
   root->addChild(myMaterialBinding);

   // Add the text.
   SoText3 *myText3 = new SoText3;
   myText3->string.setValue("Beveled Text");
   myText3->justification.setValue(SoText3::CENTER);
   myText3->parts.setValue(SoText3::ALL);
   root->addChild(myText3);

   SoXtExaminerViewer *myViewer = 
            new SoXtExaminerViewer(myWindow);
   myViewer->setSceneGraph(root);
   myViewer->setTitle("Complex 3D Text");
   myViewer->show();
   myViewer->viewAll();
   
   SoXt::show(myWindow);
   SoXt::mainLoop();
}
                  

.NET
  using OIV.Inventor.Nodes;
using OIV.Inventor.Win;
using OIV.Inventor.Win.Viewers;
using OIV.Inventor;

namespace _06_3_Complex3DText
{
    public partial class MainForm : Form
    {
        SoWinExaminerViewer myViewer;

        public MainForm()
        {
            InitializeComponent();
            CreateSample();
        }

        String LOCALFONTNAME = "Times New Roman;Regular";

        public void CreateSample()
        {
            SoGroup root = new SoGroup();

            // Set up camera 
            SoPerspectiveCamera myCamera = new SoPerspectiveCamera();
            myCamera.position.SetValue(0, -3 / 2, 10);
            myCamera.nearDistance.SetValue(5.0f);
            myCamera.farDistance.SetValue(15.0f);
            root.AddChild(myCamera);

            // Let's make the front of the text white, 
            // and the sides and back shiny yellow
            SoMaterial myMaterial = new SoMaterial();
            SbColor[] colors = new SbColor[3];
            // diffuse
            colors[0].SetRGBValue(1, 1, 1);
            colors[1].SetRGBValue(1, 1, 0);
            colors[2].SetRGBValue(1, 1, 0);
            myMaterial.diffuseColor.SetValues(0, colors);

            // specular
            colors[0].SetRGBValue(1, 1, 1);
            // Note: Inventor 2.1 doesn't support multiple specular colors.
            /* 
            colors[1].SetValue(1, 1, 0);
            colors[2].SetValue(1, 1, 0);
            myMaterial.specularColor.setValues(0, 3, colors);
            */
            myMaterial.specularColor.SetValue(colors[0]);
            myMaterial.shininess.SetValue(0.1f);
            root.AddChild(myMaterial);

            // Choose a font likely to exist.
            SoFont myFont = new SoFont();
            myFont.name.SetValue(LOCALFONTNAME);

            root.AddChild(myFont);

            // Specify a beveled cross-section for the text
            SoProfileCoordinate2 myProfileCoords =
              new SoProfileCoordinate2();
            SbVec2f[] coords = new SbVec2f[4];
            coords[0].SetValue(0.00f, 0.00f);
            coords[1].SetValue(0.25f, 0.25f);
            coords[2].SetValue(1.25f, 0.25f);
            coords[3].SetValue(1.50f, 0.00f);
            myProfileCoords.point.SetValues(0, coords);
            root.AddChild(myProfileCoords);

            SoLinearProfile myLinearProfile = new SoLinearProfile();
            Int32[] index = new Int32[4];
            index[0] = 0;
            index[1] = 1;
            index[2] = 2;
            index[3] = 3;
            myLinearProfile.index.SetValues(0, index);
            root.AddChild(myLinearProfile);

            // Set the material binding to PER_PART
            SoMaterialBinding myMaterialBinding = new SoMaterialBinding();
            myMaterialBinding.
              value.SetValue((int)SoMaterialBinding.Bindings.PER_PART);
            root.AddChild(myMaterialBinding);

            // Add the text
            SoText3 myText3 = new SoText3();
            myText3.stringField.SetValue("Beveled Text");
            myText3.justification.SetValue((int)SoText3.Justifications.CENTER);
            myText3.parts.SetValue((int)SoText3.PartType.ALL);

            root.AddChild(myText3);

            myViewer = new SoWinExaminerViewer(this, "", true,
                SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER);
            myViewer.SetSceneGraph(root);
            myViewer.SetTitle("Complex 3D Text");

            myViewer.ViewAll();
        }
    }
}
                

Java
import tools.*;

import com.openinventor.inventor.nodes.*;
import com.openinventor.inventor.*;
import com.openinventor.inventor.awt.*;

import java.awt.*;

public class Main extends DemoInventor
{

  public static void main(String[] args)
  {
    Main applet = new Main();
    applet.isAnApplet = false;
    applet.start();
    demoMain(applet, "Complex 3D Text");
  }

  public void start()
  {
    super.start();

    // Set up camera
    SoPerspectiveCamera myCamera = new SoPerspectiveCamera();
    myCamera.nearDistance.setValue(5.0f);
    myCamera.farDistance.setValue(15.0f);

    // Let's make the front of the text white,
    // and the sides and back shiny yellow
    SoMaterial myMaterial = new SoMaterial();
    // diffuse
    SbColor[] colors =
    {
      new SbColor(1, 1, 1),
      new SbColor(1, 1, 0),
      new SbColor(1, 1, 0)
    };
    myMaterial.diffuseColor.setValues(0, colors);

    // specular
    myMaterial.specularColor.setValue(colors[0]);

    myMaterial.shininess.setValue(0.1f);

    // Choose a font likely to exist.
    SoFont myFont = new SoFont();

    // Specify a beveled cross-section for the text
    SoProfileCoordinate2 myProfileCoords = new SoProfileCoordinate2();
    SbVec2f[] coords = { new SbVec2f(0.00f, 0.00f), new SbVec2f(0.25f, 0.25f),
                         new SbVec2f(1.25f, 0.25f), new SbVec2f(1.50f, 0.00f) };
    myProfileCoords.point.setValues(0, coords);

    SoLinearProfile myLinearProfile = new SoLinearProfile();
    int[] index = { 0, 1, 2, 3 };
    myLinearProfile.index.setValues(0, index);

    // Set the material binding to PER_PART
    SoMaterialBinding myMaterialBinding = new SoMaterialBinding();
    myMaterialBinding.value.setValue(SoMaterialBinding.Bindings.PER_PART);

    // Add the text
    SoText3 myText3 = new SoText3();
    myText3.string.setValue("Beveled Text");
    myText3.justification.setValue(SoText3.Justifications.CENTER);
    myText3.parts.setValue(SoText3.PartType.ALL);

    SoGroup root = new SoGroup();
    { // Assemble scene graph
      root.addChild(myCamera);
      root.addChild(myMaterial);
      root.addChild(myFont);
      root.addChild(myProfileCoords);
      root.addChild(myLinearProfile);
      root.addChild(myMaterialBinding);
      root.addChild(myText3);
    }

    SwSimpleViewer myViewer = new SwSimpleViewer();
    myViewer.setSceneGraph(root);
    myViewer.setName("Complex 3D Text");
    myViewer.viewAll();

    setLayout(new BorderLayout());
    add(myViewer, BorderLayout.CENTER);
  }
}
                

Figure 6.9. Annotation text shape node class


The text node SoAnnoText3( C++ | Java | .NET )combines the features of SoText3( C++ | Java | .NET )and SoText2( C++ | Java | .NET ) . It has exactly the same fields as the node SoText2( C++ | Java | .NET )string, spacing, and justification – and the interpretation of these fields is the same as for SoText2( C++ | Java | .NET ). SoAnnoText3( C++ | Java | .NET ) cannot have a profile.

The fields of the SoAnnoText3Property( C++ | Java | .NET )node specify the behavior of SoAnnoText3( C++ | Java | .NET ) , including how it will be printed when using HardCopy:

renderPrintType (SoSFEnum)

isCharOrientedRasterPrint (SoSFBool)

Specifies whether the text should be oriented or not (“oriented” means not horizontal) for HardCopy printing. The orientation is a rotation in the plane of the printed page. This flag is used only for raster printing

( SoAnnoText3Property::RENDER3D_PRINT_RASTER

or SoAnnoText3Property::RENDER2D_PRINT_RASTER)

fontSizeHint (SoSFEnum)

This flag is used when the field renderPrintType is RENDER3D_PRINT_RASTER or

RENDER2D_PRINT_RASTER. It specifies how the font size for 2D text (whether rendered or raster) changes according to the view as following:

  • SoAnnoText3Property::ANNOTATION: Text maintains its nominal width whatever the view angle. The nominal width is the font size.

  • SoAnnoText3Property::FIT_VECTOR_TEXT: The font size of text changes according to the view angle following the projection on the screen of 3D text.

Example 6.4. How to use SoAnnoText3

This example displays annotation text. The program source code can be found in:$OIVHOME/src/Inventor/examples/Features/AnnoText3/annoText3.cxx.


C++
int
main(int, char **argv)
  {
    Widget myWindow = SoXt::init(argv[0]);
    if (myWindow == NULL)
    exit(1);

    SoSeparator *root = new SoSeparator;
    root->ref();

  // The annotation text will be rendered in 2D and keep
  // its initial size whatever the view angle.
    SoAnnoText3Property *annoText3Prop = new SoAnnoText3Property;
    annoText3Prop->renderPrintType = SoAnnoText3Property::RENDER2D_PRINT_RASTER;
    annoText3Prop->fontSizeHint = SoAnnoText3Property::ANNOTATION;

    SoAnnoText3 *text = new SoAnnoText3;
    text->string = "Annotation text";

    root->addChild(annoText3Prop);
    root->addChild(text);

    SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow);
    myViewer->setSceneGraph(root);
    myViewer->viewAll();
    myViewer->setTitle("AnnotationText");
    myViewer->show();

    SoXt::show(myWindow);
    SoXt::mainLoop();
    return 0;
  }
         

.NET
SoSeparator root = new SoSeparator();

// The annotation text will be rendered in 2D and keep
// its initial size whatever the view angle.
SoAnnoText3Property annoText3Prop = new SoAnnoText3Property();
annoText3Prop.renderPrintType.Value = SoAnnoText3Property.RenderPrintTypes.RENDER2D_PRINT_RASTER;
annoText3Prop.fontSizeHint.Value = SoAnnoText3Property.FontSizeHints.ANNOTATION;

SoAnnoText3 text = new SoAnnoText3();
text.stringField.SetValue("Annotation text");

root.AddChild(annoText3Prop);
root.AddChild(text);

SoWinExaminerViewer myViewer = new SoWinExaminerViewer(this, "", true,
	  SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER);
myViewer.SetSceneGraph(root);
myViewer.ViewAll();
myViewer.SetTitle("AnnotationText");
myViewer.Show();
        

Java
SoSeparator root = new SoSeparator();

// The annotation text will be rendered in 2D and keep
// its initial size whatever the view angle.
SoAnnoText3Property annoText3Prop = new SoAnnoText3Property();
annoText3Prop.renderPrintType.setValue(
SoAnnoText3Property.RenderPrintTypes.RENDER2D_PRINT_RASTER);
annoText3Prop.fontSizeHint.setValue(
SoAnnoText3Property.FontSizeHints.ANNOTATION);

SoAnnoText3 text = new SoAnnoText3();
text.string.setValue("Annotation text");

root.addChild(annoText3Prop);
root.addChild(text);

myViewer = new SwSimpleViewer();
myViewer.setSceneGraph(root);
myViewer.setName("AnnotationText");
myViewer.viewAll();

panel.add(myViewer);
add(panel);