Kapitel 10
lecture
A program always describes a scene and then specifies which viewer should be
used for displaying the scene. This is true for Inventor and many other graphics
programs.
To build the Scenegraph, it has to be specified which node is a child of
which other node. This has to happen in the right order, so that material
and transformations are described before the shape is drawn.
As we have learned in the previous lecture, there needs to be a function
called main, which contains the commands to initialise and build the scene.
It is also necessary to reference the root node. With the main and ref function
the program structure will look like this:
In order to understand how to treat the Inventor objects and functions a
number of files, so called header files, have to be included. This can also
be necessary for objects and functions defined in other files, which will
be linked with this one when compiling.
It is possible that the same sequence of commands would have to be written
several times with different parameters. In this case it might be a good idea
to define a new function for the execution of those commands. Functions with
mnemonic names can make the code easier to read.
These are only the basics, but to understand them means to be in a good position
to understand the code of an Inventor C++ program. As you will see, there are
many right ways to write the same thing, which is nice because everybody can
chose the approach he/she feels the most comfortable with. On the other hand
it makes learning difficult, because there are a lot of options to chose from
instead of a straight way to go. We propose that you should start with a working
program and modifiy it until it does what you intended it to do. This is a valid
approach to learn programming, specially for tools, like Inventor, that can
do very complicated things. It is allowed to copy code, learn from reading it
and then use the code as a basic for your program. But, if you use code from
another person, always keep a reference to the original in your file. And, if
there is any copyright note in some code do not copy it unless you have the
permission to do so.
5 important nodes are introduced so that you can get started with modelling
3D scenes:
In the Scenegraph the Separator node is used to isolate effects of nodes in
a group. All nodes of the group have to be made its children. You do not have
to set any of the variables of a Separator.
SoSeparator *root = new SoSeparator;
Cubes and Spheres are specialised shape object. The important variables to be
set are width, height and depth for the cube. The default value for those dimensions
is 2.0.
SoCube *mycube = new SoCube;
mycube->width = 1.5;
mycube->height = 2.7;
mycube->depth = 2.1;
And for the Sphere the radius can be specified, default = 1.0.
SoSphere *mysphere = new SoSphere;
mysphere->radius = 0.9;
Material at first will be interesting to set the color of the following shapes.
For the beginning lets look at the diffuseColor. The default value for the diffuse
rgb-color is [0.8 0.8 0.8], the first parameter is for the amount of red, the
second for green, the third for blue. Values range from 0 to 1, white is [1
1 1], black is [0 0 0], a not too saturated red is [0.8 0 0].
SoMaterial *myblue = new SoMaterial;
myblue->diffuseColor.setValue(0.0, 0.05, 0.9);
The Material node has fields for other kinds of color, shininess and transparency,
everything you want to specify for solid colored materials. You can look up
the other fields of SoMaterial in the quick reference.
The Transformation node can specify and combine the translation, rotation and
scaling of the following shapes. The default values are set so that no transformation
will happen. A translation is defined by three values for X, Y, and Z. The orientation
of the coordinate system by default is so that Y points upwards.
SoTransform *mytrans = new SoTransform;
mytrans->translation.setValue(1.2, 0, 2.8);
The rotation is defined by a vector which defines the rotation axis and a value
for the angle in radius. The following defined a quarter turn around the Y-axis:
mytrans->rotation.setValue(SbVec3f(0 1 0), 1.57);
Shapekits can be used for any Inventor shape node. With a Shapekit you do not
have to create and arrange each node individually. The following example produces
the blue cube from example.iv of the previous exercise.
SoShapeKit *mykit = new SoShapeKit;
mykit->setPart("shape", new SoCube);
mykit->set("shape { width 2 height 2 depth 2 }");
mykit->set("material {diffuseColor 0.0 0.0 1.0}");
mykit->set("transform {translation 2.5 0.0 0.0}");
In the set() function the form of the string between " and " is actually like
the iv-format. But, because it is a string, it is not possible to use variables
inside of it.
Viewers allow you to look at the objects of a scene and move around. There are
4 types of viewers: the ExaminerViewer, the WalkViewer, the FlyViewer, and the
PlaneViewer. Important functions are common to all viewers, the difference is
mostly in the tools for navigation. They all have a "?" button to display the
necessary information on how to use them. In the following specifics of navigation
of two important viewers are explained. For navigating you have to select the
arrow cursor from the buttons on the right.
The examiner viewer treats the scene like an object. It lets you rotate the
whole scene, so that you can look at it from all sides. It is also possible
to use the zoom to get a closer look at the object.
The walk viewer lets you move around in the scene. It feels like driving around
with a car. This is nice for architectural scenes, but one has to get used to
it. Using the zoom can distort the scene.
This is how a walk viewer is coded into main, (for the ExaminerViewer replace
SoXtWalkViewer with SoXtExaminerViewer):
void main(int , char **argv)
{
Widget myWindow = SoXt::init(argv[0]);
SoSeparator *root = new SoSeparator;
root->ref();
...
...
SoXtWalkViewer *myViewer = new SoXtWalkViewer(myWindow);
myViewer->setSceneGraph(root);
myViewer->setTitle("MY WALK VIEWER");
myViewer->show();
SoXt::show(myWindow);
SoXt::mainLoop();
}
intinteger number, often used for counting.
- float
- floating number, you can use float types for all coordinates and dimensions
in Inventor.
- char
- the character type is used for strings, which are defined as an array
of characters or a pointer to a char, like:
char *word = "theword";
- enum
- An enumeration declares a set of constant integer variables, the following
command sets HORIZONTAL = 0, PERPENDIC = 1, and VERTICAL = 2. Orientation
is a new type and can be used to declare a variable.
enum orientation {HORIZONTAL, PERPENDIC, VERTICAL};
orientation myorient = HORIZONTAL;
- SbVec3f
- This is a 3D vector class used to represent points or directions. It has
some useful functions associated with which you might get to now later,
for now you will use it to define the axis of a rotation.
You will get to know many functions, two are important for building the Scenegraph.
They are always used in combination with an object:
- addChild
- to add the first child to a node or additional children the to the end
of the list of children.
root->addChild(mytrans);
root->addChild(mymaterial);
root->addChild(mycube);
- insertChild
- is used to add a child at a specific position, the first position is 0.
This is useful to add transformations or materials before a shape.
root->addChild(mycube);
root->insertChild(mytrans, 0);
- if
- The if-statement tests a particular condition, if that condition is true
an action or set of actions is executed. Form:
if (expression) {
statement 1;
statement 2;
...
}
- switch-case
- to choose among different choices. Switch specifies which variable of
type int should be compared, case gives a value and a set of statements
ended by break:
switch(a)
{
case 1:
statement 1.1;
statement 1.2;
...
break;
case 2:
statement 2.1;
statement 2.2;
...
break;
case 3:
statement 3.1;
statement 3.2;
...
break;
...
}
- for
- can be used to step through a set of statements until a condition becomes
false, usually a counter variable of type int is modified until it reaches
a limit, i++ is a way to increase i by 1 every time the loop is executed:
for (int i = 0; i<7 ; i++) {
statement 1;
statement 1;
...
}
To define a new function it is important to know whether it should return a
value. In that case a return type has to selected. For your first applications
it will be fine to have void functions, this means functions that do not return
anything, only execute a number of statements.
The second thing to specify are the arguments and their types, because for
the C++ compiler these things have to be known.
The following function will draw a number (num) of cubes each one at a certain
distance (dist) from the previous:
void makecubes(SoSeparator *root, int num, float dist)
{
SoTransform *atrans = new SoTransform;
atrans->translation.setValue(dist, 0.0, 0.0);
for (int i = 0; i < num ; i++) {
SoCube *acube = new SoCube;
root->addChild(atrans);
root->addChild(acube);
}
}
In main you can call the function with: makecubes(root, 5, 3.2);
At the very beginning of your C++ file you have to list all header files that
need to be included.
Including a header file is written like this:
#include <Inventor/nodes/SoCube.h>
or like this if the include file is in the same directory as your program:
#include "student.h"
Every viewer, node, field, or kit, that you refer to in your code needs to be
declared in a header file. The man-pages can help to find out which header files
you have to include.
The goal is to get used to the commands of a C-based language and to learn to
program 3D environments with Inventor. The task is to modify the program that
generates a model of Max Bill's Sculpture at the Bahnhofstrasse in Zurich and
lets you walk through it. These are the steps for proceeding with this exercise:
- Copy all the files in the directory "~prog/ausgabe/exercise10" to your
exercise10 directory.
- Try to understand the program, by opening the file called exercise10.c++
with an editor.
- Think about possible modifications. Start with small things, like a color
change or a change of position.
- Modify the program text, compile and run it.
The online book 'The Inventor Mentor' and the hardcopy version of it are good
places to look for explanations and samples of code.
If you think you understand every line of code of the program, which means
that you can modify it and know what is going to change in the model, you
have completed this exercise and are ready for next weeks exercise.
For a proof of your understanding please hand in a modified c++-program of the
Bill Sculpture to '~prog/abgabe/exercise10/yourname10.c++'.
This website has been archived and is no longer maintained.