threejs

102 阅读12分钟

相关文档:

three.js文档: www.yanhuangxueyuan.com/Three.js/

requestAnimationFrame详解: www.jianshu.com/p/fa5512dfb…`


import * as Three from 'three' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; interface ThreeGlbType {     canvas: HTMLElement     gldSrc: string } class ThreeGlb {     canvas: HTMLElement     camera: any     scene: any     renderer: any     ambientLight: any     controls: any     loader: any     gldSrc: string     defaultCamera: any     options: any     axesCorner: any     content: any     state: any     vignette: any     constructor(props: ThreeGlbType) {         this.state = {             environment: 'Venice Sunset',             background: false,             playbackSpeed: 1.0,             actionStates: {},             camera: '[default]',             wireframe: false,             skeleton: false,             grid: false,             // Lights             addLights: true,             exposure: 1.0,             textureEncoding: 'sRGB',             ambientIntensity: 0.3,             ambientColor: 0xFFFFFF,             directIntensity: 0.8 * Math.PI, // TODO(#116)             directColor: 0xFFFFFF,             bgColor1: '#ffffff',             bgColor2: '#353535'         };         this.canvas = props.canvas         this.gldSrc = props.gldSrc         this.init()     }     // 初始化方法     init() {         this.defaultCamera = new Three.PerspectiveCamera(60, this.canvas.clientWidth / this.canvas.clientHeight, 0.01, 1000);         // 创建场景         this.scene = new Three.Scene()         //设置场景背景颜色         this.scene.background = new Three.Color(0xeaeaea);         // 创建相机         this.camera = new Three.PerspectiveCamera(75, this.canvas.clientWidth / this.canvas.clientHeight, 0.1, 1000);         //相机角度         this.camera.position.x = 150;         this.camera.position.z = 50;         this.camera.position.y = 100;         //渲染器         this.renderer = new Three.WebGLRenderer({             gammaInput: true, //如果设置,那么它期望所有纹理和颜色都是预乘伽马。默认值为false。             gammaOutput: true         })         // 曝光值         this.renderer.outputEncoding = Three.sRGBEncoding;         this.renderer.toneMapping = Three.ReinhardToneMapping         //渲染器大小         this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);         this.canvas.appendChild(this.renderer.domElement);         console.log('12009766');                 // 添加灯光         this.ambientLight = new Three.AmbientLight(this.state.ambientColor, this.state.ambientIntensity);         var point = new Three.PointLight(0xffffff, 1) //光源设置         point.position.set(300, 400, 200) //点光源位置         this.scene.add(point) //将光源添加到场景中         var ambient = new Three.AmbientLight(0xffffff, 1) //环境光         ambient.position.set(200, 300, 200) //点光源位置         this.scene.add(ambient)         var directionalLight = new Three.DirectionalLight(0xffffff, 1) //方向光         directionalLight.position.set(150, 300, 200)         this.scene.add(directionalLight)         var spotLight = new Three.SpotLight(0xffffff, 1) //聚光灯         spotLight.position.set(150, 200, 200)         this.scene.add(spotLight)         //把灯光放入到场景中         this.scene.add(this.ambientLight)         // this.defaultCamera.add(this.ambientLight);         //添加控制器         this.controls = new OrbitControls(this.camera, this.renderer.domElement);         //开启控制器         this.controls.enableZoom = true;         //禁止鼠标交互,此处设置为false之后,不能移动位置,不能旋转物体         this.controls.enableRotate = true;         this.axesCorner = new Three.AxesHelper(5);         this.scene.add(this.vignette);         // 开始加载文件         this.GLTloader()     }     GLTloader() {         //获取loader         this.loader = new GLTFLoader         let dracoLoader = new DRACOLoader();         dracoLoader.setDecoderPath('/biosen/gltf/'); // 设置public下的解码路径,注意最后面的/         this.loader.setDRACOLoader(dracoLoader)         //开始加载 第一个参数加载成功的回调 第二个参数是加载中的回调 第三个是加载失败的回调         this.loader.load(this.gldSrc, (gltf) => {             //往场景中添加模型             gltf.scene.traverse(function (child) {                 if (child.isMesh) {                     child.frustumCulled = false;                     //模型阴影                     child.castShadow = true;                     //模型自发光                     child.material.emissive = child.material.color;                     child.material.emissiveMap = child.material.map;                 }             })             this.setContent(gltf.scene)             //监听鼠标事件             this.controls.addEventListener('change', this.render);             //开始渲染             this.render()         }, () => { }, (err) => {             console.log(err);         })     }     render() {         // 开始渲染场景和相机         this.renderer?.render(this.scene, this.camera)         //1、requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。         // 2、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。         window.requestAnimationFrame(this.render.bind(this))     } //场景配置函数     setContent(object) {         const box = new Three.Box3().setFromObject(object);         const size = box.getSize(new Three.Vector3()).length();         const center = box.getCenter(new Three.Vector3());         this.controls.reset();         object.position.x += (object.position.x - center.x);         object.position.y += (object.position.y - center.y);         object.position.z += (object.position.z - center.z);         this.controls.maxDistance = size * 10;         this.defaultCamera.near = size / 100;         this.defaultCamera.far = size * 100;         this.defaultCamera.position.copy(center);         this.defaultCamera.position.x += size / 2.0;         this.defaultCamera.position.y += size / 5.0;         this.defaultCamera.position.z += size / 2.0;         this.defaultCamera.lookAt(center);         this.camera.position.copy(this.defaultCamera.position)         this.camera.lookAt(this.scene.position)         this.camera.near = size / 100;         this.camera.far = size * 100;         this.camera.updateProjectionMatrix();         this.axesCorner.scale.set(size, size, size);         this.controls.saveState();         this.scene.add(object);         this.content = object;         this.state.addLights = true;         this.content.traverse((node) => {             if (node.isLight) {                 this.state.addLights = false;             } else if (node.isMesh) {                 // TODO(https://github.com/mrdoob/three.js/pull/18235): Clean up.                 node.material.depthWrite = !node.material.transparent;             }         });     } }; export default ThreeGlb