JME 3 入门教程 2 – HELLO NODE

原文链接:http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_node

制作3D游戏时,一开始就得创建好场景和一些对象。把这些对象(玩家、障碍物等)放置在场景当中,移动、放缩、上色,然后加上动画。

本节教程我们将看到一个简单的3D场景。你将会了解到,3D世界是以场景图(scene graph)来描绘的,以及为何rootNode如此重要。你还将学会创建简单的对象,对其进行变换——移动、放缩、旋转。你还将理解场景图中两种类型的SpatialNodeGeometry。如果你想直观地了解有关场景图的基础知识,请看Scene Graph for Dummies(为小鸟们准备的场景图课程)。

【注:鄙人认为Spatial可译为“空间元”,Node可译为“结点”,Geometry可译为“几何体”】

 1: package jme3test.helloworld;
   2:  
   3: import com.jme3.app.SimpleApplication;
   4: import com.jme3.material.Material;
   5: import com.jme3.math.Vector3f;
   6: import com.jme3.scene.Geometry;
   7: import com.jme3.scene.shape.Box;
   8: import com.jme3.math.ColorRGBA;
   9: import com.jme3.math.FastMath;
  10: import com.jme3.math.Matrix3f;
  11: import com.jme3.scene.Node;
  12:  
  13: /** Sample 2 - How to use nodes as handles to manipulate objects in the scene graph.
  14:  * You can rotate, translate, and scale objects by manipulating their parent nodes.
  15:  * The Root Node is special: Only what is attached to the Root Node appears in the scene. */
  16: public class HelloNode extends SimpleApplication {
  17:  
  18:     public static void main(String[] args){
  19:         HelloNode app = new HelloNode();
  20:         app.start();
  21:     }
  22:  
  23:     @Override
  24:     public void simpleInitApp() {
  25:  
  26:         // create a blue box at coordinates (1,-1,1)
  27:         Box box1 = new Box( new Vector3f(1,-1,1), 1,1,1);
  28:         Geometry blue = new Geometry("Box", box1);
  29:         Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
  30:         mat1.setColor("Color", ColorRGBA.Blue);
  31:         blue.setMaterial(mat1);
  32:  
  33:         // create a red box straight above the blue one at (1,3,1)
  34:         Box box2 = new Box( new Vector3f(1,3,1), 1,1,1);
  35:         Geometry red = new Geometry("Box", box2);
  36:         Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
  37:         mat2.setColor("Color", ColorRGBA.Red);
  38:         red.setMaterial(mat2);
  39:  
  40:         // create a pivot node at (0,0,0) and attach it to root
  41:         Node pivot = new Node("pivot");
  42:         rootNode.attachChild(pivot);
  43:  
  44:         // attach the two boxes to the *pivot* node!
  45:         pivot.attachChild(blue);
  46:         pivot.attachChild(red);
  47:         
  48:     // attach the two boxes to the *pivot* node!        
  49:    pivot.attachChild(blue);        
  50:    pivot.attachChild(red);
  51:         // rotate pivot node: Both boxes have rotated!
  52:         pivot.rotate( 0.4f , 0.4f , 0.4f );
  53:     }
  54: }

Build并运行此样例代码。你将看到两个立方体以同样的角度倾斜着。

理解术语

这一节,你将会学到一些新的术语:

1. 场景图——用于描述3D world

