导入一个3D模型文件是一个3D引擎必不可少的功能,我们可以用多种方式实现3D模型文件的导入,本文将告诉大家在Scene3D引擎中如何加载3D模型文件。
一.准备工作
1.AppInventor平台(本文所使用的平台为wxbit)
2.Scene3D主程序
3.Scene3D核心插件包
4.Scene3D模型导入插件
5.3D模型及纹理贴图
本文的目标将是成功加载如图所示中的所有文件
其中所使用到的AIX拓展包均可在我的上一篇文章AppInventor 3D引擎Scene3D最详细入门教程(1)找到下载地址。
二.方法/步骤
1.先将所下载的三个拓展包导入,如图将会出现9个拓展
2.将如图所示的拓展组件拖入程序并拖入一个水平布局宽度高度设为充满,以此来充当3D世界的显示器。
建议再放置一个按钮做调试
3.首先,在Scene3D中,表现一个3D对象表面的色彩的信息叫做纹理(texture),纹理可以是图片,也可以是纯颜色,特别地,如果是图片作为的纹理又称作贴图(map)。
现在,我们需要定义一个添加纹理的函数,在Scene3D中,Texture是有关纹理的拓展组件,同时Texture也是一个纹理对象。TextureManager是一个管理纹理的拓展组件,如我们用CreateTexture函数创建好texture对象后需要用TextureManager拓展将纹理对象添加到纹理库,并且为纹理命名。在本篇文章中,我们需要加载一个3D模型,并为其加载贴图。由于手机的内存是有限的,所以我们需要导入的贴图一般也不会太大,我们希望的是通过一个给定的纹理名称,图片路径,纹理的大小实现创建并导入纹理到TextureManager中。注意:由于一些原因,在Scene3D中目前仅支持尺寸大小为2的整数次方的正方形的贴图,如64×64,128×128,256×256。
相关块介绍:
如下图,位于Texture拓展中包含了几个用于创建材质对象的块,其中CreateTextureByPicture块是较常用的块用于通过图片创建一个纹理对象,并自带图片压缩的参数,CreateTexture_1所创建的纹理对象使用贴图自身的尺寸大小,CreateTexture_0所创建的纹理对象是前者的useAlpha值设为来ture的版本。
如下图,是位于TextureManager组件中的几个块,AddTexture_1是我们较常用到的一个块,用于将纹理对象添加至纹理库中,并为其起个名字,ContainsTexture块是查找纹理库中是否存在指定名字的纹理,Flush块用于清空整个材质库。
之前提到,我们希望的是通过一个给定的纹理名称,图片路径,纹理的大小实现创建并导入纹理到TextureManager中。所以创建如下函数:
4.导入OBJ模型文件
首先,明确obj文件的概念:
OBJ文件是Wavefront公司为它的一套基于工作站的3D建模和动画软件"Advanced Visualizer"开发的一种文件格式,这种格式同样也以通过Maya读写。
OBJ文件是一种文本文件,可以直接用写字板打开进行查看和编辑修改。
如图,我们将camaro.mtl、camaro.obj、camaro.jpg导入素材库中,
使用如图的代码块做实验了解3D模型文件加载器Loader组件中的OBJ加载器LoadOBJ的返回结果是什么。
返回结果如图所示:
由上图结果可知,返回结果是一个列表,其中存放了若干个3D对象
我们将以上3D模型导入至世界中去观察一下,代码块如下图所示
代码块详解:
OnSurfaceCreated事件即Scene3D世界创始之初的初始化操作,
首先需要加载我们需要的Scene3D子插件,
Flush清空内存中未释放的材质,
在世界的原点创建了一个点光源,
调用LoadOBJ函数加载了3D模型输出的列表通过MergeAll合并为一个大3D对象(类似于Excel中的合并单元格或appinventor中的布局)
将大的3D对象添加到世界中,
用3D对象控制器绑定当前3D对象使其平移到手机屏幕前方5个单位长度(Scene3D的坐标系统采用右手坐标系统,即appinventor画布对应的x,y轴方向,z轴垂直屏幕向里)。
手机界面如图所示:
为了方便360度全方位观看3D模型,我们需要在3D显示布局里添加一个充满布局的画布用于捕获手势,代码块如图所示:
这样便成功可以用手势控制3D模型的旋转了
这便成功加载了OBJ的3D模型文件,下一步将为其添加纹理。
5.为OBJ文件添加纹理
调试查看当前材质库有何材质,代码块如下:
显示结果如下:
由图可知,当前纹理库共有两个纹理,名称分别为--dummy--和camaro.jpg其中--dummy--是Scene3D默认自带的纹理,是个纯白色的纹理,camaro.jpg是我们在导入OBJ文件时导入的mtl材质文件中记载的纹理信息,在Scene3D中mtl文件的导入仅会导入贴图名称和颜色信息,具体的贴图文件需要我们自己设置,代码如图,我们仅需在初始化阶段加载如图代码块来替换纹理,然后我们设置3D对象的纹理名即可
现在我们就成功设置了纹理贴图,大家可能会有疑问,为什么车轮的位置这么诡异,实际上,之前我们导入OBJ文件时返回的是一个列表,其中有5个3D对象,其实是有4个车轮和一个车身所组成的,那么我们接下来的目标就是调整车轮的位置。
6.调整车轮位置
首先我们需要了解OBJ文件的结构,我们尝试打开obj文件,如图所示
我们会发现OBJ其实就是一个ASCII编码的文本文件,是可以直接被阅读的,其中直接以文本形式记载了一个3D模型的顶点,法向量等数据,并且可以放置多个3D对象,每个3D对象以o打头,后跟该3D对象的名称,我们想要分别获取车身和四个车轮。
在3D对象控制器中可以获取某个3D对象的名称,封装为函数如图所示,
注意:由于引擎在世界控制器WorldHandler存在有GetObject3DByName块,用于通过名称获取3D世界中的3D对象,所以尽量不要使两个相同世界中的不同的3D对象使用同一name值,以防止意外情况发生,在Scene3D引擎中,每生成一个3D对象,都有一个ID值与其对应,默认导入的Name将会以"obj文件中3DdD对象名_JPCT+ID"来命名,使用纯代码创造的3D模型将以“object+ID”形式命名。
所以,我们将通过如图的代码选择出车身和车轮的Object3D对象并删除之前的合并对象的代码(前左为lf,前右为rf,后左为lr,后右为rr)
添加一个函数,方便设置车轮的位置
添加一个函数,用于将若干个3D对象与一个3D对象绑定,成为3D对象的一部分(子对象或孩子),将会继承父对象的所有变换
如图的代码块,设置了四个车轮的坐标(局部坐标),并且将车轮作为车身的一个子对象(孩子),然后将所有对象添加至世界中,至此整个OBJ模型文件完美导入。
运行结果:
7.添加车轮动画
至此,OBJ模型文件的导入已讲解完毕,那么可能会有人问了,为什么3D建模工具在完成模型的创建后不直接把所有的模型合并呢?其实,将模型的零部件分离是有许多好处的,比如我们本节要讲解车轮动画。
通过如图的代码,我们可以控制前轮的旋转
通过如图所示的代码,我们可以控制车轮的转动