谁说Java不适合写游戏?

In the mood of java...

JME 3 入门教程 3 - Hello Assets

前一节: Hello Node,下一节: Hello Update Loop

本节教程中,我们将学习如何使用jME asset manager(jME资源管理器)向场景图加载3-D模型和文字,并将了解到如何使用正确的文件格式。

右键点击工程,选择“Properties”,选择“Libraries”,点击“Add Library”,将“jme3-test-data”库添加进去。这样,就可以在接下来的例子中使用其中的资源了。

样例代码

package jme3test.helloworld;

 

import com.jme3.app.SimpleApplication;

import com.jme3.font.BitmapText;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;                                                                                         

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

 

/** Sample 3 - how to load an OBJ model, and OgreXML model,

 * a material/texture, or text. */

public class HelloAssets extends SimpleApplication {

 

    public static void main(String[] args) {

        HelloAssets app = new HelloAssets();

        app.start();

    }

 

    @Override

    public void simpleInitApp() {

 

        Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");

        Material mat_default = new Material(

            assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");

        teapot.setMaterial(mat_default);

        rootNode.attachChild(teapot);

 

        // Create a wall with a simple texture from test_data

        Box box = new Box(Vector3f.ZERO, 2.5f,2.5f,1.0f);

        Spatial wall = new Geometry("Box", box );

        Material mat_brick = new Material(

            assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

        mat_brick.setTexture("ColorMap",

            assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));

        wall.setMaterial(mat_brick);

        wall.setLocalTranslation(2.0f,-2.5f,0.0f);

        rootNode.attachChild(wall);

 

        // Display a line of text with a default font

        guiNode.detachAllChildren();

        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");

        BitmapText helloText = new BitmapText(guiFont, false);

        helloText.setSize(guiFont.getCharSet().getRenderedSize());

        helloText.setText("Hello World");

        helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);

        guiNode.attachChild(helloText);

 

        // Load a model from test_data (OgreXML + material + texture)

        Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");

        ninja.scale(0.05f, 0.05f, 0.05f);

        ninja.rotate(0.0f, -3.0f, 0.0f);

        ninja.setLocalTranslation(0.0f, -5.0f, -2.0f);

        rootNode.attachChild(ninja);

        // You must add a light to make the model visible

        DirectionalLight sun = new DirectionalLight();

        sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));

        rootNode.addLight(sun);

 

    }

}

生成并运行样例代码。你将看到一个绿色的忍者和一个彩色的茶壶,忍者站在墙后。屏幕上的文字是“Hello World”。

Asset Manager资源管理器

JME3有一个很便捷的资源管理器,可以协助你结构化地组织游戏资源。项目中的资源是类似模型、材质、纹理、场景、着色器、声音和字体的媒体文件。资源管理器中的root存储了classpath,因此可以从当前classpath(工程的顶级目录)中加载任意文件。

除此之外,你还可以设置assetManager,在其root中添加任意路径,这样就可以从任意自定义路径中加载资源。在 jMonkeyPlatform工程中,jME3在工程中的assets目录下搜索模型。如下是推荐的一种存储资源的目录结构:

assets/Interface/

assets/MatDefs/

assets/Materials/

assets/Models/

assets/Scenes/

assets/Shaders/

assets/Sounds/

assets/Textures/

build.xml

src/...

dist/...

这只是一个最常见的例子,assets目录下的子目录名可以是任意的。

加载纹理