2. 场景图中的对象(如本例中的立方体)称为Spatial

  • Spatial是对象信息的集合,包括对象的坐标、旋转角度、以及缩放比例。
  • 可以加载、变换、保存Spatial。

    3. Spatial分为两类,NodeGeometry

    4. 要将一个Spatial添加到场景图中,就得将Spatial附加到rootNode

    5. 附加于rootNode的一切对象都属于场景图的一部分。

    理解代码

    上面的代码片段里究竟发生了些什么呢?请注意,我们用到了第一节教程中介绍的simpleInitApp()方法。

    1. 创建一个立方体Geometry

  • 立方体Geometry的延展度为(1, 1, 1),于是这个立方体的体积就为2x2x2 world unit(场景单位长度)。【注:延展是对称双向延展的,此处的(1, 1, 1)即在x, y, z轴正负方向上各延展1个world unit,就构成了一个2x2x2的立方体。】
  • 将立方体置于(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);
    • 2. 创建另一个立方体Geometry

    • 这个立方体的体积就为2x2x2 world unit。
    • 将这个立方体置于(1, 3, 1)处。这个位置位于蓝色立方体的正上方,两者间距2 world unit。
    • 设置立方体材质为纯红色。
      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);


  • 3. 创建一个Node

    • 默认情况下,Node坐标为(0, 0, 0)。
    • 把这个Node附加到rootNode。
    • Node在场景中是不可见的
    Node pivot = new Node("pivot");
    rootNode.attachChild(pivot);

    4. 注意,我们还没把这两个立方体附加于任何东西

    • 如果我们现在就运行,将看到场景图中什么也没有

    5. 将两个立方体附加到Node

    • 现在运行的话,就可以观察到一上一下两个立方体了。
    pivot.attachChild(blue);
    pivot.attachChild(red);

    6. 现在,旋转Node

    运行一下,我们看到,还是一上一下两个立方体,但是都以相同的角度倾斜着

    pivot.rotate( 0.4f , 0.4f , 0.0f );

    上述步骤进行了什么操作呢?我们把两个立方体Geometry附加到一个Node上,接着,利用这个Node作为“句柄”,同时对两个立方体进行变换(旋转)。这是一种常见的操作,在创建游戏移动游戏人物时,你将频繁使用这种操作。

    定义:Geometry vs Node

    在场景图中,你会使用到两种类型的Spatial:Node和Geometry。以下是二者的区别:

     

    Geometry

    Node

    可见性 可见的3-D对象 不可见的“句柄”
    用途 存储对象外形 用于将多个Geometry和Node组织在一起
    举例 立方体,球体,玩家,建筑物,地形,车辆,导弹,NPC等等 默认的rootNode,guiNode(用于屏幕文字显示),地面Node,自定义的载有乘客的车辆node,声音Node等等

    FAQ:怎样填充场景图

    任务

    解决方案

    创建Spatial 创建一个几何形,设定材质。比如一个立方体的例子:
    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);
    让对象显示在场景中

    将Spatial附加到rootNode或者任何附加于rootNode的Node。

    rootNode.attachChild(thing);
    从场景中移除对象

    将Spatial从rootNode或任何附加于rootNode的Node上分离下来。

    rootNode.detachChild(thing); 
    rootNode.detachAllChildren();
    以对象名称或ID在场景中查找某Spatial

    查找Node的孩子

    Spatial thing = rootNode.getChild("thing"); 
    Spatial twentythird = rootNode.getChild(22);
    指定初始化场景时加载内容 只要在simpleInitApp()方法中初始化对象,并附加于rootNode,该对象就会显示在游戏初始场景中。

     

    怎样变换对象?

    有三种类型的3D变换:位移(平移),放缩(调整大小),旋转(转动)

    任务

    解决方案

    x

    Y

    Z

    坐标以及移动对象

    Translation(位移):指定对象在三维坐标系中的新坐标:右/左、上/下、前/后。

    例1. 将对象移动到指定坐标,如(0, 40.2f, -2),代码如下:

    thing.setLocalTranslation( new Vector3f( 0.0f, 40.2f, -2.0f ) ); 

    例2. 将对象移动一段距离,如上移(y = 40.2f)后移(z = -2.0f):

    thing.move( 0.0f, 40.2f, -2.0f );
    右/左 上/下 前/后
    调整对象大小

    放缩(Scaling):调整Spatial大小,指定各坐标轴方向上的放缩系数:长度、高度、宽度。放缩系数介于0.0f和1.0f之间时,对象将缩小;放缩系数大于1.0f时,对象将放大;放缩系数为1.0f时将保持原来的体积不变。若各坐标轴方向上的放缩系数相同,则对象将保持原有形状成倍放缩,否则对象将走样【注:走样指长高宽比例变化】。

    例:长度增至原来10倍,高度缩小至原来的1/10,宽度不变:

    thing.setLocalScale( 10.0f, 0.1f, 1.0f ); 
    thing.scale( 10.0f, 0.1f, 1.0f );
    转动对象

    旋转(Rotation):3-D旋转有些棘手(了解更多)。简而言之,可以绕着三个坐标轴旋转,【注:数学上,关于右手笛卡尔坐标系的x-, y- 和z-轴的旋转分别叫做roll, pitch 和yaw 旋转。参见维基百科。但在jME中坐标系是这样(这是3D基础知识介绍,稍后我会把翻译出来)的,这是3D游戏引擎中惯用的坐标系统,与数学中的有所不同,以Z轴作为深度的坐标轴,这也就是为什么Z-Buffer算法也叫深度缓冲算法。】

    注意:不要使用角度制,角度范围0°~360°;请使用弧度制,弧度范围0.0f~6.28f(FastMath.PI*2)。

    例:将对象绕Z轴旋转180°。

    thing.rotate( 0f , 0f , FastMath.PI );

    提示:如果游戏中涉及大量旋转,最好使用quaternion。Quaternion是一种数据结构,它可以高效地存储和组合多个旋转。

    thing.setLocalRotation( new Quaternion(). fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0)));
    X轴旋转角度(pitch) Y轴旋转角度(yaw) Z轴旋转角度(roll)

    有关Node的故障排除

    问题

    解决方案

    场景中看不见创建的Geometry

    把Geometry附加到rootNode没?或者附加到某个附加于rootNode的Node没?

    有没有设定材质?

    坐标是多少?是不是被别的Geometry遮挡了?

    Spatial旋转错误

    使用的是弧度还是角度?

    是不是旋转了正确的Node?

    旋转轴是否正确?

    Geometry材质异常 是不是用了别的Geometry的材质?或者不小心修改了材质的属性?

    小结

    你已经了解到3D场景就是一张“画”满各种Spatial的场景图:可见的Geometry和不可见的Node。你可以对Spatial进行变换,或者将其附加到Node,然后变换Node。

    类似球体、立方体等标准几何形是老古董了,接着学习下一节,你将学会如何加载3-D模型等资源。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
