学习Three.js(二)

597 阅读1分钟
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>2</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            /* 隐藏body窗口区域滚动条 */
        }

        canvas {
            background-image: url('./imgs/star.jpg');
            background-size: cover;
        }

        .label {
            color: #fff;
            font-size: 16px;
        }
    </style>
</head>

<body>
    <script type="module">
        import * as THREE from './libs/build/three.module.js';
        import { OrbitControls } from './libs/jsm/controls/OrbitControls.js';
	import { CSS2DRenderer, CSS2DObject } from './libs/jsm/renderers/CSS2DRenderer.js';

        //声明全局变量
        let camera, scene, renderer, labelRenderer;
        let moon,earth;
        let clock = new THREE.Clock();

        //实例化纹理加载器
        const textureLoader = new THREE.TextureLoader();

        function init() {
            //设定地球和月球的大小
            const EARTH_RADIUS = 2.5;
            const MOON_RADIUS = 0.27;

            //实例化相机 透视相机
            camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,200);
            camera.position.set(10,5,20);

            //实例化场景
            scene = new THREE.Scene();
            //光源 添加聚光灯
            const spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(0,0,10);
            //光照强度。 缺省值 1
            spotLight.intensity = 2;
            //设置为 true 聚光灯将投射阴影
            spotLight.castShadow = true;
            scene.add(spotLight);

            //光源 添加环境光
            const ambLight = new THREE.AmbientLight(0xffffff);
            ambLight.intensity = 0.3;
            scene.add(ambLight);

            //创建月球
            const moonGometry = new THREE.SphereGeometry(MOON_RADIUS,16,16);
            //一种用于具有镜面高光的光泽表面的材质
            const moonMaterial = new THREE.MeshPhongMaterial({
                //颜色贴图。默认为null。纹理贴图颜色由漫反射颜色.color调节。
                //map: textureLoader.load('./imgs/02.jpg')
                map: textureLoader.load('./textures/planets/moon_1024.jpg')
            });
            moon = new THREE.Mesh(moonGometry,moonMaterial);
            moon.receiveShadow = true;
            moon.castShadow = true;
            scene.add(moon);

            //创建地球
            const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS,16,16);
            const earthMaterial = new THREE.MeshPhongMaterial({
                //高亮的程度,越高的值越闪亮。默认值为 30。
                shininess: 5,
                //map: textureLoader.load('./imgs/01.jpg'),
                map: textureLoader.load('./textures/planets/earth_atmos_2048.jpg'),
                //镜面反射贴图值会影响镜面高光以及环境贴图对表面的影响程度。默认值为null。
                specularMap: textureLoader.load('./textures/planets/earth_specular_2048.jpg'),
                normalMap: textureLoader.load('./textures/planets/earth_normal_2048.jpg')
            });
            earth = new THREE.Mesh(earthGeometry,earthMaterial);
            earth.receiveShadow = true;
            earth.castShadow = true;
            scene.add(earth);
            
            //创建地球和月球的标签
            const earthDiv = document.createElement('div');
            earthDiv.className = 'label';
            earthDiv.textContent = 'Earch';
            
            const eartchLabel = new CSS2DObject(earthDiv);
            eartchLabel.position.set(0, EARTH_RADIUS + 0.5, 0);
            earth.add(eartchLabel);
            
            const moonDiv = document.createElement('div');
            moonDiv.className = 'label';
            moonDiv.textContent = 'Moon';
            
            const moonLabel = new CSS2DObject(moonDiv);
            moonLabel.position.set(0, MOON_RADIUS + 0.5, 0);
            moon.add(moonLabel);


            // 创建渲染器
            renderer = new THREE.WebGLRenderer({
                //canvas是否包含alpha (透明度)。默认为 false
                alpha: true
            });
            //设置设备像素比。通常用于避免HiDPI设备上绘图模糊
            // devicePixelRatio 返回当前显示设备的物理像素分辨率与CSS 像素分辨率之比。
            // 此值也可以解释为像素大小的比率:一个 CSS 像素的大小与一个物理像素的大小。
            // 简单来说,它告诉浏览器应使用多少屏幕实际像素来绘制单个 CSS 像素。
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth,window.innerHeight);
            //渲染阴影
            renderer.shadowMap.enabled = true;
            document.body.appendChild(renderer.domElement);

            //标签渲染器
            labelRenderer = new CSS2DRenderer();
            labelRenderer.setSize(window.innerWidth, window.innerHeight)
            labelRenderer.domElement.style.position = 'absolute';
            labelRenderer.domElement.style.top = '0px';
            labelRenderer.domElement.style.pointerEvents = 'none';
            document.body.appendChild(labelRenderer.domElement)

            //绑定控制和摄像头
            const controls = new OrbitControls(camera,renderer.domElement);
        }

        let oldTime = 0;
        function animate() {
            const elapsed = clock.getElapsedTime();
            moon.position.set(Math.sin(elapsed) * 5, 0, Math.cos(elapsed) * 5);
            // 地球自转
            var axis = new THREE.Vector3(0, 1, 0);
            earth.rotateOnAxis(axis, (elapsed - oldTime) * Math.PI / 10);
            renderer.render(scene, camera)
            labelRenderer.render(scene, camera)
            oldTime = elapsed;
            requestAnimationFrame(animate)
        }

        init();
        animate();

        // 调整尺寸
        window.onresize = function () {
            camera.aspect = window.innerWidth / window.innerHeight;
            //在大多数属性发生改变之后,你将需要调用.updateProjectionMatrix来使得这些改变生效。
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight)
	}
    </script>
</body>

</html>

踩坑

ThreeJs CSS2DRenderer、OrbitControls 鼠标事件问题
在ThreeJs3D场景中使用CSS2DRenderer渲染Html元素,OrbitControls 功能失效

原因分析:

CSS2DRenderer渲染器会在页面渲染出一个Div,里面包含自定义的html片段,默认情况下该Div或捕获页面的键盘、鼠标事件,导致OrbitControls的相关事件失效

处理方案:

方案1:修改css2DRenderer对应dom元素的pointerEvents属性为none:

css2DRenderer.domElement.style.pointerEvents = 'none';

方案2:修改OrbitControls关联的Dom元素为当前的css2DRenderer.domElement

const controls = new OrbitControls( camera, css2DRenderer.domElement );