通过cesium官网文章可以得知二者结合使用的方法
提前准备内容
- node环境 (案例版本14.17.2)
- 创建vue项目
- 安装cesium依赖 (案例版本1.73.0)
- 安装three.js依赖(案例版本0.155.0)
功能以及实现方法
1创建标签
<div class="container-integrate" style="">
<!--cesium容器-->
<div id="cesiumContainer" style="height: 100%;width: 100%;"></div>
<!-- three.js场景 -->
<div id="ThreeContainer"></div>
</div>
2.初始化参数
// 声明变量
// 存储 three对象
let three = {
renderer: null,
camera: null,
scene: null,
};
// 存储cesium对象
let cesium = {
viewer: null,
};
// 模型定位范围,用来吧模型添加到这个执行为止
let minWGS84 = [115.56936458615716, 39.284100766866445];
let maxWGS84 = [117.10745052365716, 41.107831235616445];
// 存储一下等待刷新的模型
let _3Dobjects = []; // 可以是任何Three.js对象网格
// cesium 容器
let cesiumContainer = document.getElementById("cesiumContainer");
功能函数
- 清空数据对象
_3DObject() {
//THREEJS 3DObject.mesh
this.threeMesh = null;
//location bounding box
this.minWGS84 = null;
this.maxWGS84 = null;
}
- 初始化cesium
initCesium() {
cesium.viewer = new Cesium.Viewer(cesiumContainer, {
useDefaultRenderLoop: false,
selectionIndicator: false,
homeButton: false,
sceneModePicker: false,
infoBox: false,
navigationHelpButton: false,
navigationInstructionsInitiallyVisible: false,
animation: false,
timeline: false,
fullscreenButton: false,
allowTextureFilterAnisotropic: false,
baseLayerPicker: false,
contextOptions: {
webgl: {
alpha: false,
antialias: true,
preserveDrawingBuffer: true,
failIfMajorPerformanceCaveat: false,
depth: true,
stencil: false,
anialias: false,
},
},
targetFrameRate: 60,
resolutionScale: 0.1,
orderIndependentTranslucency: true,
//加载底图
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url:
"https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",
}),
geocoder: false,
automaticallyTrackDataSourceClocks: false,
// creditContainer : "hidecredit", //注意:这里需要注释掉,否则会报找不到容器的问题
dataSources: null,
clock: null,
terrainShadows: Cesium.ShadowMode.DISABLED,
});
let center = Cesium.Cartesian3.fromDegrees(
(minWGS84[0] + maxWGS84[0]) / 2,
(minWGS84[1] + maxWGS84[1]) / 2 - 1,
200000
);
cesium.viewer.camera.flyTo({
destination: center,
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-60),
roll: Cesium.Math.toRadians(0),
},
duration: 3,
});
}
- 初始化three.js
initThree() {
let fov = 45;
let width = window.innerWidth;
let height = window.innerHeight;
let aspect = width / height;
let near = 1;
let far = 10 * 1000 * 1000;
three.scene = new THREE.Scene();
three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
three.renderer = new THREE.WebGLRenderer({ alpha: true });
let Amlight = new THREE.AmbientLight(0xffffff, 2);
three.scene.add(Amlight);
// 注意这里,直接把three容器(canvas 添加到 cesium中,在cesium的canvas之下),
// 这样的话,两个canvas才会重叠起来。
cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(
three.renderer.domElement
);
// ThreeContainer.appendChild(three.renderer.domElement);
var ThreeContainer = document.getElementById("ThreeContainer");
ThreeContainer.appendChild(three.renderer.domElement);
}
全部代码
<template>
<div class="container-integrate" style="">
<!--cesium容器-->
<div id="cesiumContainer" style="height: 100%;width: 100%;"></div>
<!-- three.js场景 -->
<div id="ThreeContainer"></div>
</div>
</template>
<script>
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// 水
import { Water } from "three/examples/jsm/objects/Water.js";
// 天空
import { Sky } from "three/examples/jsm/objects/Sky.js";
const Cesium = require("cesium/Cesium");
export default {
name: "HelloWorld",
mounted() {
// three对象
let three = {
renderer: null,
camera: null,
scene: null,
};
//cesium对象
let cesium = {
viewer: null,
};
function pageload() {
// 模型定位范围
let minWGS84 = [115.56936458615716, 39.284100766866445];
let maxWGS84 = [117.10745052365716, 41.107831235616445];
// cesium 容器
let cesiumContainer = document.getElementById("cesiumContainer");
let _3Dobjects = []; // 可以是任何Three.js对象网格
// three对象
function _3DObject() {
//THREEJS 3DObject.mesh
this.threeMesh = null;
//location bounding box
this.minWGS84 = null;
this.maxWGS84 = null;
}
// 初始化地球
function initCesium() {
cesium.viewer = new Cesium.Viewer(cesiumContainer, {
animation: false, //动画控制,默认true
baseLayerPicker: false, //地图切换控件(底图以及地形图)是否显示,默认显示true
scene3DOnly: true, //设置为true,则所有几何图形以3D模式绘制以节约GPU资源
fullscreenButton: false, //全屏按钮,默认显示true
geocoder: false, //地名查找,默认true
timeline: true, //时间线,默认true
vrButton: false, //双屏模式,默认不显示false
homeButton: false, //主页按钮,默认true
infoBox: false, //点击要素之后显示的信息,默认true
selectionIndicator: false, //选中元素显示,默认true
navigationHelpButton: false, //导航帮助说明,默认true
navigationInstructionsInitiallyVisible: false,
automaticallyTrackDataSourceClocks: false, //自动追踪最近添加的数据源的时钟设置,默认true
terrainExaggeration: 2.0,
sceneModePicker: false, //是否显示地图2D2.5D3D模式
useDefaultRenderLoop: false,
allowTextureFilterAnisotropic: false,
contextOptions: {
webgl: {
alpha: false,
antialias: true,
preserveDrawingBuffer: true,
failIfMajorPerformanceCaveat: false,
depth: true,
stencil: false,
anialias: false,
},
},
targetFrameRate: 60,
resolutionScale: 0.1,
orderIndependentTranslucency: true,
//加载底图
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url:
"https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",
}),
// creditContainer : "hidecredit", //注意:这里需要注释掉,否则会报找不到容器的问题
dataSources: null,
clock: null,
terrainShadows: Cesium.ShadowMode.DISABLED,
});
//去掉银河,月亮,太阳,大气层
cesium.viewer.scene.moon.show = false;
cesium.viewer.scene.fog.enabled = false;
cesium.viewer.scene.sun.show = true;
cesium.viewer.scene.skyBox.show = false
let center = Cesium.Cartesian3.fromDegrees(
(minWGS84[0] + maxWGS84[0]) / 2,
(minWGS84[1] + maxWGS84[1]) / 2 - 1,
200000
);
cesium.viewer.camera.flyTo({
destination: center,
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-60),
roll: Cesium.Math.toRadians(0),
},
duration: 3,
});
}
//初始化three
function initThree() {
let fov = 45;
let width = window.innerWidth;
let height = window.innerHeight;
let aspect = width / height;
let near = 1;
let far = 10 * 1000 * 1000;
three.scene = new THREE.Scene();
three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
three.renderer = new THREE.WebGLRenderer({ alpha: true });
let Amlight = new THREE.AmbientLight(0xffffff, 2);
three.scene.add(Amlight);
// 注意这里,直接把three容器(canvas 添加到 cesium中,在cesium的canvas之下),
// 这样的话,两个canvas才会重叠起来。
cesium.viewer.cesiumWidget.canvas.parentElement.appendChild(
three.renderer.domElement
);
// ThreeContainer.appendChild(three.renderer.domElement);
var ThreeContainer = document.getElementById("ThreeContainer");
ThreeContainer.appendChild(three.renderer.domElement);
}
//创建 cesium 图形,跟three无关
function createPolygon() {
let entity = {
name: "Polygon",
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([
minWGS84[0],
minWGS84[1],
maxWGS84[0],
minWGS84[1],
maxWGS84[0],
maxWGS84[1],
minWGS84[0],
maxWGS84[1],
]),
material: Cesium.Color.BLUE.withAlpha(0.4),
},
};
let Polygon = cesium.viewer.entities.add(entity);
}
// 加载three模型 (多面球体创建)
function getModel(geometry) {
// 创建多面体
geometry = new THREE.DodecahedronGeometry();
// 材质
const material = new THREE.MeshBasicMaterial({ color: 0xf1f2f3 });
// 创建物体
let dodecahedronMesh = new THREE.Mesh(geometry, material);
// let dodecahedronMesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
// 大小缩放倍率
dodecahedronMesh.scale.set(5000, 5000, 5000); // 缩放相关参数 scale object to be visible at planet scale
// z方向移动一段距离
dodecahedronMesh.position.z += 25000.0; // 在Three.js空间中平移“向上”,使网格的“底部”为句柄
// x方向旋转版权
dodecahedronMesh.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
// 创建一个组
let dodecahedronMeshYup = new THREE.Group();
dodecahedronMeshYup.add(dodecahedronMesh);
// 添加场景当中
three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually
//Assign Three.js object mesh to our object array
// 设置模型位置
let _3DOB = new _3DObject();
// 存储模型
_3DOB.threeMesh = dodecahedronMeshYup;
// 存储模型位置坐标
_3DOB.minWGS84 = minWGS84;
_3DOB.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB);
}
function getDBModel(url) {
// let url = './model/1.glb'
// 外部模型加载
const loader = new GLTFLoader();
loader.load(url, (gltf) => {
const modelss = gltf.scene;
console.log(modelss, "加载到模型");
modelss.scale.set(10, 10, 10); // 缩放相关参数 scale object to be visible at planet scale
// z方向移动一段距离
// modelss.position.z += 10.0; // 在Three.js空间中平移“向上”,使网格的“底部”为句
modelss.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
let dodecahedronMeshYup = new THREE.Group();
dodecahedronMeshYup.add(modelss);
// 添加场景当中
three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually
let _3DOB = new _3DObject();
// 存储模型
_3DOB.threeMesh = dodecahedronMeshYup;
// 存储模型位置坐标
_3DOB.minWGS84 = minWGS84;
_3DOB.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB);
});
}
// 创建天空(不透明)
function getSky() {
// sun = new THREE.Vector3();
var sun = new THREE.Vector3();
// 创建天空
const sky = new Sky();
sky.scale.setScalar(100000);
// 添加到场景当中
three.scene.add(sky);
const skyUniforms = sky.material.uniforms;
skyUniforms["turbidity"].value = 10;
skyUniforms["rayleigh"].value = 2;
skyUniforms["mieCoefficient"].value = 0.005;
skyUniforms["mieDirectionalG"].value = 0.8;
const parameters = { elevation: 17, azimuth: 180 };
const pmremGenerator = new THREE.PMREMGenerator(three.renderer);
let renderTarget;
function updateSun() {
const phi = THREE.MathUtils.degToRad(90 - parameters.elevation);
const theta = THREE.MathUtils.degToRad(parameters.azimuth);
sun.setFromSphericalCoords(1, phi, theta);
sky.material.uniforms["sunPosition"].value.copy(sun);
if (renderTarget !== undefined) renderTarget.dispose();
renderTarget = pmremGenerator.fromScene(sky);
three.scene.environment = renderTarget.texture;
}
updateSun();
let _3DOB = new _3DObject();
// 存储模型
_3DOB.mysky = true;
_3DOB.threeMesh = sky;
// 存储模型位置坐标
_3DOB.minWGS84 = minWGS84;
_3DOB.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB);
// 控制天空光照
}
// 创建发光源
function createLight() {}
// 种树
function getTree() {
console.log("开始加载树木");
// 加载树纹理贴图
var textureTree = new THREE.TextureLoader().load("./textures/shu.jpg");
console.log("创建组", textureTree);
let dodecahedronMeshYup = new THREE.Group();
// 批量创建表示一个树的精灵模型
for (let i = 0; i < 10; i++) {
var spriteMaterial = new THREE.SpriteMaterial({
map: textureTree, //设置精灵纹理贴图
});
// 创建精灵模型对象
var sprite = new THREE.Sprite(spriteMaterial);
// 添加场景当中
var k1 = Math.random() - 0.5;
var k2 = Math.random() - 0.5;
// 位置
sprite.scale.set(1000, 1000, 1000); // 只需要设置x、y两个分量就可以
sprite.position.set(1000 * k1, 50, 1000 * k2);
sprite.position.z += 1000.0; // 在Three.js空间中平移“向上”,使网格的“底部”为句
sprite.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
// 添加到组中
dodecahedronMeshYup.add(sprite);
}
// 加载树
console.log("加载树");
three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually
let _3DOB = new _3DObject();
// 存储模型
_3DOB.threeMesh = dodecahedronMeshYup;
// 存储模型位置坐标
_3DOB.minWGS84 = minWGS84;
_3DOB.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB);
}
// 设置说
function setWater() {
// 创建一个平面
const waterGeometry = new THREE.PlaneGeometry(300, 300);
// 平面添加材质
const water = new Water(waterGeometry, {
textureWidth: 512,
textureHeight: 512,
// 纹理图片
waterNormals: new THREE.TextureLoader().load(
"textures/waternormals.jpg",
function(texture) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
}
),
sunDirection: new THREE.Vector3(),
sunColor: 0xffffff,
waterColor: 0x001e0f,
distortionScale: 8,
fog: three.scene.fog !== undefined,
});
// water.rotation.x = -Math.PI / 2;
// scene.add(water);
// 设置位置
water.scale.set(100, 100, 100);
water.position.y += 100.0; // 在Three.js空间中平移“向上”,使网格的“底部”为句
water.rotation.x = Math.PI; // rotate mesh for Cesium's Y-up system
// let dodecahedronMeshYup = new THREE.Group();
// dodecahedronMeshYup.add(water);
// 添加场景当中
three.scene.add(water); // don’t forget to add it to the Three.js scene manually
let _3DOB = new _3DObject();
// 存储模型
_3DOB.myType = true;
_3DOB.threeMesh = water;
// 存储模型位置坐标
_3DOB.minWGS84 = minWGS84;
_3DOB.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB);
}
// 加载three立方体模型
function cube() {
const geometry = new THREE.BoxGeometry();
const bulbLight = new THREE.PointLight(0xffee88, 1, 100, 2); // 点光源
const material = new THREE.MeshBasicMaterial({
emissive: 0xffffee, // 材质的放射(光)颜色,基本上是不受其他光照影响的固有颜色
emissiveIntensity: bulbLight.intensity / Math.pow(0.02, 2.0), // 放射光强度,将光源表面的强度转换为辐照度
color: 0x000000,
});
const dodecahedronMesh = new THREE.Mesh(geometry, material);
dodecahedronMesh.scale.set(1500, 1500, 1500); //scale object to be visible at planet scale
dodecahedronMesh.position.z += 10000.0; // translate "up" in Three.js space so the "bottom" of the mesh is the handle
dodecahedronMesh.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
// 加点光
let dodecahedronMeshYup = new THREE.Group();
dodecahedronMeshYup.add(dodecahedronMesh);
three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually
//Assign Three.js object mesh to our object array
let _3DOB = new _3DObject();
_3DOB.threeMesh = dodecahedronMeshYup;
_3DOB.minWGS84 = minWGS84;
_3DOB.maxWGS84 = maxWGS84;
_3Dobjects.push(_3DOB);
}
// 创建一个大光源
// 创建three 对象
function createThreeObject() {
// getSky()
// getModel();
getDBModel("./model/1.glb");
getDBModel("./model/2.glb");
getDBModel("./model/3.glb");
getDBModel("./model/4.glb");
cube();
setWater();
// 加载树
getTree();
}
// 初始化模型
function init3DObject() {
//Cesium entity
// createPolygon();
//Three.js Objects
createThreeObject();
}
// cesium 渲染
function renderCesium() {
cesium.viewer.render();
}
// three.js每次刷新的操作
function renderThreeObj() {
// register Three.js scene with Cesium
// 镜头同步
three.camera.fov = Cesium.Math.toDegrees(
cesium.viewer.camera.frustum.fovy
); // ThreeJS FOV is vertical
//three.camera.updateProjectionMatrix();
let cartToVec = function(cart) {
return new THREE.Vector3(cart.x, cart.y, cart.z);
};
// 控制下水流变化 water.position.y += 100.0;
// water.material.uniforms["time"].value += 1.0 / 60.0;
// Configure Three.js meshes to stand against globe center position up direction
// 将Three.js网格配置为相对于地球仪中心位置向上
for (let id in _3Dobjects) {
// 水流动一动
if (_3Dobjects[id].myType)
_3Dobjects[id].threeMesh.material.uniforms["time"].value +=
1.0 / 60.0;
minWGS84 = _3Dobjects[id].minWGS84;
maxWGS84 = _3Dobjects[id].maxWGS84;
// convert lat/long center position to Cartesian3
let center = Cesium.Cartesian3.fromDegrees(
(minWGS84[0] + maxWGS84[0]) / 2,
(minWGS84[1] + maxWGS84[1]) / 2
);
// get forward direction for orienting model
let centerHigh = Cesium.Cartesian3.fromDegrees(
(minWGS84[0] + maxWGS84[0]) / 2,
(minWGS84[1] + maxWGS84[1]) / 2,
1
);
// use direction from bottom left to top left as up-vector
let bottomLeft = cartToVec(
Cesium.Cartesian3.fromDegrees(minWGS84[0], minWGS84[1])
);
let topLeft = cartToVec(
Cesium.Cartesian3.fromDegrees(minWGS84[0], maxWGS84[1])
);
let latDir = new THREE.Vector3()
.subVectors(bottomLeft, topLeft)
.normalize();
// configure entity position and orientation
// 配置实体位置和方向
_3Dobjects[id].threeMesh.position.copy(center); // 控制更新后的模型位置
// if(_3Dobjects[id].myType) _3Dobjects[id].threeMesh.position.y += 10.0;
_3Dobjects[id].threeMesh.lookAt(
centerHigh.x,
centerHigh.y,
centerHigh.z
);
_3Dobjects[id].threeMesh.up.copy(latDir);
}
// Clone Cesium Camera projection position so the
// Three.js Object will appear to be at the same place as above the Cesium Globe
// 克隆铯相机的投影位置,使Three.js对象看起来与铯地球仪上方的位置相同
three.camera.matrixAutoUpdate = false;
let cvm = cesium.viewer.camera.viewMatrix;
let civm = cesium.viewer.camera.inverseViewMatrix;
// 注意这里,经大神博客得知,three高版本这行代码需要放在 three.camera.matrixWorld 之前
three.camera.lookAt(0, 0, 0);
three.camera.matrixWorld.set(
civm[0],
civm[4],
civm[8],
civm[12],
civm[1],
civm[5],
civm[9],
civm[13],
civm[2],
civm[6],
civm[10],
civm[14],
civm[3],
civm[7],
civm[11],
civm[15]
);
three.camera.matrixWorldInverse.set(
cvm[0],
cvm[4],
cvm[8],
cvm[12],
cvm[1],
cvm[5],
cvm[9],
cvm[13],
cvm[2],
cvm[6],
cvm[10],
cvm[14],
cvm[3],
cvm[7],
cvm[11],
cvm[15]
);
// 设置three宽高
let width = cesiumContainer.clientWidth;
let height = cesiumContainer.clientHeight;
let aspect = width / height;
three.camera.aspect = aspect;
three.camera.updateProjectionMatrix();
three.renderer.setSize(width, height);
three.renderer.clear();
three.renderer.render(three.scene, three.camera);
}
// 同步
function loop() {
requestAnimationFrame(loop);
renderCesium();
renderThreeObj();
}
initCesium(); // Initialize Cesium renderer
initThree(); // Initialize Three.js renderer
init3DObject(); // Initialize Three.js object mesh with Cesium Cartesian coordinate system
loop(); // Looping renderer
}
pageload();
},
};
</script>
<style scoped>
/*设置cesium和three的画布位置*/
.container-integrate canvas {
position: absolute;
top: 0;
}
/*three画布禁止鼠标操作*/
.container-integrate canvas:nth-child(3) {
pointer-events: none;
}
#ThreeContainer {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
margin: 0;
overflow: hidden;
padding: 0;
font-family: sans-serif;
/* 禁止鼠标操做 */
pointer-events: none;
}
</style>