其他分享
首页 > 其他分享> > three.js实现简单的3D中国省份立体板块地图

three.js实现简单的3D中国省份立体板块地图

作者:互联网

image

源码资料获取:https://github.com/huangchun0121/3D-example/tree/main/省份立体板块

实现代码:

点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>中国地图</title>
    <style>
        /*body{*/
        /*    width: 100%;*/
        /*    height: 100%;*/
        /*    padding: 0;*/
        /*    margin: 0;*/
        /*}*/


    </style>
</head>
<body>
<div id="provinceInfo"></div>
<script src="js/three.js"></script>
<script src="js/three.orbitcontrols.js"></script>
<script src="js/d3-array.v1.min.js"></script>
<script src="js/d3-geo.v1.min.js"></script>
<script>

    let renderer, camera, scene, light, controller;
    const width = window.innerWidth, height = window.innerHeight;
    var map;

    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();

    /**
     * @description 初始化渲染场景
     */
    function initRenderer() {
       renderer = new THREE.WebGLRenderer({attributes:true});
       renderer.setSize(width,height);
       document.body.appendChild(renderer.domElement);
    }
    /**
     * @description 初始化相机
     */
    function initCamera() {
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, -70, 150);
        camera.lookAt(0, 0, 0);
    }
    /**
     * @description 初始化场景
     */
    function initScene() {
        scene = new THREE.Scene();
    }
    /**
     * 初始化用户交互
     **/
    function initControls() {
        controller = new THREE.OrbitControls(camera, renderer.domElement);
    }

    /**
     * 初始化物体
     */
    function initObject(){
        var loader = new THREE.FileLoader();
        loader.load('model/chinaJson.json',function(data){
            var chinaData = JSON.parse(data);
            initMap(chinaData);
        });
        window.addEventListener('mousemove', onm ouseMove, false);
    }
    /**
     * 描绘中国边界(平面)
     */
    function initMap(chinaJson) {
        // 建一个空对象存放对象
        map = new THREE.Object3D();

        // 墨卡托投影转换
        const projection = d3.geoMercator().center([104.0, 37.5]).scale(80).translate([0, 0]);

        chinaJson.features.forEach(elem => {
            // 定一个省份3D对象
            const province = new THREE.Object3D();
            // 每个的 坐标 数组
            const coordinates = elem.geometry.coordinates;
            // 循环坐标数组
            coordinates.forEach(multiPolygon => {

                multiPolygon.forEach(polygon => {
                    const shape = new THREE.Shape();
                    const lineMaterial = new THREE.LineBasicMaterial({
                        color: 'white'
                    });
                    const lineGeometry = new THREE.Geometry();

                    for (let i = 0; i < polygon.length; i++) {
                        const [x, y] = projection(polygon[i]);
                        if (i === 0) {
                            shape.moveTo(x, -y);
                        }
                        shape.lineTo(x, -y);
                        lineGeometry.vertices.push(new THREE.Vector3(x, -y, 4.01));
                    }

                    const extrudeSettings = {
                        depth: 4,
                        bevelEnabled: false
                    };

                    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
                    const material = new THREE.MeshBasicMaterial({
                        color: '#02A1E2',
                        transparent: true,
                        opacity: 0.6
                    });
                    const material1 = new THREE.MeshBasicMaterial({
                        color: '#3480C4',
                        transparent: true,
                        opacity: 0.5
                    });
                    /* const material = new THREE.MeshBasicMaterial({ color: '#dedede', transparent: false, opacity: 0.6 });
                    const material1 = new THREE.MeshBasicMaterial({ color: '#dedede', transparent: false, opacity: 0.5 }); */
                    const mesh = new THREE.Mesh(geometry, [material, material1]);
                    const line = new THREE.Line(lineGeometry, lineMaterial);
                    province.add(mesh);
                    province.add(line)

                })

            })
            // 将geo的属性放到省份模型中
            province.properties = elem.properties;
            if (elem.properties.contorid) {
                const [x, y] = projection(elem.properties.contorid);
                province.properties._centroid = [x, y];
            }

            map.add(province);

        })

       scene.add(map);
    }

    /**
     * 鼠标拾取
     */

    function onm ouseMove(event) {

        // calculate mouse position in normalized device coordinates
        // (-1 to +1) for both components

       mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    }
    /**
     * @description 初始化光
     */
    function initLight() {
        const ambientLight = new THREE.AmbientLight( 0xffffff );
        scene.add( ambientLight );
    }

    /**
     * 窗口变动
     **/
    function onWindowResize() {
        camera.aspect = innerWidth / innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( innerWidth, innerHeight );
        renders();
    }

    /**
     * 渲染
     */
    function renders() {
        renderer.clear();
        renderer.render( scene, camera );
    }

    /**
     * 更新
     **/
    var activeInstersect =[];//用于存放选中的物体
    function animate() {
        requestAnimationFrame(animate);
        if(controller) controller.update();

        raycaster.setFromCamera(mouse,camera);
        var intersects = raycaster.intersectObjects(scene.children,true);//获取鼠标与屏幕射线相交的物体

        if (activeInstersect.length > 0) { // 将上一次选中的恢复好颜色
            activeInstersect.forEach(element => {
                element.object.material[0].color.set('#02A1E2');
                element.object.material[1].color.set('#3480C4');
            });
        }

         activeInstersect = []; // 设置为空

        for (var i = 0; i < intersects.length; i++) {      //
            if (intersects[i].object.material && intersects[i].object.material.length === 2) {
                activeInstersect.push(intersects[i]);
                intersects[i].object.material[0].color.set(0xff0000);
                intersects[i].object.material[1].color.set(0xff0000);
                break; // 只取第一个
            }
        }

        renders();
    }

    window.onload = () => {
        initRenderer();
        initCamera();
        initScene();
        initObject();
        initLight();
        initControls();
        animate();
        window.addEventListener('resize', onWindowResize, false);
    }

</script>
</body>
</html>

标签:function,const,material,THREE,three,window,new,js,3D
来源: https://www.cnblogs.com/huangchun/p/16662779.html