com.jme3.animation com.jme3.app com.jme3.app.state com.jme3.asset com.jme3.asset.pack com.jme3.asset.plugins com.jme3.audio com.jme3.audio.joal com.jme3.audio.lwjgl com.jme3.audio.plugins com.jme3.bounding com.jme3.bullet com.jme3.bullet.collision com.jme3.bullet.collision.shapes com.jme3.bullet.control com.jme3.bullet.joints com.jme3.bullet.joints.motors com.jme3.bullet.nodes com.jme3.bullet.nodes.infos com.jme3.bullet.util com.jme3.collision com.jme3.collision.bih com.jme3.effect com.jme3.export com.jme3.export.binary com.jme3.export.xml com.jme3.font com.jme3.font.plugins com.jme3.input com.jme3.input.awt com.jme3.input.binding com.jme3.input.dummy com.jme3.input.event com.jme3.input.lwjgl com.jme3.light com.jme3.material com.jme3.material.plugins com.jme3.math com.jme3.niftygui com.jme3.post com.jme3.renderer com.jme3.renderer.jogl com.jme3.renderer.layer com.jme3.renderer.lwjgl com.jme3.renderer.queue com.jme3.scene com.jme3.scene.control com.jme3.scene.debug com.jme3.scene.mesh com.jme3.scene.plugins com.jme3.scene.plugins.ogre com.jme3.scene.shape com.jme3.shader com.jme3.shader.plugins com.jme3.shadow com.jme3.system com.jme3.system.jogl com.jme3.system.lwjgl com.jme3.terrain com.jme3.texture com.jme3.texture.plugins com.jme3.ui com.jme3.util com.jme3.util.xml com.jme3.video com.jme3.video.plugins.jheora jme3game.cubefield jme3test jme3test.app jme3test.asset jme3test.audio jme3test.awt jme3test.bounding jme3test.bullet jme3test.collision jme3test.conversion jme3test.effect jme3test.export jme3test.gui jme3test.light jme3test.material jme3test.math jme3test.model jme3test.model.anim jme3test.model.shape jme3test.niftygui jme3test.post jme3test.scene jme3test.stress jme3test.texture jme3tools.converters jme3tools.converters.model jme3tools.converters.model.strip jme3tools.nvtex jme3tools.optimize jme3tools.preview

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值