- 快速入门
- 动画
- Picking 拾取
- 转换COLLADA为glTF
- Troubleshooting 故障排除
- 资源
- 视频总结
- 作业
5 - 3D Models 三维模型
本教程将教您如何通过Primitive API转换、加载和使用Cesium中的三维模型。如果你是Cesium的新用户,可能需要阅读三维模型部分的(空间数据可视化教程)[https://cesium.com/docs/tutorials/creating-entities#3d-models],本系列教程中叫:”空间数据可视化“。
Cesium支持3D模型,包括关键帧动画、skinning(贴皮?)和独立节点选取,使用glTF,这是由Khronos Group(WebGL和COLLADA背后的联合体)为网络上的3D模型开发的一种新兴行业标准格式。Cesium还提供了一个基于网络的工具,将COLLADA模型转换为glTF,以便与Cesium一起优化使用。
快速入门
Cesium包括一些现成的二进制gLTF模型:
- 一个带有动画螺旋桨的飞机
- 带有动画车轮的地面车辆
- 带有皮肤周期行走的角色
- 热气球
- 一辆牛奶车(还包括Draco-compressed格式的牛奶车)
这些模型在Apps/SampleData/models中都有自己的目录。大多数将包括原始COLLADA文件(.dae)、glTF文件(.gltf)和/或 二进制glTF文件(.glb)。在Cesium应用程序中不需要使用原始的COLLADA文件。
让我们编写代码来加载这些模型。打开http://111.22.69.99:58080/cesium/Apps/Sandcastle的Hello World示例。在第4行var viewer=...下,添加一个scene变量。
var scene = viewer.scene;
接下来,通过添加以下代码,使用glTF中的cesium.model加载地面车辆模型。
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(-75.62898254394531, 40.02804946899414, 0.0));
var model = scene.primitives.add(await Cesium.Model.fromGltfAsync({
url : 'http://111.22.69.99:58080/cesium/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb',
modelMatrix : modelMatrix,
scale : 200.0
}));
viewer.scene.primitives.add(model);
var destination = Cesium.Cartesian3.fromDegrees(
-75.62898254394531,
40.02804946899414,
10000
);
viewer.camera.flyTo({
destination: destination,
});
运行文件,找到车载模型。
我们现在直视地面车辆。我们可以用鼠标右键拖动放大,用鼠标中键拖动倾斜视图。
cesium.Model.fromGltf异步加载glTF模型,包括任何外部文件,并在完全加载后渲染该模型一次,从而解析readyPromise。只需要.gltf文件的URL,在本例中为http://111.22.69.99:58080/cesium/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb。
scale作为可选参数提供给fromGltf用于放大模型。许多真实大小的模型也可以变小。所以使用一个较大的scale数值来第一次测试模型是有益的,比如200000.0,示例如下:
modelMatrix也提供给从fromGltf定位和旋转模型。这将为模型创建局部坐标系。这里,Cesium.Transforms.eastnorthupfixedframe用于创建一个本地的东北向上坐标系,其原点为经度*-75.62898254394531度,纬度40.02804946899414*度。可以随时更改模型的modelMatrix属性以移动模型。
要可视化坐标系,请使用Cesium Inspector,在第4行*var viewer=...*下的任意位置添加以下代码:
viewer.extend(Cesium.viewerCesiumInspectorMixin);
单击F8,inspector界面将出现在左上方。展开Primitives,点击Pick a Primitive,点击地面上的车辆模型,然后确认show reference frame。
此处: x轴(东)是红色的,y轴(北)是绿色的,以及z(向上)是蓝色的。
我们可以使用相同的代码来加载飞机或角色模型,只需更改URL传递给fromGltf的为“http://111.22.69.99:58080/cesium/Apps/SampleData/models/cesiumAir/Cesium-Air.glb” 或 “http://111.22.69.99:58080/cesium/Apps/SampleData/models/Cesium%20Man/Cesium-Man.glb” 。有关其所有选项,请参阅Cesium.Model.fromGltf的参考文档。
动画
这些模型中的每一个模型都有内置的动画,这些动画是由一个艺术家(比如,一个艺术家通过定义几个关键姿势创建了一个动画),Cesium在运行时进行插值以创建平滑的动画。
要播放动画,请在调用Cesium.Model.fromGltf后添加以下代码。
model.readyEvent.addEventListener(() => {
model.activeAnimations.add({
index: animations.length - 1,
loop: Cesium.ModelAnimationLoop.REPEAT,
speedup: 0.5,
reverse: true,
multiplier: 0.5,
});
});
由于动画存储在glTF模型中,因此我们需要等待readyPromise解决后再访问它们。addAll用于播放模型中的所有动画。Cesium.ModelAnimationLoop.REPEAT循环动画,直到将其从activeAnimations集合中移除。要播放特定的动画,请改用add,并提供动画的id(glTF JSON属性名)。
除循环选项之外,addAll和add还提供了许多选项来控制动画的开始和停止时间、速度和方向。例如,下面的动画以半速(相对于Cesium clock)和反向运转。
model.activeAnimations.addAll({
loop : Cesium.ModelAnimationLoop.REPEAT,
speedup : 0.5,
reverse : true
});
add返回ModelAnimation对象(addAll返回这些对象的数组),其中包含动画开始、停止和更新每个帧时的事件。例如,这允许,相对于另一个动画启动一个动画。请前往API文档查看开始start、停止stop和更新update事件。
动画与Cesium clock同步,因此要查看它们,请按播放小部件上的播放。可以使用时间线和播放小部件来增加、减少和反转动画的速度。
要将应用程序配置为自动播放动画,请初始化如下查看器:
var viewer = new Cesium.Viewer('cesiumContainer', {
shouldAnimate : true
});
Picking 拾取
与所有Cesium primitives一样,如果选择了模型,Scene.Pick将返回一个模型作为其结果的一部分。此外,还返回了glTF节点和glTF网格的id(JSON属性名),从而可以精确地拾取不同的模型部件。以下示例在控制台窗口中的鼠标光标下显示节点和网格名称。
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(
function (movement) {
var pick = scene.pick(movement.endPosition);
if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
console.log('node: ' + pick.node.name + '. mesh: ' + pick.mesh.name);
}
},
Cesium.ScreenSpaceEventType.MOUSE_MOVE
);
转换COLLADA为glTF
为了完全转换COLLDA模型到glTF格式供Cesium使用,可以使用web-based COLLADA-to-glTF或collada2gltf.exe转换器。该工具能够将*.dae文件和图像文件转换为嵌入图像的.gltf*文件。
Troubleshooting 故障排除
如果在Cesium中加载3D模型时出现问题,请首先确定问题所在。问题可能出现在:
- 模型工具的导出器,比如:Maya,Modo,ShetchUp等等
- COLLADA-to-glTF转换工具
- Cesium glTF渲染器
Mac下的故障排除
在Mac上,要确定是否正确导出了COLLADA文件,请双击*.dae*文件,该文件应显示在预览窗口中。如果模型有动画,鼠标悬停在窗口底部会弹出一个工具栏来播放它们。
如果collada文件无效,预览将显示错误。这通常表示COLLADA导出器中存在用于创建collada文件的错误。
要解决此问题,请安装xcode,然后右键单击*.dae文件并选择Open With“打开方式”*->xcode。
Xcode显示的模型类似于预览,但具有更多的功能,如选择单个节点的能力。Xcode还为无效的COLLADA文件实现了许多解决方法,因此它通常可以加载和预览无法加载的collada文件。如果模型在Xcode中加载,请选择“文件-保存”以将模型与解决方法一起保存,然后应在“预览确定”中加载。
如果在预览中仍然没有加载,那么COLLADA导出器有问题。确保您拥有最新版本的建模工具,并尝试本文中的提示。如果仍然不起作用,请向建模工具(而不是Cesium)提交一个bug。也值得尝试导出为*.fbx*或其他格式,然后导入到另一个具有更好的COLLADA导出器的建模工具中。
Windows下的故障排除
在Windows下,Visual Studio2013 包括免费的社区版的模型编辑器,可以加载COLLADA模型。为了确定COLLADA文件是否被正确导出,将*.dae*文件拖拽近Visual Studio然后它被加载。如果没有加载,这通常意味着COLLADA导出器存在bug。确保您拥有最新版本的建模工具,并尝试本文中的提示。如果仍然不起作用,请向建模工具(而不是Cesium)提交一个bug。它也值得尝试导出为.fbx或其他格式,然后导入到另一个具有更好的COLLADA导出器的建模工具中。
如果没有Visual Studio,则Autodesk有一个允许拖放的WebGL查看器,并且不需要登录。查看器不支持动画。如果模型中有图像,请上传包含.dae和图像文件的zip包。
Cesium中的故障排除
一旦我们有了一个有效的COLLADA文件,就通过COLLADA-to-glTF转换器运行它,然后尝试将其加载到Cesium中。如果没有加载到Cesium中或显示不正确,则转换器或Cesium中存在错误。要获取更多详细信息,请打开浏览器的开发人员工具(chrome中的ctrl-shift-i)并启用ause on all exceptions(chrome中的Sources选项卡),然后重新加载Cesium应用程序。
向Cesium论坛发一条信息,我们通常可以提供一个解决方案,直到有修复方案。在您的帖子中,请包括:
- 原始的COLLADA和转换的glTF文件。我们认识到并不是每个人都可以分享他们的模型,但是如果可以的话,它会极大地提高我们的帮助能力。
- 浏览器的控制台窗口以及加载模型时引发的任何异常,例如
资源
查看http://111.22.69.99:58080/cesium/Apps/Sandcastle中的3D模型示例以及Model和ModelAnimationCollection的参考文档。
视频总结
Cesium加载GLTF数据:
(1)GLTF数据介绍:
1,scene: glTF格式的场景结构描述条目。它通过引用node来定义场景图;
2,node: 场景图层次中的一个节点。它可以包含一个变换(比如旋转或平移),并且可以引用其他(子)节点 。此外,它可以引用网格和相机,以及描述网格变换的蒙皮;
3,camera: 定义了用于渲染场景的视锥体配置;
4,mesh: 描述了出现在场景中几何对象实际的几何数据。它是指accessor用于访问实际几何数据material的对象,并且是指在渲染对象时定义其外观的 ;
5,skin: 定义了用于蒙皮的参数,参数的值通过一个accessor对象获得。
6,animation: 描述了一些结点如何随时间进行变换(比如旋转或平移);
7,accessor: 一个访问任意数据的抽象数据源。被mesh、skin和animation元素使用来提供几何数据、蒙皮参数和基于时间的动画值。它通过引用一个bufferView对象,来引用实际的二进制数据;
8,material: 包含了定义3D对象外观的参数。它通常引用了用于3D对象渲染的texture对象;
9,texture: 定义了一个sampler对象和一个image对象。sampler对象定义了image对象在3D对象上的张贴方式。
(2)添加GLTF数据代码:
GLTF加载可以使用两种方式:一种添加entity,一种添加primitive。
// 添加GLTF数据源
async function addGLTF() {
viewer.entities.removeAll()
const position = Cesium.Cartesian3.fromDegrees(
120, 45
)
const heading = Cesium.Math.toRadians(0)
const pitch = 0
const roll = 0
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
)
// 第一种方式:通过enitity方式
const entity = viewer.entities.add({
name: "ferrari.glb",
position: position,
orientation: orientation,
model: {
uri: "ferrari.glb",
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小
scale: 1, // 缩放比例
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
runAnimations: true, // 指定是否应运行 glTF 动画
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE // 表示相对于地形的位置。NONE表示绝对位置
}
})
viewer.trackedEntity = entity
// 第二种方式:通过primitive方式
// 加载调试primitive和地形的工具
viewer.extend(Cesium.viewerCesiumInspectorMixin)
const origin = Cesium.Cartesian3.fromDegrees(120, 46)
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin)
const model = await Cesium.Model.fromGltfAsync({
url: 'ferrari.gltf',
modelMatrix, // primitive只能通过模型矩阵方式加载位置
scale: 1, // 缩放比例
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE // 表示相对于地形的位置。NONE表示绝对位置
})
viewer.scene.primitives.add(model)
}
addGLTF()
(3)添加有颜色的GLTF数据代码:
color:模型颜色。
colorBlendMode:颜色混合模式。HIGHLIGHT、MIX、REPLACE
colorBlendAmount:控制颜色混入的程度。
silhouetteColor:线框颜色。
silhouetteSize:模型边框大小。
// 添加有颜色的GLTF数据代码
const position = Cesium.Cartesian3.fromDegrees(
120, 45
)
const heading = Cesium.Math.toRadians(0)
const pitch = 0
const roll = 0
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
)
// 第一种方式:通过enitity方式
const entity = viewer.entities.add({
name: "ferrari.glb",
position: position,
orientation: orientation,
model: {
uri: "ferrari.glb",
minimumPixelSize: 128,
maximumScale: 20000,
scale: 1, // 缩放比例
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
runAnimations: true, // 指定是否应运行 glTF 动画
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE, // 表示相对于地形的位置。NONE表示绝对位置
color: Cesium.Color.RED, // 与模型的渲染颜色混合的颜色
colorBlendMode: Cesium.ColorBlendMode.MIX, // 颜色混合模式,HIGHLIGHT、MIX、REPLACE
colorBlendAmount: 0.3, // colorBlendMode是MIX时有效,控制颜色混入的程度
silhouetteColor: Cesium.Color.WHITE.withAlpha(0.5), // 白色线框,模型边框的颜色
silhouetteSize: 5 // 模型边框大小
}
})
viewer.trackedEntity = entity
作业
使用entity和primitive两种方式加载飞机模型,并且使用滑动条调整颜色。