相关文档:
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