React集成Cesium+ThreeJs流程汇总

本文详细介绍了如何在React应用中集成Cesium和ThreeJS,通过安装ThreeJS模块,创建CesiumForThreeJS组件,设置视角和加载3D模型,最终实现在Cesium地球表面展示3D模型的效果。文章提供了完整的代码示例,包括加载模型、同步Cesium和ThreeJS相机等关键步骤。
摘要由CSDN通过智能技术生成

React集成Cesium+ThreeJs流程汇总



集成Cesium+ThreeJS

React集成Cesium流程汇总 已经集成好Cesium的基础上集成ThreeJS

1.安装ThreeJS模块

1)执行yarn add three 安装ThreeJS模块:

yarn add three

2)因为项目基于TypeScript进行构建,需要按装three 的声明文件,执行命令:

yarn add typescript @types/three 或者
npm i --save-dev @types/three

2.创建CesiumForThreeJS组件

在 src-> components->CesiumForThree目录下创建 CesiumForThree.js 文件 并写入如下内容:

CesiumForThree.js

import React,{Component} from 'react';

import './CesiumForThree.css';

//引入Three.js
import * as THREE from "three"
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

//引入cesium
import 'cesium/Widgets/widgets.css'
var Cesium = require('cesium/Cesium');

class CesiumForThree extends Component {
    state={
        viewer:null,
        scene:null,
        camera:null,
        renderer:null
    }

    componentDidMount() {
        var viewer = new Cesium.Viewer('cesiumContainer', {
                    
            selectionIndicator: false,
            animation: false,
            baseLayerPicker: false,
            geocoder: false,
            timeline: false,
            sceneModePicker: false,
            navigationHelpButton: false,
            infoBox: false,
            fullscreenButton: false,
            homeButton: false,

            imageryProvider:new Cesium.UrlTemplateImageryProvider({
				url : "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
				name: "openstreetmap",
				subdomains: ["a", "b", "c", "d"],
				format: "image/jpeg",
				tileMatrixSetID:"GoogleMapsCompatible",
				minimumLevel:1,            
				maximumLevel:20
			})
        });
        viewer.bottomContainer.style.display = "none"; //隐藏图标
        viewer.scene.globe.depthTestAgainstTerrain = true;
        viewer.scene.debugShowFramesPerSecond = true;

        let center = Cesium.Cartesian3.fromDegrees(114.052652, 22.501094,2000);
        
        viewer.camera.setView({//flyTo
            destination: center,
            orientation: {
                heading: Cesium.Math.toRadians(0),
                pitch: Cesium.Math.toRadians(-60),
                roll: Cesium.Math.toRadians(0)
            },
            duration: 3
        });
        this.loadThree(viewer);
        this.state.viewer=viewer;
        this.loop();
    }

    loadThree=(viewer)=>{
        
        let fov = 45;
        let width = window.innerWidth;
        let height = window.innerHeight;
        let aspect = width / height;
        let near = 1;
        let far = 10 * 1000 * 1000;
        
        var scene = new THREE.Scene();//Scene
        // fov — 摄像机视锥体垂直视野角度
        // aspect — 摄像机视锥体长宽比
        // near — 摄像机视锥体近端面
        // far — 摄像机视锥体远端面
        var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
        camera.lookAt(0, 0, 0);
        
        var renderer = new THREE.WebGLRenderer({
            antialias: true,// 开启抗锯齿
            alpha: true,// canvas是否包含alpha (透明度)。默认为 false
        });//渲染场景
        
        var pmremGenerator = new THREE.PMREMGenerator(renderer);
        pmremGenerator.compileEquirectangularShader();
        viewer.cesiumWidget.canvas.parentElement.appendChild(renderer.domElement);
        
        viewer.cesiumWidget.canvas.parentElement.appendChild(renderer.domElement);
        
        this.addModel(scene);
        this.state.scene=scene;
        this.state.camera=camera;
        this.state.renderer=renderer;
    }

