JME 3 入门教程 3 - Hello Assets
本节教程中,我们将学习如何使用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模型格式。
- 打开菜单File > Export > OgreXML Exporter,弹出导出器(exporter)对话框。
- 在导出材质(Export Matertials)栏将材质命名为与模型同样的名称。例如,模型的名称为something.mesh.xml,那么材质的名称就应当是something.material,也许还有something.skeleton.xml以及一些JPG文件。
- 在导出模型(Export Meshes)栏,选择您assets/Models/目录下的一个子目录。例如,assets/Models/something/。
- 勾选下列导出选项:
- § Copy Textures: YES
- § Rendering Materials: YES
- § Flip Axis: YES
- § Require Materials: YES
- § Skeleton name follows mesh: YES
- 点击导出(export)。
文件格式:JME3可以加载Ogre XML模型、材质、场景,还能有加载Wavefront OBJ+MTL格式的模型。发布游戏时,您应该把所有的模型转换为JME3的.j3o格式,这样才能优化模型加载过程。我们推荐您使用jMonkeyPlatform创建工程,它集成了一个.j3o转换器。
- 在jMonkeyplatform中打开您的JME3工程。
- 在Projects(或者Favorites)视图中右击一个.mesh.xml文件,然后选择“convert to JME3 binary”。
- .j3o文件将出现在.mesh.xml文件旁边,文件名保持相同。
- 如果您使用jMonkeyPlatform生成的build script,那么mesh.xml文件和obj文件将不会包含在可执行JAR文件中。如果您碰到了运行时异常,请确保您已经把所有的模型都转换成了.j3o格式。
加载模型和场景
任务? |
解决方案! |
加载有材质的模型 |
使用资源管理器的 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文件中加载:
- 下载town.zip示例场景。
- (可选:)解压town.zip可以观察到其中的文档结构:您将看到一个名为
town
文件夹
,
包含了main.scene、XML、纹理等文件。(这里仅仅是介绍一下,您不需要对模型文件做任何操作。) - 将wildhouse.zip放在工程顶级目录,比如这样:
jMonkeyProjects/MyGameProject/assets/
jMonkeyProjects/MyGameProject/build.xml
jMonkeyProjects/MyGameProject/src/
jMonkeyProjects/MyGameProject/town.zip
...
用如下方法从zip文件中加载模型:
- 确保
town.zip
在工程目录中
。 - 我们把zip文件定位器注册到工程目录。loadModel() 方法将直接在zip文件中搜索需要加载的文件。
(也就是说,不要写出town.zip/main.scene
这样的路径
) - 在
simpleInitApp()
中添加如下代码
- 清理、生成并运行此工程。您将看到小镇里树立着一堵墙,上面有一个水壶,墙后是一个忍者。
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);
如果你注册了一个新的定位器,请确保无文件名冲突:每个场景都有一个独一无二的名字。
在本教程的前面部分,您是从资源目录下加载的模型和场景。这是加载模型和场景的一般方法。如下是一个典型的过程:
- 删除前面练习中输入的代码。
- 将解压后的
town/
目录拷贝到 您工程目录下的assets/Scenes/
。 - 在
simpleInitApp()
中添加如下代码
:
- 注意,这些路径都是相对于
assets/…
目录的
。
- 清理、生成并运行此工程。您将再次看到小镇里树立着一堵墙,上面有一个水壶,墙后是一个忍者。
Spatial gameLevel = assetManager.loadModel("Scenes/town/main.scene");
gameLevel.setLocalTranslation(0, -5.2f, 0);
gameLevel.setLocalScale(2);
rootNode.attachChild(gameLevel);
:如下这个方法您一定得知道。从.j3o文件加载场景或模型:
- 删除前面练习中输入的代码。
- 请打开jMonkeyPlatform,打开包含HelloAsset类的工程。
- 在工程窗口中,浏览
assets/Scenes/town
目录。 - 右击
main.scene
将其转换为二进制格式::jMoneyPlatform会生成一个main.j3o文件。 - 在
simpleInitApp()
中添加如下代码:
- 再次提醒,这些路径都是相对于
assets/…
目录的。
- 清理、生成并运行此工程。您将再次看到小镇里树立着一堵墙,上面有一个水壶,墙后是一个忍者。
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。
另请参阅:
- 将Blender中的Ogre XML格式的场景导出到JME
- 一个很棒的加载模型的截图
- 欲了解如何加载声音,请参阅Hello Audio
- 欲进一步了解纹理和材质,请参阅Hello Material
posted on 2012-02-03 15:50 sailingbird 阅读(1833) 评论(0) 编辑 收藏 举报