three.js 8 物体

import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper";

/**
 * 3d Object 物体
 * https://threejs.org/docs/index.html#api/zh/objects/Bone
 */
export class ThreeDoc8Object {
    constructor(canvasId) {
        this.work(canvasId);
    }

    work(canvasId) {
        // 创建 3d 场景
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x9e9e9e);

        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。
        document.body.appendChild(renderer.domElement);

        // AxesHelper  3个坐标轴的对象.
        this.addAxesHelper(scene);


        // 骨骼,什么的太难了,后续再看。。。Bone、Skeleton、SkinnedMesh

        //
        // let group = this.setGroup(scene);
        // 实例化网格(InstancedMesh) - 不知为何会无效
        // this.setInstancedMesh(scene)
        // 线
        // this.addLine(scene);
        // 环线(LineLoop) - 什么区别?
        // this.addLineLoop(scene);
        // 线段(LineSegments) - 22一对,组成线段
        // this.addLineSegments(scene);
        // 多细节层次(LOD,Levels of Detail) - 没观察出来什么细节东西
        // this.addLOD(scene);
        // 网格(Mesh)
        this.addMesh(scene);
        // 精灵(Sprite)
        this.addSprite(scene);


        // 包围盒辅助线框对象
        // const box = new THREE.BoxHelper(dodecahedron, 0xffff00);
        // scene.add(box);

        // 半球光(HemisphereLight)
        this.addHemisphereLight(scene);
        // 平面光光源(RectAreaLight)
        this.addRectAreaLight(scene);


        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        // 设置相机位置
        camera.position.x = 10;
        camera.position.y = 10;
        camera.position.z = 10;
        // camera.lookAt(0, 0, 0);

        // 添加控制器
        let orb = new OrbitControls(camera, document.body);
        orb.addEventListener('change', function () {
            renderer.render(scene, camera);
        });

        renderer.render(scene, camera);

        function animate() {
            requestAnimationFrame(animate);
            group.rotation.y += 0.01; // 组横向旋转
            renderer.render(scene, camera);
        }

