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 ); } }