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); } } }
效果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2017-05-19 select2 插件 - 多选功能