将纹理放在assets/Textures/的子目录下。先加载纹理,再设置材质。下面是simpleInitApp()方法中的示例代码:

        // Create a wall with a simple texture from test_data
        Box box = new Box(Vector3f.ZERO, 2.5f,2.5f,1.0f);
        Spatial wall = new Geometry("Box", box );
        Material mat_brick = new Material(
            assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat_brick.setTexture("ColorMap",
            assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
        wall.setMaterial(mat_brick);
        wall.setLocalTranslation(2.0f,-2.5f,0.0f);
        rootNode.attachChild(wall);

大多数情况下,你可以像本例中一样使用类似“SimpleTextured.j3md”的默认材质。如果是高手,也可以创建自定义材质

加载文字和字体

本例中以默认字体在窗口下方边缘处显示了“Hello Text”。guiNode是一个用于显示平面(正投影)元素的特殊结点,可以把文字附加到guiNode上,这样就能在屏幕上显示该文字。移除guiNode上的孩子结点可以将已存在的文本全部清除。下面是simpleInitApp()方法中的示例代码:

        // Display a line of text with a default font
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText helloText = new BitmapText(guiFont, false);
        helloText.setSize(guiFont.getCharSet().getRenderedSize());
        helloText.setText("Hello World");
        helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
        guiNode.attachChild(helloText);

加载Ogre XML 模型

将模型导出为OgreXML格式(包含.mesh.xml,.scene,.material,.skeleton.xml)并将其放在assets/Models/的子目录下。下面是simpleInitApp()方法中的示例代码:

        // Load a model from test_data (OgreXML + material + texture)
        Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
        ninja.scale(0.05f, 0.05f, 0.05f);
        ninja.rotate(0.0f, -3.0f, 0.0f);
        ninja.setLocalTranslation(0.0f, -5.0f, -2.0f);
        rootNode.attachChild(ninja);
        // You must add a light to make the model visible
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
        rootNode.addLight(sun);

如果使用的是 jMonkeyPlatform创建的build script,那么默认状态下,发布的游戏中将不会包含原始的OgreXML文件,加载时就会报错。

com.jme3.asset.DesktopAssetManager loadAsset
WARNING: Cannot locate resource: Scenes/town/main.scene
com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException

如果是release build,你只能使用.j3o文件。jMonkeyPlatform右键菜单中有“OgreXML模型转为.j3o格式”命令。

从自定义路径中加载资源

如果你的游戏依赖于用户提供的模型文件(显然你不可能在发布时把这些模型添加进去),那又该怎么办呢?如果文件不在默认路径下,你可以注册一个自定义Locator(定位器),这样就能从任意路径加载模型文件。

如下是使用ZipLocator的例子,这个ZipLocator已注册了工程顶级目录下的town.zip这个文件:

    assetManager.registerLocator("town.zip", ZipLocator.class.getName());
    Spatial scene = assetManager.loadModel("main.scene");
    rootNode.attachChild(scene);

如下是一个能够下载压缩模型的HttpZipLocator:

    assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/wildhouse.zip",
                                 HttpZipLocator.class.getName());
    Spatial scene = assetManager.loadModel("main.scene");
    rootNode.attachChild(scene);

JME3 还提供了 ClasspathLocator, ZipLocator, FileLocator, HttpZipLocator, 和 UrlLocator (参见com.jme3.asset.plugins)。

创建模型和场景

为了创建3D模型和场景,你需要一款安装了OgreXML Exporter插件的3D模型编辑器,比如Blender。创建模型时,请使用UV纹理。你可以使用jMonkeyPlatform加载模型,并用这些模型创建场景

将模型导出为带材质的Ogre XML模型格式。

  1. 打开菜单File > Export > OgreXML Exporter,弹出导出器(exporter)对话框。
  2. 在导出材质(Export Matertials)栏将材质命名为与模型同样的名称。例如,模型的名称为something.mesh.xml,那么材质的名称就应当是something.material,也许还有something.skeleton.xml以及一些JPG文件。
  3. 在导出模型(Export Meshes)栏,选择您assets/Models/目录下的一个子目录。例如,assets/Models/something/。
  4. 勾选下列导出选项:
  • § Copy Textures: YES
  • § Rendering Materials: YES
  • § Flip Axis: YES
  • § Require Materials: YES
  • § Skeleton name follows mesh: YES
  1. 点击导出(export)。

文件格式:JME3可以加载Ogre XML模型、材质、场景,还能有加载Wavefront OBJ+MTL格式的模型。发布游戏时,您应该把所有的模型转换为JME3的.j3o格式,这样才能优化模型加载过程。我们推荐您使用jMonkeyPlatform创建工程,它集成了一个.j3o转换器。

  1. 在jMonkeyplatform中打开您的JME3工程。
  2. 在Projects(或者Favorites)视图中右击一个.mesh.xml文件,然后选择“convert to JME3 binary”。
  3. .j3o文件将出现在.mesh.xml文件旁边,文件名保持相同。
  4. 如果您使用jMonkeyPlatform生成的build script,那么mesh.xml文件和obj文件将不会包含在可执行JAR文件中。如果您碰到了运行时异常,请确保您已经把所有的模型都转换成了.j3o格式。

加载模型和场景

任务?

解决方案!

加载有材质的模型

使用资源管理器的loadModel() 方法,将这一Spatial附加到rootNode。

Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
rootNode.attachChild(elephant);
Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.j3o");
rootNode.attachChild(elephant);

加载无材质的模型

如果您有无材质的模型,您应当添加一个默认的材质,以使模型可见。

Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
teapot.setMaterial(mat);
rootNode.attachChild(teapot);

加载场景

您可以像加载模型一样加载场景:

Spatial scene = assetManager.loadModel("Scenes/house/main.scene");
rootNode.attachChild(scene);

练习 - 怎样加载资源

作为练习,不妨尝试一下用不同的方法加载场景。可以直接加载场景,也可以从zip文件中加载:

  1. 下载town.zip示例场景。
  2. (可选:)解压town.zip可以观察到其中的文档结构:您将看到一个名为town文件夹包含了main.scene、XML、纹理等文件。(这里仅仅是介绍一下,您不需要对模型文件做任何操作。)
  3. 将wildhouse.zip放在工程顶级目录,比如这样:

jMonkeyProjects/MyGameProject/assets/

jMonkeyProjects/MyGameProject/build.xml

jMonkeyProjects/MyGameProject/src/

jMonkeyProjects/MyGameProject/town.zip

...

用如下方法从zip文件中加载模型:

  1.  确保town.zip在工程目录中 。
  2. 我们把zip文件定位器注册到工程目录。loadModel() 方法将直接在zip文件中搜索需要加载的文件。
    (也就是说,不要写出town.zip/main.scene这样的路径
  3. simpleInitApp() 中添加如下代码
  4. 清理、生成并运行此工程。您将看到小镇里树立着一堵墙,上面有一个水壶,墙后是一个忍者。
assetManager.registerLocator("town.zip", ZipLocator.class.getName());
Spatial gameLevel = assetManager.loadModel("main.scene");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);

如果你注册了一个新的定位器,请确保无文件名冲突:每个场景都有一个独一无二的名字。

在本教程的前面部分,您是从资源目录下加载的模型和场景。这是加载模型和场景的一般方法。如下是一个典型的过程:

  1. 删除前面练习中输入的代码。
  2. 将解压后的 town/ 目录拷贝到 您工程目录下的assets/Scenes/ 。
  3. simpleInitApp() 中添加如下代码
  4. 注意,这些路径都是相对于assets/…目录的
  5. 清理、生成并运行此工程。您将再次看到小镇里树立着一堵墙,上面有一个水壶,墙后是一个忍者。
    Spatial gameLevel = assetManager.loadModel("Scenes/town/main.scene");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);

