网站建设设计计划表怎么查询搜索关键词
文章目录
- 前言
- 一、ArcGIS如何加载GLTF
- 1.JavaScript 代码
- 2. 结果
- 二、ThreeJS使用
- 三、ArcGIS场景基于ThreeJS加载GLTF
- 1. 编写RenderNode引入代码
- 2.调用RenderNode
- 3、结果
- 四 、总结
前言
通常我们在Web端三维场景中看到的动态模型一般都为GLTF或者GLB模型(GLB是GLTF的二级制心态)。而GLTF模型有分为带骨骼动画和不带骨骼动画两种形态。而上面或到的动态效果就是只带有骨骼动画的GLTF。
对于ArcGIS For JavaScript而言,目前可以通过符号化三维对象的方式去加载GLTF,但是在符号化的过程中无法去设置开启GLTF的动画参数,所以不管是骨骼模型还是普通模型,加载出来都只能看到静态的效果。在文章《03-ArcGIS For JavaScript结合ThreeJS功能》的时候,讲过RenderNode可以将ThreeJS的效果集中到ArcGIS的场景中,所以这里就介绍一下ArcGIS中通过ThreeJS去加载带有骨骼动画的GLTF模型。
一、ArcGIS如何加载GLTF
1.JavaScript 代码
首先看一下ArcGIS For JavaScript中如何加载GLTF。
<!doctype html>
<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /><title>Import glTF 3D Models | Sample | ArcGIS Maps SDK for JavaScript 4.32</title><link rel="stylesheet" href="https://js.arcgis.com/4.32/esri/themes/light/main.css" /><script src="https://js.arcgis.com/4.32/"></script><style>html,body,#viewDiv {padding: 0;margin: 0;height: 100%;width: 100%;}#paneDiv {padding: 10px;max-width: 200px;background-color: rgba(255, 255, 255, 0.8);font-size: 1.1em;}#credits {font-size: 0.7em;line-height: 1.1em;}</style><script>require(["esri/views/SceneView","esri/Map","esri/layers/GraphicsLayer","esri/Graphic","esri/geometry/Point"], (SceneView, Map, GraphicsLayer, Graphic, Point) => {let scene = new Map({basemap: 'satellite'})const view = new SceneView({container: "viewDiv",map: scene,camera: {heading: 359.20366065537,fov: 55,tilt: 1.2342814547871352,position: {latitude: 39.90281086554516,longitude: 116.37414026811818,z: 1445.7247159378603}}});const graphicsLayer = new GraphicsLayer({elevationInfo: { mode: "on-the-ground" }});scene.add(graphicsLayer);view.when(() => {let symbol = {type: "point-3d",symbolLayers: [{type: "object",resource: {href: "https://developers.arcgis.com/javascript/latest/sample-code/import-gltf/live/tent.glb"},width: 100,hight:100}]};let point = new Point({latitude: 39.903718309815375,longitude: 116.37175217665084,z: 60});let graphic = new Graphic({geometry: point,symbol})graphicsLayer.add(graphic);})});</script>
</head>
<body><div id="viewDiv"></div>
</body>
</html>
2. 结果
二、ThreeJS使用
ThreeJS的使用方式可以参考前面《03-ArcGIS For JavaScript结合ThreeJS功能》
三、ArcGIS场景基于ThreeJS加载GLTF
1. 编写RenderNode引入代码
renderNodeClass.js
let RenderNodeClass = {constructor(options) {this.webgl = options.webgl;this.view = options.view;this.mixer = null;this.horseMixer = null;this.clock = null;this.horseClock = null;},setParams() {this.isStop = !this.isStop;},initialize() {let THREE = window.THREE;// this.mixer = new THREE.AnimationMixer();this.horseMixer = THREE.AnimationMixer;this.clock = new THREE.Clock();this.horseClock = new THREE.Clock();this.mixer = THREE.AnimationMixer;this.renderer = new THREE.WebGLRenderer({context: this.gl, // 可用于将渲染器附加到已有的渲染环境(RenderingContext)中premultipliedAlpha: false, // renderer是否假设颜色有 premultiplied alpha. 默认为true});this.renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比。通常用于避免HiDPI设备上绘图模糊this.renderer.setViewport(0, 0, this.view.width, this.view.height); // 视口大小设置this.renderer.autoClear = false;this.renderer.autoClearDepth = false;this.renderer.autoClearColor = false;// this.renderer.autoClearStencil = false;let originalSetRenderTarget = this.renderer.setRenderTarget.bind(this.renderer);let that = this;this.renderer.setRenderTarget = function (target) {originalSetRenderTarget(target);if (target == null) {that.bindRenderTarget();}};this.scene = new THREE.Scene();// setup the cameralet cam = this.camera;this._camera = new THREE.PerspectiveCamera(cam.fovY, cam.aspect, cam.near, cam.far);// 添加坐标轴辅助工具const axesHelper = new THREE.AxesHelper(1);axesHelper.position.copy(1000000, 100000, 100000);this.scene.add(axesHelper);let grid = new THREE.GridHelper(30, 10, 0xf0f0f0, 0xffffff);this.scene.add(grid);// setup scene lightingthis.ambient = new THREE.AmbientLight(0xffffff, 0.5);this.scene.add(this.ambient);this.sun = new THREE.DirectionalLight(0xffffff, 0.5);this.sun.position.set(-600, 300, 60000);this.scene.add(this.sun);window.gltf = null;const loader = new THREE.GLTFLoader();loader.load('Horse.glb', function (gltf) {console.log('gltf', gltf);gltf.scene.scale.set(10.8, 10.8, 10.8)that.scene.add(gltf.scene);gltf.scene.position.set(12956671.47026511,4851275.366457126, 10);gltf.scene.rotateX(Math.PI / 2);that.mixer = new THREE.AnimationMixer(gltf.scene);// obj.animations[0]:获得剪辑对象clipvar AnimationAction = that.mixer.clipAction(gltf.animations[0]);window.gltf = gltf;// AnimationAction.timeScale = 1; //默认1,可以调节播放速度// AnimationAction.loop = THREE.LoopOnce; //不循环播放// AnimationAction.clampWhenFinished = true;//暂停在最后一帧播放的状态AnimationAction.play();//播放动画});// this.getCoords(context);this.resetWebGLState();},/*** 渲染器更新渲染* @memberof BuildingEffect* @method render* @param {Object} context 已有渲染器信息,无需传值*/render(context) {let THREE = window.THREE;let cam = this.camera;//需要调整相机的视角this._camera.position.set(cam.eye[0], cam.eye[1], cam.eye[2]);this._camera.up.set(cam.up[0], cam.up[1], cam.up[2]);this._camera.lookAt(new THREE.Vector3(cam.center[0], cam.center[1], cam.center[2]));// Projection matrix can be copied directlythis._camera.projectionMatrix.fromArray(cam.projectionMatrix);if (this.mixer && this.mixer.update) {// 更新混合器相关的时间, clock.getDelta()方法获得两帧的时间间隔this.mixer.update(this.clock.getDelta());}this.renderer.state.reset();this.bindRenderTarget();this.renderer.render(this.scene, this._camera);// as we want to smoothly animate the ISS movement, immediately request a re-renderthis.requestRender();// cleanupthis.resetWebGLState();}
}
2.调用RenderNode
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="./jquery/jquery-1.12.3.min.js"></script><script src="./threejs/three.min.js"></script><script src="./threejs/GLTFLoader.js"></script><script src="./renderNodeClass.js"></script><link rel="stylesheet" href="https://js.arcgis.com/4.32/esri/themes/light/main.css" /><script src="https://js.arcgis.com/4.32/"></script><style>body,html,#viewDiv {padding: 0;margin: 0;height: 100%;width: 100%;}</style></script><script>require(['esri/Map','esri/views/SceneView',"esri/geometry/Mesh","esri/Graphic","esri/geometry/Point","esri/geometry/Polyline","esri/layers/GraphicsLayer","esri/geometry/operators/densifyOperator","esri/Camera","esri/views/3d/webgl/RenderNode","esri/views/3d/webgl"], (Map, SceneView, Mesh, Graphic, Point, Polyline, GraphicsLayer, densifyOperator, Camera, RenderNode,webgl) => {let graphicLayer = new GraphicsLayer();let map = new Map({layers: [graphicLayer],basemap: 'satellite'})let view = new SceneView({container: 'viewDiv',viewingMode:'local',map,camera: {heading: 46.490512697555566,tilt: 65.03077172871896,position: {// longitude: 116.37280650987242,// latitude: 39.88099012247863,x: 12956520.797315104,y: 4851088.587867753,z: 127.55169651366651,spatialReference: {wkid: 102100}}}})let subRenderClass = RenderNode.createSubclass(RenderNodeClass);view.when(function(){new subRenderClass({view,webgl})})})</script>
</head><body><div id="viewDiv"></div>
</body></html>
3、结果
这里面主要在使用ThreeJs的时候引入了GLTFLoader.js用于加载gltf文件,并且调用that.mixer = new THREE.AnimationMixer(gltf.scene)去启动动画效果,在render中实时更新就能看到动态的模型。
四 、总结
在ArcGIS场景中使用ThreeJS得时候,只能通过设置viewingMode=‘local’的方式去加载,及只能在平面效果上看,如果设置为global或出现因为坐标轴不一致导致的模型位置和旋转问题。