Poprzedni: Hello SimpleApplication, Następny: Hello Assets.

+

Kiedy tworzysz grę, zaczynasz od stworzenia sceny oraz paru obiektów. Umieszczasz obiekty na scenie, a następnie przemieszczasz, obracasz, zmniejszasz oraz animujesz je.

+

W tym tutorialu rzucimy okiem na prostą scenę trójwymiarową. 3D world is represented in a scene graph, i dlaczego rootNode jest tak ważny. Dowiesz się jak tworzyć i manipulować obiektami – przemieszczać, skalować czy obracać. Zrozumiesz różnicę pomiędzy dwoma typami Spatials w scene graph, Node i Geometry. Aby zrozumieć jak działa scene graph zajrzyj do prezentacji introduction to the scene graph check out our Scene Graph for Dummies.

Kod źródłowy

package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Node;
/** Przykład 2 - How to use nodes as handles to manipulate objects in the scene graph.
 * You can rotate, translate, and scale objects by manipulating their parent nodes.
 * The Root Node is special: Only what is attached to the Root Node appears in the scene. */
public class HelloNode extends SimpleApplication {
    public static void main(String[] args){
        HelloNode app = new HelloNode();
        app.start();
    }
    @Override
    public void simpleInitApp() {
        // create a blue box at coordinates (1,-1,1)
        Box box1 = new Box( new Vector3f(1,-1,1), 1,1,1);
        Geometry blue = new Geometry("Box", box1);
        Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat1.setColor("Color", ColorRGBA.Blue);
        blue.setMaterial(mat1);
        // create a red box straight above the blue one at (1,3,1)
        Box box2 = new Box( new Vector3f(1,3,1), 1,1,1);
        Geometry red = new Geometry("Box", box2);
        Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat2.setColor("Color", ColorRGBA.Red);
        red.setMaterial(mat2);
        // create a pivot node at (0,0,0) and attach it to root
        Node pivot = new Node("pivot");
        rootNode.attachChild(pivot);
        // attach the two boxes to the *pivot* node!
        pivot.attachChild(blue);
        pivot.attachChild(red);
        // rotate pivot node: Both boxes have rotated!
        pivot.rotate( 0.4f , 0.4f , 0.0f );
    }
}----
Build and run the code sample. You should see two colored boxes tilted at the same angle.



== Understanding the Terminology

In this tutorial, you will learn some new terms:


.  The _scene graph_ represents your 3D world.
.  Objects in the scene graph (such as the boxes in this example) are called _Spatials_.
**  A Spatial is a collection of information about an object: its location, rotation, and scale.
**  A Spatial can be loaded, transformed, and saved.

.  There are two types of Spatials, _Nodes_ and _Geometries_.
.  To add a Spatial to the scene graph, you attach the Spatial to the _rootNode_.
.  Everything attached to the _rootNode_ is part of the scene graph.


== Understanding the Code

So what exactly happens in this code snippet? Note that we are using the `simpleInitApp()` method that was introduced in the first tutorial.


.  We create a box Geometry.
**  The box Geometry's extends are (1,1,1), that makes it 2x2x2 world units big.
**  We place the box at (1,-1,1)
**  We give it a solid blue material.
[source,java]
Box box1 = new Box( new Vector3f(1,-1,1), 1,1,1);
Geometry blue = new Geometry("Box", box1);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.Blue);
blue.setMaterial(mat1);----
  1. We create a second box Geometry.

    • This box Geometry is also 2x2x2 world units big.

    • We place the second box at (1,3,1). This is straight above the blue box, with a gap of 2 world units inbetween.

    • We give it a solid red material

        Box box2 = new Box( new Vector3f(1,3,1), 1,1,1);
        Geometry red = new Geometry("Box", box2);
        Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat2.setColor("Color", ColorRGBA.Red);
        red.setMaterial(mat2);----

.  We create a Node.
**  By default the Node is placed at (0,0,0).
**  We attach the Node to the rootNode.
**  An attached Node has no visible appearance in the scene.
[source,java]
Node pivot = new Node("pivot");
rootNode.attachChild(pivot);----
  1. Note that we have not attached the two boxes to anything yet!

    • If we ran the application now, the scenegraph would appear empty.

  2. We attach the two boxes to the node.

    • If we ran the app now, we would see two boxes: one straight above the other.

        pivot.attachChild(blue);
        pivot.attachChild(red); ----

.  Now, we rotate the node.
**  _When we run the application now, we see two boxes on top of each other – but both are tilted at the same angle._
[source,java]
pivot.rotate( 0.4f , 0.4f , 0.0f );----

What has happened? We have attached two box Geometries to a Node. Then we used the Node as a handle to grab the two boxes and transform (rotate) both, in one step. This is a common task and you will use this method a lot in your games when you move game characters around.

Definition: Geometry vs Node