    addModel=(scene)=>{
        // 加载 glTF 格式的模型
        let loader = new GLTFLoader(); /*实例化加载器*/	
        const group = new THREE.Group();//实体容器
        //http://127.0.0.1:8066/PubData/MainBuilding/SM_AC_FNGC_1.gltf
        // http://127.0.0.1:8066/PubData/ThreeModel/models/gltf/Xbot.glb/
        var model="http://127.0.0.1:8066/PubData/MainBuilding/SM_AC_FNGC_1.gltf";
        var model01="http://127.0.0.1:8066/PubData/ThreeModel/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf";
        var model02="http://127.0.0.1:8066/WebServer/three.js-r136/examples/models/gltf/IridescentDishWithOlives.glb";
        var model03="http://127.0.0.1:8066/PubData/ThreeModel/models/gltf/MaterialsVariantsShoe/glTF/MaterialsVariantsShoe.gltf";
        
        // loader.setDecoderPath( '/examples/js/libs/draco/' );
        loader.load(model, function(gltf) {
            let GroupS = new THREE.Group();
            
            var model = gltf.scene;
            // Three.scene.add( model );
            
            model.traverse( function ( child ) {
                if (child instanceof THREE.Mesh){
                  //设置模型生成阴影并接收阴影
                  child.castShadow = true;
                  child.receiveShadow = true;
                }
            });
            // model.castShadow = true;
            // model.receiveShadow = true;
            
            let centerHigh = Cesium.Cartesian3.fromDegrees(114.052652, 22.509394,0);
            model.position.set(centerHigh.x,centerHigh.y,centerHigh.z);
            model.translateX(-20);//沿着x轴正方向平移距离100
            model.translateZ(-20);//沿着x轴正方向平移距离100
            
            // var axis = new THREE.Vector3(031,0);//向量axis
            // model.rotateOnAxis(axis,2);//绕axis3旋转π/8
            // model.rotateX(Math.PI/4)3
            model.rotateY(3.55);//水平旋转 越大逆时针 反正  z
            model.rotateX(-0.23);//水平旋转 越大逆时针 反正  Y
            model.rotateZ(-0.53);//X
            
            scene.add( model );
            
            //点聚光===================
            let center33 = Cesium.Cartesian3.fromDegrees(114.052970,22.509301,100);
            const light = new THREE.PointLight( 0xffffff, 8, 150);
            light.position.copy(center33);
            // light.position.set( 15, 40, 35 );
            light.castShadow = false; // default false
            scene.add( light );
            
            light.shadow.mapSize.width = 15; // default
            light.shadow.mapSize.height = 12; // default
            light.shadow.camera.near = 1.5; // default
            light.shadow.camera.far = 10 // default


        }, function(xhr) {
            console.log((xhr.loaded / xhr.total * 100) + '% loaded');
        }, function(error) {
            console.log('load error!' + error.getWebGLErrorMessage());
        })
    }

    // 同步
	loop=()=>{
        var viewer=this.state.viewer;
        var camera=this.state.camera;
        var scene=this.state.scene;
        var renderer=this.state.renderer;

        let cesiumContainer = document.getElementById("cesiumContainer");

        requestAnimationFrame(this.loop);//告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
        //该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
        
        // 1、requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
        // 2、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
        
        // stats.update();
        
        viewer.render();//渲染场景。除非设置为 false,否则将自动调用此函数;
        
        //用 Cesium 注册 Three.js 场景
        camera.fov = Cesium.Math.toDegrees(viewer.camera.frustum.fovy) // 将three试图的中心 赋值等于Cesium 试图的中心
        
        //three.camera.updateProjectionMatrix();
        
        // Clone Cesium Camera projection position so the
        // Three.js Object will appear to be at the same place as above the Cesium Globe
        camera.matrixAutoUpdate = false;//矩阵自动更新 
        let cvm = viewer.camera.viewMatrix;
        let civm = viewer.camera.inverseViewMatrix;
        
        // 注意这里,经大神博客得知,three高版本这行代码需要放在 three.camera.matrixWorld 之前
        // Three.camera.lookAt(0, 0, 0);
        
        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]
        );
        
        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;
        camera.aspect = aspect;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
        renderer.clear();
        renderer.render(scene,camera);
    }
		
    
    render() {
     return (
        <div className='container-integrate'>
		    {/* cesium容器*/}
		    <div id="cesiumContainer" className='cesiumContainer'></div>
		</div>
     );
   }
 }

export default CesiumForThree

在 src-> pages-> Home->Home.tsx 处引入Three组件 代码如下:

import React from 'react';
import { useNavigate } from 'react-router-dom';

import { Button } from 'antd';

import CesiumForThree from '../../components/CesiumForThree/CesiumForThree';

function MyButton() {
    let navigate = useNavigate();
    function handleClick() {
        navigate('/Index');
    };
    return <button onClick={handleClick}>Submit</button>;
};

class Home extends React.Component{
    
    render(){
        return(
            <div>
                <Button type="primary">Home页面</Button>

                <MyButton></MyButton>
                <CesiumForThree></CesiumForThree>
            </div>
        )
    }
}
export default Home

3.运行查看效果

控制台输入命令 yarn start
在这里插入图片描述
在这里插入图片描述
浏览器打开显示如上图所示

总结

以上就是React集成Cesium+ThreeJs的内容了。

源代码打包-> React集成Cesium+ThreeJs示例代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GIS子枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值