libgdx3D第三讲-场景载入
Loading a scene with LibGDX
- 资源准备
四个模型。包含之前用到的飞船、入侵者、障碍、空间场景(有纹理和反向法线。因此内部可视)
- 教程開始
1. 上一讲我们使用fbx-conv转换我们的模型,对新的模型也须要这样做。但如今我们先直接使用给出的OBJ文件。把他们复制到asset/data文件夹下,并像上次一样载入它们。以下给出今天的代码,并在下方解说。
public
class
LoadSceneTest
implements
ApplicationListener {
public
PerspectiveCamera cam;
public
CameraInputController camController;
public
ModelBatch modelBatch;
public
AssetManager assets;
public
Array<ModelInstance> instances =
new
Array<ModelInstance>();
public
Environment environment;
public
boolean
loading;
public
Array<ModelInstance> blocks =
new
Array<ModelInstance>();
public
Array<ModelInstance> invaders =
new
Array<ModelInstance>();
public
ModelInstance ship;
public
ModelInstance space;
@Override
public
void
create () {
modelBatch =
new
ModelBatch();
environment =
new
Environment();
environment.set(
new
ColorAttribute(ColorAttribute.AmbientLight,
0
.4f,
0
.4f,
0
.4f,
1f));
environment.add(
new
DirectionalLight().set(
0
.8f,
0
.8f,
0
.8f, -1f, -
0
.8f,
-0
.2f));
cam =
new
PerspectiveCamera(
67
, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(0f, 7f, 10f);
cam.lookAt(
0
,
0
,
0
);
cam.near = 1f;
cam.far = 300f;
cam.update();
camController =
new
CameraInputController(cam);
Gdx.input.setInputProcessor(camController);
assets =
new
AssetManager();
assets.load(
"data/ship.obj"
, Model.
class
);
assets.load(
"data/block.obj"
, Model.
class
);
assets.load(
"data/invader.obj"
, Model.
class
);
assets.load(
"data/spacesphere.obj"
, Model.
class
);
loading =
true
;
}
private
void
doneLoading() {
ship =
new
ModelInstance(assets.get(
"data/ship.obj"
, Model.
class
));
ship.transform.setToRotation(Vector3.Y,
180
).trn(
0
,
0
, 6f);
instances.add(ship);
Model blockModel = assets.get(
"data/block.obj"
, Model.
class
);
for
(
float
x = -5f; x <= 5f; x += 2f) {
ModelInstance block =
new
ModelInstance(blockModel);
block.transform.setToTranslation(x,
0
, 3f);
instances.add(block);
blocks.add(block);
}
Model invaderModel = assets.get(
"data/invader.obj"
, Model.
class
);
for
(
float
x = -5f; x <= 5f; x += 2f) {
for
(
float
z = -8f; z <= 0f; z += 2f) {
ModelInstance invader =
new
ModelInstance(invaderModel);
invader.transform.setToTranslation(x,
0
, z);
instances.add(invader);
invaders.add(invader);
}
}
space =
new
ModelInstance(assets.get(
"data/spacesphere.obj"
, Model.
class
));
loading =
false
;
}
@Override
public
void
render () {
if
(loading && assets.update())
doneLoading();
camController.update();
Gdx.gl.glViewport(
0
,
0
, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instances, environment);
if
(space !=
null
)
modelBatch.render(space);
modelBatch.end();
}
@Override
public
void
dispose () {
modelBatch.dispose();
instances.clear();
assets.dispose();
}
@Override
public
void
resume () {
}
@Override
public
void
resize (
int
width,
int
height) {
}
@Override
public
void
pause () {
}
}
如今来看代码具体解释:
public
Array<ModelInstance> blocks =
new
Array<ModelInstance>();
public
Array<ModelInstance> invaders =
new
Array<ModelInstance>();
public
ModelInstance ship;
public
ModelInstance space;
这里我们添加Array存放障碍blocks和入侵者invaders,建立ModelInstance单例存飞船ship和场景space。我们依旧用它们来渲染。这样做的优点是我们能够非常方便的控制每一个部分。
public
void
create () {
modelBatch =
new
ModelBatch();
...
cam.position.set(0f, 7f, 10f);
...
assets.load(
"data/ship.obj"
, Model.
class
);
assets.load(
"data/block.obj"
, Model.
class
);
assets.load(
"data/invader.obj"
, Model.
class
);
assets.load(
"data/spacesphere.obj"
, Model.
class
);
loading =
true
;
}
给camera设置一个更合适的位置;让assetmanager载入全部模型;
private
void
doneLoading() {
ship =
new
ModelInstance(assets.get(
"data/ship.obj"
, Model.
class
));
ship.transform.setToRotation(Vector3.Y,
180
).trn(
0
,
0
, 6f);
instances.add(ship);
Model blockModel = assets.get(
"data/block.obj"
, Model.
class
);
for
(
float
x = -5f; x <= 5f; x += 2f) {
ModelInstance block =
new
ModelInstance(blockModel);
block.transform.setToTranslation(x,
0
, 3f);
instances.add(block);
blocks.add(block);
}
Model invaderModel = assets.get(
"data/invader.obj"
, Model.
class
);
for
(
float
x = -5f; x <= 5f; x += 2f) {
for
(
float
z = -8f; z <= 0f; z += 2f) {
ModelInstance invader =
new
ModelInstance(invaderModel);
invader.transform.setToTranslation(x,
0
, z);
instances.add(invader);
invaders.add(invader);
}
}
space =
new
ModelInstance(assets.get(
"data/spacesphere.obj"
, Model.
class
));
loading =
false
;
}
从这里開始就有趣了。第一行我们取飞船模型并建立ModelInstance;第二行我们把它回转180度。如今它面向远离照相机方向。然后将它在Z轴朝向相机移动6个单位;第三行我们把它增加array中,使它能被渲染。之后我们对block 和 invader 模型做同样的事,但在这里我们建立多个实例。block将在x轴上排成一列,并将它们增加到两个array中; invader将被放置在在XZ平面的网格上;最后建立space,但我们不会将它增加array中,由于它不须要渲染光照。
public
void
render () {
...
modelBatch.begin(cam);
modelBatch.render(instances, environment);
if
(space !=
null
)
modelBatch.render(space);
modelBatch.end();
}
在render()方法中,我们像之前一样使用渲染。我们也对space使用无灯光渲染,注意这里要检查space是否载入好。由于它是异步载入的。
效果如图:
看起来不错。我们如今能够仅仅实现一些游戏功能,然后到此结束。其实。我敢打赌。有相当多的游戏是这样做的。但对更大的场景就不能使用了,如今我们来调整它。
2.打开你喜欢的模型应用程序(modeling application )。建立新场景。我使用Maya。这个样例不论什么模型应用程序都能够。如今把四个模型导入到场景中。假设你是新手建议一个一个导入来保证正确显示,比如手动制定纹理、翻转纹理坐标等。
另外给每一个模型起名字,且在之后不要改名。如图:
我启用了X射线。以方便编辑,这就是为什么这些模型看起来是透明的。后面的是场景。你也能够看到 “ship”、“block”、“invader” 模型都堆在一起,由于它们的位置都是(0,0,0)。假设全部模型都正确载入并起好名字,你能够将其导出成FBX格式,起名为invaders.fbx。模型应用程序中也能够保存一份以备改动。
3.使用fbx-conv把FBX文件转换为G3DB格式
fbx-conv invaders.fbx
假设你在创建FBX文件时有翻转纹理坐标,你如今也须要将它们翻转。那么代码例如以下
fbx-conv -f invaders.fbx
如今把invaders.g3db复制到assets/data目录下,我们继续编程
public
class
LoadSceneTest
extends
GdxTest
implements
ApplicationListener {
...
@Override
public
void
create () {
...
assets =
new
AssetManager();
assets.load(
"data/invaders.g3db"
, Model.
class
);
loading =
true
;
}
private
void
doneLoading() {
Model model = assets.get(
"data/invaders.g3db"
, Model.
class
);
ship =
new
ModelInstance(model,
"ship"
);
ship.transform.setToRotation(Vector3.Y,
180
).trn(
0
,
0
, 6f);
instances.add(ship);
for
(
float
x = -5f; x <= 5f; x += 2f) {
ModelInstance block =
new
ModelInstance(model,
"block"
);
block.transform.setToTranslation(x,
0
, 3f);
instances.add(block);
blocks.add(block);
}
for
(
float
x = -5f; x <= 5f; x += 2f) {
for
(
float
z = -8f; z <= 0f; z += 2f) {
ModelInstance invader =
new
ModelInstance(model,
"invader"
);
invader.transform.setToTranslation(x,
0
, z);
instances.add(invader);
invaders.add(invader);
}
}
space =
new
ModelInstance(model,
"space"
);
loading =
false
;
}
...
}
在create()方法中我们删除了其它模型载入。换上了invaders.g3db;在doneLoading()方法中,我们从assetmanager获取该模型。并创建ModelInstances,參数为model和创建FBX时所使用的名称。以后我们会深入解说。但如今让我们执行它。看看它的全然和曾经一样。这是非常实用的。由于我们能够把全部模型放在一个场景中。并且ModelInstances仅仅载入一个模型。因此能够共享资源,并且这使得ModelBatch(稍后详述)性能提升。当然,假设须要的话,你仍然能够使用多个文件,事实上有时(如与皮肤或动画模型)使用一个单独的文件更方便。
4.让我们回到模型应用程序,并打开我们之前创建的场景。如今改动ship模型,绕Y轴旋转180度。并把沿Z轴移动6格,就像在java中做的一样。接着改动block模型。把它在Z轴移动3格,X轴移动-5格,然后重命名其为block1。改动invader模型,X轴移动-5格,重命名为invader1;复制block1五次,依次以X轴2格间距摆放。如今一共同拥有6个block,重命名其为block1-block6;再按上步同一方法复制invader1,得到下图:
注意:网格间距5个单位。
5.仍然使用fbx-conv转换,然后载入场景
public
void
create () {
...
assets =
new
AssetManager();
assets.load(
"data/invaderscene.g3db"
, Model.
class
);
loading =
true
;
}
private
void
doneLoading() {
Model model = assets.get(
"data/invaderscene.g3db"
, Model.
class
);
for
(
int
i =
0
; i < model.nodes.size; i++) {
String id = model.nodes.get(i).id;
ModelInstance instance =
new
ModelInstance(model, id);
Node node = instance.getNode(id);
instance.transform.set(node.globalTransform);
node.translation.set(
0
,
0
,
0
);
node.scale.set(
1
,
1
,
1
);
node.rotation.idt();
instance.calculateTransforms();
if
(id.equals(
"space"
)) {
space = instance;
continue
;
}
instances.add(instance);
if
(id.equals(
"ship"
))
ship = instance;
else
if
(id.startsWith(
"block"
))
blocks.add(instance);
else
if
(id.startsWith(
"invader"
))
invaders.add(instance);
}
loading =
false
;
}
取得invaders模型,遍历节点得到每一个节点的id,然后使用model和id建立ModelInstance;
设置ModelInstance的转换(通常是读取在模型应用程序中改动的旋转和平移等)。然后我们重置节点的转换信息。由于如今我们能够直接读取ModelInstance中存放的信息。重置的方法例如以下:
translation为(0,0,0);scale为(1,1,1);rotation shiyong idt();最后调用calculateTransforms()使ModelInstance被更新。(这段翻译可能不太对。原文例如以下)
Next we set the transformation of the ModelInstance to the transformation of the node. Practically this reads the transformation (like rotation and translation) we set earlier within the modeling application. Then we need to reset the node’s transformation,
because we now use the ModelInstance transform. For translation this is (0,0,0), for scale this is (1,1,1) and for rotation we set the quaternion to identity. This is followed by a call to calculateTransforms() to make sure the ModelInstance is updated with
these new values.把不是space的ModelInstance都增加到array中,使其得到渲染,然后把ship、lobck、incader各增加其array中。
大功告成!
libgdx3D第三讲-场景载入的更多相关文章
- HoloLens开发手记 - Unity之Persistence 场景保持
Persistence 场景保持是HoloLens全息体验的一个关键特性,当用户离开原场景中时,原场景中全息对象会保持在特定位置,当用户回到原场景时,能够准确还原原场景的全息内容.WorldAncho ...
- [Unity3D]Unity3D游戏开发之异步记载场景并实现进度条读取效果
大家好,我是秦元培.欢迎大家关注我的博客,我的博客地址是:blog.csdn.net/qinyuanpei.终于在各种无语的论文作业中解脱了,所以立即抓紧时间来这里更新博客.博主本来计划在Unity3 ...
- Unity多个场景叠加或大场景处理方法小结
本文章由cartzhang编写.转载请注明出处. 全部权利保留. 文章链接: http://blog.csdn.net/cartzhang/article/details/47614153 作者:ca ...
- WEBGL学习【十五】利用WEBGL实现三维场景的一般思路总结
实现三维场景载入操作的实现步骤: 主要知识点:着色器,纹理贴图,文件载入 实现思路: 获取canvas,初始化WEBGL上下文信息. 主要是实现WEBGL上下文的获取,设置视的大小,此时gl存储了WE ...
- SOSO街景地图 API (Javascript)开发教程(1)- 街景
SOSO街景地图 Javascript API 干什么用的? 你想在网页里嵌入个地图,就需要它了! 另外,它还支持:地点搜索.周边/附近查询.地图标注.公交/驾车路线规划.地理坐标与地址相互转换.地理 ...
- 游戏世界之Unity3D的基础认识
1.写在前面 Unity3D是由Unity Technologies开发的一个让你轻松创建诸如三维视频游戏.建筑可视化.实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏 ...
- Unityclient通信測试问题处理(二)
Unityclient通信測试问题处理(二) 在client的通信測试过程中.场景载入的问题给自己带来了不小的麻烦.由于消息的解析方法在单独的监听线程中调用,这也就意味着无法在消息的解析方法中调用Un ...
- DontDestroyOnLoad(Unity3D开发之五)
Unity中我们从A场景切换到B场景的时候,A场景全部对象都会销毁,但有时候我不须要销毁某些东西. 比方一个简单的游戏的背景音乐,我不须要多次反复创建,多个场景播放这一个即可了.这个时候就须要用到Do ...
- 于Unity3D动态创建对象和创建Prefab三种方式的原型对象
于Unity3D动态创建对象和创建Prefab三种方式的原型对象 u3d在动态创建的对象,需要使用prefab 和创建时 MonoBehaviour.Instantiate( GameObject o ...
随机推荐
- C#基本功之委托和事件
定义:委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用. 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联 目的:方法声明和方法实现的分离,使得程序更容易扩展 一 ...
- linux使用yum的方式安装mysql实践
1.先检测是否已安装mysql ps -ef|grep mysql root : pts/ :: /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mys ...
- 大话git中的撤销操作
下面以现实场景作为情境. 基础知识,理解git中的几个区域 本地代码已经add,未commit 修改本地工作目录中的readme.md,添加文字"第一次修改" 然后查看下状态 ➜ ...
- [转载] Java NIO教程
转载自并发编程网 – ifeve.com http://ifeve.com/java-nio-all/ 关于通道(Channels).缓冲区(Buffers).选择器(Selectors)的故事. 从 ...
- [转]Oracle 重建索引的必要性
http://blog.csdn.net/leshami/article/details/23763963 索引重建是一个争论不休被不断热烈讨论的议题.当然Oracle官方也有自己的观点,我们很多DB ...
- javaweb-2-Tomcat初步学习与使用
一.Tomcat服务器简介(此点网上官方有详尽的解释,故此不赘述,以学习使用为主) Apache Jakarta的开源项目 JSP/Servlet容器 二.Tomcat的目录结构 三.启动和停止Tom ...
- js实际工作中的技能点
1.基础知识 a.原型,原型链 b.作用域,闭包 c.异步,单线程 2.JS API a.DOM操作 b.Ajax c.事件绑定 3.开发环境 a.版本管理(git) b.模块化(require.js ...
- IBM的websphere MQ的c#使用
1.关于websphere MQ的常用名词(针对Websphere MQ7.5版本) 队列管理器:为应用程序提供消息传递服务的程序.使用消息队列接口(MQI)的应用程序可以将消息放置到队列并可从队列中 ...
- Serializable 都这么牛逼了,Parcelable 还要你何用?
一些闲聊 距离上一篇文章似乎又是很久了,看起来也没有很多反馈,催更就更不用说了.哈哈,放弃了. 话说最近公司在招聘一批至少 5 年开发经验的 Android 开发工程师,我也是忙开了花,激动得不行呀. ...
- python网络编程之单线程之间的并发
单线程之间的并发就是利用一个线程实现并发的效果,也就是利用了cup遇到阻塞的那段时间去做别的事情,从而提高了cup的利用率,使之在单个线程中就实现了并发的效果. 下面就是一个简单的服务端单个线程实现并 ...