You work with two types of Spatials in your scenegraph: Nodes and Geometries. Here is the difference:

Geometry Node

Visibility:

A visible 3-D object.

An invisible “handle.

Purpose:

A Geometry stores an object’s looks.

A Node groups Geometries and other Nodes together.

Examples:

A box, a sphere, player, a building, a piece of terrain, a vehicle, missiles, NPCs, etc…

The default rootNode, the guiNode (for on-screen text); a floor node, a custom vehicle-with-passengers node, an audio node, etc…

FAQ: How to Populate the Scenegraph?

Task? Solution!

Create a Spatial

Create a shape and give it a Material. For instance a box shape:

----Box mesh = new Box(Vector3f.ZERO, 1, 1, 1);
Geometry thing = new Geometry("thing", mesh);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
thing.setMaterial(mat);----

Make an object appear in the scene

Attach the Spatial to the rootNode, or to any node that is attached to the rootNode.

----rootNode.attachChild(thing);----

Remove objects from the scene

Detach the Spatial from the rootNode, and from any node that is attached to the rootNode.

----rootNode.detachChild(thing);----
[source,java]
----rootNode.detachAllChildren();----

Find a Spatial in the scene by the object’s name or ID

Look at the node’s children.

----Spatial thing = rootNode.getChild("thing");----
[source,java]
----Spatial twentyThird = rootNode.getChild(22);----

Specify what should be loaded at the start

Everything you initialize and attach to the rootNode in the simpleInitApp() method is part of the scene at the start of the game.

How to Transform Objects?

There are three types of 3D transformation: Translation (moving), Scaling (resizing), and Rotation (turning).

Task? Solution! X Y Z

Position and move objects

Translation: Specify the new location in three dimensions: right/left, up/down, forward/backward.
Example 1. To move an object to specific coordinates, such as (0,40.2f,-2), use:

----thing.setLocalTranslation( new Vector3f( 0.0f, 40.2f, -2.0f ) );----
 +
Example 2: To move an object _by_ a certain amount, e.g. higher up (y=40.2f) and further back (z=-2.0f):
----thing.move( 0.0f, 40.2f, -2.0f );----

right/left

up/down

forward/ backward

Resize objects

Scaling: To resize a Spatial, specify the scale factor in each dimension: length, height, width. A value between 0.0f and 1.0f will shrink the object; a value bigger than 1.0f will make it grow; and 1.0f will keep this dimension the same. Using the same value for each dimension scales an object proportionally, using different values stretches it.
Example: Make it 10 times longer, one tenth of the height, same width:

----thing.setLocalScale( 10.0f, 0.1f, 1.0f  );----
[source,java]
----thing.scale( 10.0f, 0.1f, 1.0f );----

length

height

width

Turn objects

Rotation: 3-D rotation is a bit tricky (learn details here). In short: You can rotate around three axes, pitch, yaw, and roll.
Important: You do not specify the rotation in degrees from 0° to 360°, but in radians from 0.0f to 6.28f (FastMath.PI*2) !
Example: To roll an object 180° around the z axis:

----thing.rotate( 0f , 0f , FastMath.PI );----
 If you do want to specify angles in degrees then multiply your degrees value with FastMath.DEG_TO_RAD +
Example:
----thing.rotate( 0f , 0f , 180*FastMath.DEG_TO_RAD );----
  Tip: If your game idea calls for a serious amount of rotations, it is worth looking into <<jme2/quaternion#,quaternion>>s, a data structure that can combine and store rotations efficiently.
----thing.setLocalRotation( new Quaternion(). fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0)));----

pitch

yaw

roll

How to Troubleshoot Nodes?

If you get unexpected results, check whether you made the following common mistakes:

Problem? Solution!

Created Geometry does not appear in scene

Have you attached it to (a node that is attached to) the rootNode?
Does it have a Material?
What is its translation (position)? Is it covered up by another Geometry?
Is it too far from the camera? try cam.setFrustumFar(111111f);

Spatial rotates wrong

Did you use radian values, and not degrees? (if you used degrees multiply them with FastMath.DEG_TO_RAD to get them converted to radians)+ Did you rotate the intended pivot node?
Did you rotate around the right axis?

Geometry has an unexpected Material

Did you reuse a Material from another Geometry and have inadvertently changed its properties?
(if so, maybe consider cloning: mat2 = mat.clone(); )

Conclusion

You have learned that the 3D world is a Scene Graph of Spatials: Visible Geometries and invisible Nodes. You can transform Spatials, or attach them to nodes and transform the nodes.

+

Since standard shapes like spheres and boxes get old fast, continue with the next chapter where you learn to load assets, such as 3-D models.

<tags><tag target="beginner" /><tag target="rootNode" /><tag target="node" /><tag target="intro" /><tag target="documentation" /><tag target="color" /><tag target="polish" /></tags>