        // animate();
    }

    /**
     * AxesHelper
     * 用于简单模拟3个坐标轴的对象.
     * 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
     * AxesHelper( size : Number )
     * size -- (可选的) 表示代表轴的线段长度. 默认为 1.
     */
    addAxesHelper(scene) {
        const axesHelper = new THREE.AxesHelper(12);
        scene.add(axesHelper);
    }

    /**
     * 半球光(HemisphereLight) - 喜欢这个光
     * 光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。
     * 半球光不能投射阴影。
     *
     * HemisphereLight( skyColor : Integer, groundColor : Integer, intensity : Float )
     * skyColor - (可选参数) 天空中发出光线的颜色。 缺省值 0xffffff。
     * groundColor - (可选参数) 地面发出光线的颜色。 缺省值 0xffffff。
     * intensity - (可选参数) 光照强度。 缺省值 1。
     */
    addHemisphereLight(scene) {
        const light = new THREE.HemisphereLight(0xffffbb, 0x080820, 100);
        scene.add(light);
        light.position.set(0, -10, 0);
        const helper = new THREE.HemisphereLightHelper(light, 3);
        scene.add(helper);
    }

    /**
     * 平面光光源(RectAreaLight) - 这个光源也不错!
     * 平面光光源从一个矩形平面上均匀地发射光线。这种光源可以用来模拟像明亮的窗户或者条状灯光光源。
     * 注意事项:
     * 不支持阴影。
     * 只支持 MeshStandardMaterial 和 MeshPhysicalMaterial 两种材质。
     * 你必须在你的场景中加入 RectAreaLightUniformsLib ,并调用init()。
     *
     * RectAreaLight( color : Integer, intensity : Float, width : Float, height : Float )
     * color - (可选参数) 十六进制数字表示的光照颜色。缺省值为 0xffffff (白色)
     * intensity - (可选参数) 光源强度/亮度 。缺省值为 1。
     * width - (可选参数) 光源宽度。缺省值为 10。
     * height - (可选参数) 光源高度。缺省值为 10。
     */
    addRectAreaLight(scene) {
        const width = 20;
        const height = 10;
        const intensity = 100;
        const rectLight = new THREE.RectAreaLight(0xffffff, intensity, width, height);
        rectLight.position.set(10, 10, 0);
        rectLight.lookAt(0, 0, 0);
        scene.add(rectLight);

        let rectLightHelper = new RectAreaLightHelper(rectLight);
        scene.add(rectLightHelper);
    }

    /**
     * 成组
     */
    setGroup(scene) {
        const lGeometry = new THREE.SphereGeometry(5, 32, 16);
        const sGeometry = new THREE.SphereGeometry(0.5, 32, 16);
        const material = new THREE.MeshStandardMaterial({ color: 0x049EF4 });

        const cubeL = new THREE.Mesh(lGeometry, material);
        cubeL.position.set(0, 0, 0);

        const cubeS = new THREE.Mesh(sGeometry, material);
        cubeS.position.set(-5, 0, -5);

//create a group and add the two cubes
//These cubes can now be rotated / scaled etc as a group
        const group = new THREE.Group();
        group.add(cubeL);
        group.add(cubeS);

        scene.add(group);

        const box = new THREE.BoxHelper(group, 0xffff00);
        scene.add(box);

        return group;
    }

    /**
     * 实例化网格(InstancedMesh)
     * 一种具有实例化渲染支持的特殊版本的Mesh。你可以使用 InstancedMesh 来渲染大量具有相同几何体与材质、但具有不同世界变换的物体。
     * 使用 InstancedMesh 将帮助你减少 draw call 的数量,从而提升你应用程序的整体渲染性能。
     * InstancedMesh( geometry : BufferGeometry, material : Material, count : Integer )
     * geometry - 一个 BufferGeometry 的实例。
     * material - 一个 Material 的实例。默认为一个新的 MeshBasicMaterial 。
     * count - 实例的数量
     */
    setInstancedMesh(scene) {
        const geometry = new THREE.SphereGeometry(0.5, 32, 16);
        const material = new THREE.MeshStandardMaterial({ color: 0x049EF4 });
        let mesh = new THREE.InstancedMesh(geometry, material, 10);
        // mesh.instanceMatrix.setUsage( DynamicDrawUsage ); // will be updated every frame
        scene.add(mesh);
    }

    /**
     * 线(Line)
     * 一条连续的线。
     * Line( geometry : BufferGeometry, material : Material )
     * geometry —— 表示线段的顶点,默认值是一个新的BufferGeometry。
     * material —— 线的材质,默认值是一个新的具有随机颜色的LineBasicMaterial。
     */
    addLine(scene) {
        const material = new THREE.LineBasicMaterial({
            color: 0x049EF4
        });

        const step = 3;
        const points = [
            new THREE.Vector3(-step, 0, 0),
            new THREE.Vector3(0, step, 0),
            new THREE.Vector3(step, 0, 0),
            new THREE.Vector3(0, -step, 0),
            new THREE.Vector3(-step, 0, 0),
            new THREE.Vector3(0, 0, -step),
            new THREE.Vector3(step, 0, 0),
            new THREE.Vector3(0, 0, step),
            new THREE.Vector3(0, -step, 0),
        ];
        points.push(points);

        const geometry = new THREE.BufferGeometry().setFromPoints(points);

        const line = new THREE.Line(geometry, material);

        const box = new THREE.BoxHelper(line, 0xffff00);
        scene.add(box);
        scene.add(line);
    }

    /**
     * 环线(LineLoop)
     * 一条头尾相接的连续的线。
     *
     * 它几乎和Line是相同的,唯一的区别是它在渲染时使用的是gl.LINE_LOOP, 而不是gl.LINE_STRIP, 它绘制一条直线到下一个顶点,
     * 并将最后一个顶点连回第一个顶点。
     * LineLoop( geometry : BufferGeometry, material : Material )
     * geometry —— 表示环线上的点的顶点列表。
     * material —— 线的材质,默认值是LineBasicMaterial。
     * @param scene
     */
    addLineLoop(scene) {
        const material = new THREE.LineBasicMaterial({
            color: 0x049EF4
        });

        const step = 3;
        const points = [
            new THREE.Vector3(-step, 0, 0),
            new THREE.Vector3(0, step, 0),
            new THREE.Vector3(step, 0, 0),
            new THREE.Vector3(0, -step, 0),
        ];
        points.push(points);

        const geometry = new THREE.BufferGeometry().setFromPoints(points);

        const line = new THREE.LineLoop(geometry, material);

        const box = new THREE.BoxHelper(line, 0xffff00);
        scene.add(box);
        scene.add(line);
    }

    /**
     * 线段(LineSegments)
     * 在若干对的顶点之间绘制的一系列的线。
     *
     * 它和Line几乎是相同的,唯一的区别是它在渲染时使用的是gl.LINES, 而不是gl.LINE_STRIP。
     * LineSegments( geometry : BufferGeometry, material : Material )
     * geometry —— 表示每条线段的两个顶点。
     * material —— 线的材质,默认值是LineBasicMaterial。
     * @param scene
     */
    addLineSegments(scene) {
        const material = new THREE.LineBasicMaterial({
            color: 0x049EF4
        });

        const step = 3;
        const points = [
            new THREE.Vector3(-step, -step / 2, -step / 2),
            new THREE.Vector3(step, -step / 2, -step / 2),
            new THREE.Vector3(-step, step / 2, -step / 2),
            new THREE.Vector3(step, step / 2, -step / 2),
            new THREE.Vector3(-step, -step / 2, step / 2),
            new THREE.Vector3(step, -step / 2, step / 2),
            new THREE.Vector3(-step, step / 2, step / 2),
            new THREE.Vector3(step, step / 2, step / 2),
            new THREE.Vector3(-step / 2, step / 2, step),
            new THREE.Vector3(-step / 2, step / 2, -step),
            new THREE.Vector3(step / 2, step / 2, step),
            new THREE.Vector3(step / 2, step / 2, -step),
            new THREE.Vector3(-step / 2, -step / 2, step),
            new THREE.Vector3(-step / 2, -step / 2, -step),
            new THREE.Vector3(step / 2, -step / 2, step),
            new THREE.Vector3(step / 2, -step / 2, -step),
            new THREE.Vector3(step / 2, step, step / 2),
            new THREE.Vector3(step / 2, -step, step / 2),
            new THREE.Vector3(step / 2, step, -step / 2),
            new THREE.Vector3(step / 2, -step, -step / 2),
            new THREE.Vector3(-step / 2, step, step / 2),
            new THREE.Vector3(-step / 2, -step, step / 2),
            new THREE.Vector3(-step / 2, step, -step / 2),
            new THREE.Vector3(-step / 2, -step, -step / 2),
        ];
        points.push(points);

        const geometry = new THREE.BufferGeometry().setFromPoints(points);

        const line = new THREE.LineSegments(geometry, material);

        const box = new THREE.BoxHelper(line, 0xffff00);
        scene.add(box);
        scene.add(line);
    }

    /**
     * 多细节层次(LOD,Levels of Detail)
     * 多细节层次 —— 在显示网格时,根据摄像机距离物体的距离,来使用更多或者更少的几何体来对其进行显示。
     *
     * 每一个级别都和一个几何体相关联,且在渲染时,可以根据给定的距离,来在这些级别对应的几何体之间进行切换。 通常情况下,你会创建多个几何体,
     * 比如说三个,一个距离很远(低细节),一个距离适中(中等细节),还有一个距离非常近(高质量)。
     * @param scene
     */
    addLOD(scene) {
        const lod = new THREE.LOD();
        //Create spheres with 3 levels of detail and create new LOD levels for them
        for (let i = 0; i < 3; i++) {
            const geometry = new THREE.IcosahedronGeometry(10, 3 - i);
            const material = new THREE.LineBasicMaterial({ color: 0x049EF4 });
            const mesh = new THREE.Mesh(geometry, material);
            lod.addLevel(mesh, i * 75);
        }
        scene.add(lod);
    }

    /**
     * 网格(Mesh)
     * 表示基于以三角形为polygon mesh(多边形网格)的物体的类。 同时也作为其他类的基类,例如SkinnedMesh。
     * Mesh( geometry : BufferGeometry, material : Material )
     * geometry —— (可选)BufferGeometry的实例,默认值是一个新的BufferGeometry。
     * material —— (可选)一个Material,或是一个包含有Material的数组,默认是一个新的MeshBasicMaterial。
     * @param scene
     */
    addMesh(scene) {
        const geometry = new THREE.SphereGeometry( 1, 32,16 );
        const material = new THREE.MeshBasicMaterial( { color: 0x049EF4 } );
        const mesh = new THREE.Mesh( geometry, material );

        let edges = new THREE.EdgesHelper(mesh, 0x00ff00);
        scene.add(edges);

        scene.add( mesh );
    }

    /**
     * 精灵(Sprite)
     * 精灵是一个总是面朝着摄像机的平面,通常含有使用一个半透明的纹理。
     * 精灵不会投射任何阴影,即使设置了 castShadow = true 也将不会有任何效果。
     * Sprite( material : Material )
     * material - (可选值)是SpriteMaterial的一个实例。 默认值是一个白色的SpriteMaterial。
     * @param scene
     */
    addSprite(scene) {
        const map = new THREE.TextureLoader().load( "assets/floor-wb.png" );
        const material = new THREE.SpriteMaterial( { map: map } );

        const sprite = new THREE.Sprite( material );
        sprite.scale.set(10, 10, 0);
        scene.add( sprite );
    }
}

 

posted @ 2022-06-01 09:10  名字不好起啊  阅读(71)  评论(0编辑  收藏  举报