• three.js 学习


    import * as THREE from 'three';
    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
    
    /**
     * 3d 学习
     */
    export class ThreeStudy {
        constructor(canvasId) {
            // 初始测试绘制
            // this.one(canvasId);
            // 正式调试
            this.two(canvasId);
        }
    
        one(canvasId) {
            let width = window.innerWidth;
            let height = window.innerHeight;
            let renderer = new THREE.WebGLRenderer({
                antialias: true
            });
            let scene = new THREE.Scene();
            renderer.setSize(width, height);
            document.getElementById(canvasId).appendChild(renderer.domElement);
            renderer.setClearColor(0x000000, 1.0);
    
            let camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
            camera.position.set(400, 400, 400);
            camera.up.set(0, 1, 0);
            camera.lookAt(0, 0, 0);
    
            let light = new THREE.AmbientLight(0xFFFFFF);
            light.position.set(300, 300, 0);
            scene.add(light);
    
            let geometry = new THREE.BoxGeometry(200, 200, 100);
            let material = new THREE.MeshLambertMaterial({ color: 0xFF0000 });
            let mesh = new THREE.Mesh(geometry, material);
            mesh.position.set(0, 0, 0);
            scene.add(mesh);
    
            renderer.render(scene, camera);
        }
    
        two(canvasId) {
            let width = window.innerWidth;
            let height = window.innerHeight;
            // 创建渲染器
            let renderer = new THREE.WebGLRenderer({
                antialias: true
            });
            renderer.setSize(width, height);
            document.getElementById(canvasId).appendChild(renderer.domElement);
            renderer.setClearColor(0x000000);
    
    
            // 创建 3d 场景
            let scene = new THREE.Scene();
    
    
            /**
             * 照相机常用的有两种
             * 正投影相机:THREE.OrthographicCamera(left,right,top,bottom,near,far);
             * 透视照相机:THREE.PerspectiveCamera( fov, aspect, near, far ) ;
             */
                // let camera = new THREE.OrthographicCamera(-100, 6, 4.5, -4.5, 0, 50);
            let camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
            // 主视图(front 视角)
            // camera.position.set(0, 0, 200);
            // 俯视图(top 视角)
            // camera.position.set(0, 200, 0);
            // 侧视图(side 视角)
            // camera.position.set(200, 0, 0);
            // 3d 视图(主视角)
            camera.position.set(200, 200, 200);
            //设置照相机的位置
            camera.lookAt(new THREE.Vector3(0, 0, 0)); //设置照相机面向(0,0,0)坐标观察 照相机默认坐标为(0,0,0); 默认面向为沿z轴向里观察;
    
    
            /**
             * 添加自然光源
             * a. 平行光(DirectionalLight),效果类似太阳光 , DirectionalLight ( color, intensity )
             * b. 点光源(PointLight),效果类似灯泡 , PointLight ( color, intensity, distance, decay )
             * c.. 聚光光源(SpotLight),效果类似聚光灯 , SpotLight ( color, intensity, distance, angle, penumbra, decay )
             * color — 光源颜色的RBG数值。
             * intensity — 光强的数值。
             * distance -- 光强为0处到光源的距离,0表示无穷大。
             * decay -- 沿着光照距离的衰退量。
             * angle -- 光线散射角度,最大为Math.PI/2。
             * penumbra -- 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。
             */
            let light = new THREE.DirectionalLight(0xffffff, 1, 100);  //创建光源
            // 光源移动
            light.position.set(500, 500, 500);
            scene.add(light);  //在场景中添加光源
            /**
             * DirectionalLightHelper(平行光)
             * 用于模拟场景中平行光 DirectionalLight 的辅助对象. 其中包含了表示光位置的平面和表示光方向的线段。
             * DirectionalLightHelper( light : DirectionalLight, size : Number, color : Hex )
             * light-- 被模拟的光源
             * size – (可选的) 平面的尺寸. 默认为 1
             * color – (可选的) 如果没有设置颜色将使用光源的颜色
             *
             * SpotLightHelper(聚光灯)
             * 用于模拟聚光灯 SpotLight 的锥形辅助对象
             * SpotLightHelper( light : SpotLight, color : Hex )
             * light – 被模拟的聚光灯 SpotLight .
             * color – (可选的) 如果没有赋值辅助对象将使用光源的颜色
             *
             * RectAreaLightHelper(矩形面光源)
             * 创建一个表示 RectAreaLight 的辅助对象.
             * RectAreaLightHelper( light : RectAreaLight, color : Hex )
             * light – 被模拟的光源.
             * color – (可选) 如果没有赋值辅助对象将使用光源的颜色。
             *
             * HemisphereLightHelper(半球/户外光源)
             * 创建一个虚拟的球形网格 Mesh 的辅助对象来模拟 半球形光源 HemisphereLight.
             * HemisphereLightHelper( light : HemisphereLight, sphereSize : Number, color : Hex )
             * light – 被模拟的光源.
             * size – 用于模拟光源的网格尺寸.
             * color – (可选的) 如果没有赋值辅助对象将使用光源的颜色.
             */
    
    
            /**
             * 添加物体 new THREE.Mesh(Geometry, Material);  Geometry 为物体的形状,Material 为物体的材质;
             * a. 形状(Geometry)
             * 1.BoxGeometry--长方体
             * 2.CircleGeometry--圆形平面
             * 3.CylinderGeometry--圆柱体
             * 4.PlaneGeometry--方形平面
             * 5.RingGeometry--环形平面
             * 6.SphereGeometry--球形
             * 7.TextGeometry--文字
             * 8.TorusGeometry--圆环
             * 9.TubeGeometry--圆管
             * 还有根据坐标去生成具体形状的方法,可以借助第三方建模软件建模之后引入,转换为坐标后再生成,就可以做比较复杂的形状了,比如人脸、汽车等等。
             * b. 材质(Material)
             * 材质就像是物体的皮肤,决定物体外表的样子,例如物体的颜色,看起来是否光滑,是否有贴图等等。
             * 网格基础材质(MeshBasicMaterial) 该材质不受光照的影响,不需要光源即可显示出来,设置颜色后,各个面都是同一个颜色。
             * 网格朗博材质(MeshLambertMaterial) 该材质会受到光照的影响,没有光源时不会显示出来,用于创建表面暗淡,不光亮的物体。漫反射材质
             * 网格 Phong 材质(MeshPhongMaterial) 该材质会受到光照的影响,没有光源时不会显示出来,用于创建光亮的物体。镜面反射材质
             * 网格法向材质(MeshNormalMaterial) 该材质不受光照的影响,不需要光源即可显示出来,并且每个方向的面的颜色都不同,同但一个方向的面颜色是相同的,该材质一般用于调试。
             * MeshDepthMaterial--根据物体上每一点到摄像机的远近来显示颜色,远的显示黑色,近的显示白色
             */
                // 图片加载异步,render 时设置 setTimeout 延时 render 即可
            let box = this.getBox();
            box.position.set(20, 20, 20);
            scene.add(box);
            // 草地
            let num = 5; // 5 * 5
            for (let i = 1; i <= num; i++) {
                for(let j = 1; j <= num; j++) {
                    let grass = this.getGrass();
                    let k = (num + 1) / 2;
                    grass.position.set((i - k) * 40, -20, (j - k) * 40);
                    scene.add(grass);
                }
            }
    
            /**
             * 盒Helper对象,显示包围一个对象的线框盒。
             * BoxHelper(object)
             * object 要包裹的模型
             */
            // let box = new THREE.BoxHelper( obj );
            // scene.add(box);
    
            /**
             * 包围盒Helper对象,用于创建对象和世界轴对齐的包围盒的一个帮助对象。
             * BoundingBoxHelper(object, hex)
             */
            // let bbox = new THREE.BoundingBoxHelper(obj, 0xff0000);
            // scene.add(bbox);
    
            /**
             * 边缘Helper对象,绘制出构成三维模型每个面边缘线信息。
             * EdgesHelper(object, color, thresholdAngle)
             * object(画边界的对象)
             * color(边界颜色)
             * thresholdAngle(角的最小值)
             */
            // let edges = new THREE.EdgesHelper( obj, 0x00ff00 );
            // scene.add( edges );
    
            /**
             * 网格辅助线
             * GridHelper 本质上是对线模型对象 Line 的封装,纵横交错的直线构成一个矩形网格模型对象。
             * GridHelper( size : number, divisions : Number, colorCenterLine : Color, colorGrid : Color )
             * size -- 网格宽度,默认为 10.
             * divisions -- 等分数,默认为 10.
             * colorCenterLine -- 中心线颜色,默认 0x444444
             * colorGrid --  网格线颜色,默认为 0x888888
             * @type {GridHelper}
             */
            let gridHelper = new THREE.GridHelper(200, 10, 0x444444, 0xffffff);
            scene.add(gridHelper);
    
            /**
             * 三维坐标轴参考线
             * AxisHelper(size)
             * size(轴线长)
             * @type {AxisHelper}
             */
            let axes = new THREE.AxisHelper(100);
            scene.add(axes);
    
            /**
             * 箭头Helper对象,功能很简单就是添加一个箭头。
             * ArrowHelper( dir, origin, length, color, headLength, headWidth )
             * dir(方向向量)
             * origin(起点)
             * length(长度)
             * hex(颜色)
             * headLength(箭头长度)
             * headWidth(箭头宽度)
             */
            // let arrowYHelper = new THREE.ArrowHelper(// y 轴
            //     new THREE.Vector3(0, 10, 0),
            //     new THREE.Vector3(0, 0, 0),
            //     30, 0x00FF1C, 5, 3);
            // scene.add(arrowYHelper);
            // // x 轴
            // let arrowXHelper = new THREE.ArrowHelper(
            //     new THREE.Vector3(10, 0, 0),
            //     new THREE.Vector3(0, 0, 0),
            //     30, 0xFF0000, 5, 3);
            // scene.add(arrowXHelper);
            // // z 轴
            // let arrowZHelper = new THREE.ArrowHelper(
            //     new THREE.Vector3(0, 0, 10),
            //     new THREE.Vector3(0, 0, 0),
            //     30, 0x002EFF, 5, 3);
            // scene.add(arrowZHelper);
    
            // 渲染,设置延迟,物料材质贴图,需时间加载
            setTimeout(() => {
                // material.needsUpdate = true; // 可以隐藏,不用通知更新标记了
                renderer.render(scene, camera);
            }, 100);
    
            // 添加鼠标操作
            let controls = new OrbitControls(camera, renderer.domElement);
            // 动态阻尼系数 就是鼠标拖拽旋转灵敏度,阻尼越小越灵敏
            controls.dampingFactor = 0.5;
            // 是否可以缩放
            controls.enableZoom = true;
            //是否自动旋转
            controls.autoRotate = true;
            //设置相机距离原点的最近距离
            controls.minDistance = 20;
            //设置相机距离原点的最远距离
            controls.maxDistance = 1000;
            //是否开启右键拖拽
            controls.enablePan = true;
            //上下翻转的最大角度
            controls.maxPolarAngle = 3.5;
            //上下翻转的最小角度
            controls.minPolarAngle = 0;
            // 是否可以旋转
            controls.enableRotate = true;
            controls.addEventListener('change', () => {
                renderer.render(scene, camera);
            });
    
            // 用于动画
            function rotated () {
                requestAnimationFrame(rotated);
                // scene.rotation.y += 0.01; // 世界横向旋转
                // box.position.x += 0.3; // 盒子横向移动
                box.scale.x += 0.001; // 形变,目前没有固定方向,为双向形变
                renderer.render(scene, camera);
            }
            console.log(box);
            rotated();
        }
    
        /**
         * 获取盒子
         */
        getBox() {
            let geometry = new THREE.BoxGeometry(40, 40, 40);
            // let geometry = new THREE.SphereBufferGeometry(10, 10, 10); // 球体,方便查看边缘Helper
            // 测试使用无需光照材质
            // let material = new THREE.MeshNormalMaterial();
            let material = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load('./assets/box.png') });
            // // 物体
            return new THREE.Mesh(geometry, material);
        }
    
        /**
         * 获取草地块
         */
        getGrass() {
            let grass;
            let geometry = new THREE.BoxGeometry(40, 40, 40);
            let top = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load('./assets/grass-top.png') });
            let side = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load('./assets/grass-side.png') });
            let bottom = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load('./assets/grass-bottom.png') });
            // 物体,左右上下前后
            grass = new THREE.Mesh(geometry, [ side, side, top, bottom, side, side ]);
            return grass;
        }
    
        /**
         * 设置网格参考线
         * 使用 MeshBasicMaterial 无需光源即展示,方便设置坐标
         */
        setGrid(scene) {
            // 线条数
            let num = 10;
            // 间距
            let step = 20;
            // 粗细
            let width = 0.2;
            for (let i = 0; i <= num; i++) {
                let x = i - (num) / 2;
                // 长度
                let len = step * num;
                // 0,0 原点标线颜色特殊一下
                let color = x === 0 ? '#666' : '#fff';
                let lineM = new THREE.MeshBasicMaterial({ color: color });
                // 纵向线 depth
                let lineXG = new THREE.BoxGeometry(width, width, len);
                let lineX = new THREE.Mesh(lineXG, lineM);
                lineX.position.set(x * step, 0, 0);
                scene.add(lineX);
                // 横向线
                let lineZG = new THREE.BoxGeometry(step * num, width, width);
                let lineZ = new THREE.Mesh(lineZG, lineM);
                lineZ.position.set(0, 0, x * step);
                scene.add(lineZ);
            }
        }
    }

    效果: 

  • 相关阅读:
    Cookie、Session详解
    阿里云高速maven库
    java23种设计模式详解
    分布式和集群的区别
    2016 年 Java 优秀文章
    java任务调度
    解酒
    中医教你如何调理女性内分泌失调
    Oracle RedoLog-二进制格式分析,文件头,DML,DDL
    Oracle RedoLog-基本概念和组成
  • 原文地址:https://www.cnblogs.com/guofan/p/16288507.html
Copyright © 2020-2023  润新知