• three.js 物体、路径与移动


    import * as THREE from 'three';
    import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    import { DragControls } from "three/examples/jsm/controls/DragControls";
    import { Pieces } from "../@share/pieces";
    
    /**
     * 3d 动画测试,路径与移动
     * https://threejs.org/docs/index.html#api/zh/extras/curves/SplineCurve - 曲线
     * https://threejs.org/docs/index.html#api/zh/extras/core/Curve - 核心
     */
    export class ThreePathAndMove {
        constructor(canvasId) {
            this.work(canvasId);
        }
    
        work(canvasId) {
            // 创建 3d 场景
            const scene = new THREE.Scene();
            scene.background = new THREE.Color(0x9e9e9e);
    
            // 渲染器
            const renderer = this.addRenderer();
    
            // 创建相机
            const camera = this.makeCamera();
            // .multiplyScalar() 矩阵的每个元素乘以参数。
            camera.position.set(-20, 20, 80).multiplyScalar(3);
            // 朝向
            camera.lookAt(0, 0, 0);
            // 控制相机
            const controls = new OrbitControls(camera, renderer.domElement);
            controls.update();
    
            // 初始化灯光
            // 方向光
            const light = new THREE.DirectionalLight(0xffffff, 1);
            light.position.set(0, 20, 0)
            scene.add(light);
            // 方向光
            const light2 = new THREE.DirectionalLight(0xffffff, 1);
            light2.position.set(1, 2, 4);
            scene.add(light2);
    
            const len = 300;
            // 添加地面
            this.addArea(scene, len);
    
            // 添加物体
            const boat = this.makeObject(scene);
    
            // 绘制路径
            const curve = this.addPath(scene, len / 2);
    
            const boatPosition = new THREE.Vector2()
            const boatTarget = new THREE.Vector2()
    
            function render(time) {
                time *= 0.0005;
                const boatTime = time * 0.05;
                curve.getPointAt(boatTime % 1, boatPosition);
                // 获取路径前一点坐标,用于头部向前
                curve.getPointAt((boatTime + 0.01) % 1, boatTarget);
                // 位移
                boat.position.set(boatPosition.x, 0, boatPosition.y);
                boat.lookAt(boatTarget.x, 1, boatTarget.y);
    
                // 加载渲染器
                renderer.render(scene, camera)
                // 开始动画
                requestAnimationFrame(render)
            }
    
            // 开始渲染
            requestAnimationFrame(render);
        }
    
        /**
         * 创建相机公用方法
         * */
        makeCamera(fov = 40) {
            const aspect = 2 // the canvas default
            const zNear = 0.1
            const zFar = 1000
            return new THREE.PerspectiveCamera(fov, aspect, zNear, zFar)
        }
    
        /**
         * 添加平面
         */
        addArea(scene, len) {
            const groundGeometry = new THREE.PlaneGeometry(len, len);
            const groundMaterial = new THREE.MeshPhongMaterial({ color: 0x23ADE5 });
            const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
            groundMesh.rotation.x = Math.PI * -0.5;
            scene.add(groundMesh);
        }
    
        /**
         * 添加渲染器
         */
        addRenderer() {
            let renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            // 最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。
            document.body.appendChild(renderer.domElement);
            return renderer;
        }
    
        /**
         * 添加船只
         */
        makeObject(scene) {
            const boat = new THREE.Object3D();
            boat.position.y = -1;
            scene.add(boat);
    
            const bodyRadius = 2;
            const bodyLength = 10;
            // 舰体
            const bodyGeometry = new THREE.CapsuleGeometry(bodyRadius, bodyLength, 4, 32);
            const bodyMaterial = new THREE.MeshPhongMaterial({ color: 0x6688aa });
            const bodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial);
            bodyMesh.rotation.x = Math.PI * 0.5;
            boat.add(bodyMesh);
    
            const doorRadius = bodyRadius / 7 * 5;
            const doorHeight = 2;
            // 舰桥
            const doorGeometry = new THREE.CylinderGeometry(doorRadius, doorRadius, doorHeight, 36);
            const doorMesh = new THREE.Mesh(doorGeometry, bodyMaterial);
            doorMesh.position.set(0, 2, -2);
            boat.add(doorMesh);
    
            const glassRadius = doorRadius / 7;
            const glassHeight = bodyLength / 2;
            // 潜望镜
            const glassGeometry = new THREE.CylinderGeometry(glassRadius, glassRadius, glassHeight, 36);
            const glassMesh = new THREE.Mesh(glassGeometry, bodyMaterial);
            glassMesh.position.set(0, 2, -2.9);
            boat.add(glassMesh);
    
            const swingWidth = 5;
            const swingHeight = doorHeight / 20;
            // 舰桥翼
            const swingGeometry = new THREE.BoxGeometry(swingWidth, swingHeight, 1, 36);
            const swingMesh = new THREE.Mesh(swingGeometry, bodyMaterial);
            swingMesh.position.set(0, 2.5, -2);
            boat.add(swingMesh);
    
            const swingTailHeight = doorHeight / 8;
            const swingTailWidth = 4;
            // 尾翼
            const swingTail1Geometry = new THREE.BoxGeometry(swingTailWidth, swingTailHeight, 2, 36);
            const swingT1Mesh = new THREE.Mesh(swingTail1Geometry, bodyMaterial);
            swingT1Mesh.position.set(0, 0, -6);
            boat.add(swingT1Mesh);
            const swingTail2Geometry = new THREE.BoxGeometry(swingTailHeight, swingTailWidth, 2, 36);
            const swingT2Mesh = new THREE.Mesh(swingTail2Geometry, bodyMaterial);
            swingT2Mesh.position.set(0, 0, -6);
            boat.add(swingT2Mesh);
    
            return boat;
        }
    
        /**
         * 添加路径,平面
         */
        addPath(scene, num) {
            let max = num;
            let min = -num;
            let pointArr = [];
            // 随机点
            for (let i = 0; i < 10; i++) {
                let point = Pieces.getRandomNumberByCount(2, max, 0, min);
                pointArr.push(new THREE.Vector2(point[0], point[1]));
            }
            // 封闭路径
            pointArr.push(JSON.parse(JSON.stringify(pointArr[0])));
            /**
             * 样条曲线(SplineCurve)
             * 从一系列的点中,创建一个平滑的二维样条曲线。内部使用Interpolations.CatmullRom来创建曲线。
             * SplineCurve( points : Array )
             * points – 定义曲线的Vector2点的数组。
             *
             * 方法
             * .getPoints ( divisions : Integer ) : Array
             * divisions -- 要将曲线划分为的分段数。默认是 5.
             * 使用getPoint(t)返回一组divisions+1的点
             *
             * .getPointAt ( u : Float, optionalTarget : Vector ) : Vector
             * u - 根据弧长在曲线上的位置。必须在范围[0,1]内。
             * optionalTarget — (可选) 如果需要, (可选) 如果需要, 结果将复制到此向量中,否则将创建一个新向量。
             * 根据弧长返回曲线上给定位置的点。
             * @type {SplineCurve}
             */
            const curve = new THREE.SplineCurve(pointArr);
    
            const points = curve.getPoints(50);
            const geometry = new THREE.BufferGeometry().setFromPoints(points);
            const material = new THREE.LineBasicMaterial({ color: 0xffffff });
            const splineObject = new THREE.Line(geometry, material);
            splineObject.rotation.x = Math.PI * 0.5;
            splineObject.position.y = 0.05;
            scene.add(splineObject);
            return curve;
        }
    
    }
  • 相关阅读:
    css基础
    什么是css
    js写guess网页
    JavaScript_day02
    html基础知识
    JavaScript_day01
    由一个瀑布流导出对滚动条滚动距离,可视区尺寸,元素尺寸的内容的知识点
    一个页面从输入URL到页面加载显示完成,这个过程中发生了什么?
    http常用状态吗以及分别代表什么意思?
    cookies,sessionStorage和localStorage的相同点和不同点?
  • 原文地址:https://www.cnblogs.com/guofan/p/16355906.html
Copyright © 2020-2023  润新知