:如下这个方法您一定得知道。从.j3o文件加载场景或模型:

  1. 删除前面练习中输入的代码。
  2. 请打开jMonkeyPlatform,打开包含HelloAsset类的工程。
  3. 在工程窗口中,浏览 assets/Scenes/town目录。
  4. 右击main.scene 将其转换为二进制格式::jMoneyPlatform会生成一个main.j3o文件。
  5. simpleInitApp() 中添加如下代码:
  6. 再次提醒,这些路径都是相对于assets/…目录的。
  7. 清理、生成并运行此工程。您将再次看到小镇里树立着一堵墙,上面有一个水壶,墙后是一个忍者。
    Spatial gameLevel = assetManager.loadModel("Scenes/town/main.j3o");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);

加载Scenes/town/main.j3o 和加载Scenes/town/main.scene有什么不同?

  • 在开发阶段你可以使用*.scene.xml文件:您的设计师会不断更新资源目录下的文件,在开发阶段您能够快速查看最新版本的资源目录。 
  • 在测试和发布阶段,请创建和加载*.j3o 文件:.j3o是jME3应用程序的二进制格式,.j3o文件会自动包含在发布的JAR文件中。测试或者发布时,请使用jMonkeyPlatform把所有的.scene和.xml文件转换成.j3o文件,然后再加载。

小结

您已经知道在场景图中摆放静态形状和模型了,也知道如何创建场景了。您学习了如何使用assetManager来加载资源,知道资源在您工程目录下的存放路径。还有重要的一点就是,您学会了如何把模型转换为.j3o格式,使其包含在发布的JAR文件中。

让我们给场景增添一点“动静”,请继续学习Update Loop


另请参阅:

 

posted on 2012-02-03 15:50  sailingbird  阅读(1833)  评论(0编辑  收藏  举报

导航