当前位置: 首页 > Web前端 > HTML

three.js练习3D渲染

时间:2023-03-28 14:30:39 HTML

需求分析因为业务需要能够对上传的3D模型数据进行渲染,初衷是为了支持根据不同的数据格式进行不同的渲染,所以想到了使用three.js来实现这个功能。本来想直接从网上学习我的内容,因为我们的技术选型是React,所以一开始我们尝试用github上别人配置的一些react-3,但是好像没有我需要的,于是有了自己做。其实整体的实现方法就是按照上面三个官方文档的参数设置的,废话不多说,直接上传代码:importcomponentsimportReact,{Component,Fragment}from'react'import*asTHREEfrom'three'//从'three/examples/jsm/loaders/OBJLoader'导入{OBJLoader}从'three/examples/jsm/loaders/GLTFLoader'导入{GLTLoader}从'three/examples/jsm/controls/OrbitControls'//import{MTLLoader}from'three/examples/jsm/loaders/MTLLoader'importFileServicefrom'@/services/FileService'import'./styles.less'contentrenderingclassOnline3DViewextendsComponent{constructor(props){super(props)this.state={isModel:false,currentName:'nonameyet',clientX:0,clientY:0,}this.threeRef=React.createRef()}componentDidMount(){const{height,width,fileId}复制代码=this.propsletthat=this//加载要渲染的文件的数据Stream(Blob)FileService.downloadForPreview(fileId).then((res)=>{consturl=window.URL.createObjectURL(res)//todo初始化场景constscene=newTHREE.Scene()//todo加载cameraconstcamera=newTHREE.PerspectiveCamera(60,width/height,0.1,80)camera.position.set(1,25,25)camera.lookAt(newTHREE.Vector3(0,0,0))//todo加载光constambLight=newTHREE.AmbientLight(0x404040,1)constpointLight=newTHREE.PointLight(0x404040,0.8)constdirectionalLight=newTHREE.DirectionalLight(0xffffff,1)pointLight.position.set(100,10,0)pointLight.receiveShadow=truescene.add(ambLight)scene.add(pointLight)scene.add(directionalLight)//todo渲染器constrenderer=newTHREE.WebGLRenderer({antialias:true,})renderer.setSize(width,height-10)renderer.setClearColor(0xb9d3ff,1)//这里使用哪种loader需要构建对应的loader,我这里使用的是glb文件类型,所以加载了这个letglbLoader=newGLTFLoader()glbLoader.load(网址,函数(glTF){glTF.scene.traverse(function(child){if(glTF.isMesh){glTF.frustumCulled=false//模型阴影glTF.castShadow=true//模型自发光glTF.material.emissive=glTF.material.colorglTF.material.emissiveMap=glTF.material.map}})scene.add(glTF.scene)//todo场景控制器初始化constcontrols=newOrbitControls(camera,renderer.domElement)controls.enabled=true//鼠标控件是否可用//是否自动旋转controls.autoRotate=truecontrols.autoRotateSpeed=0.05//是否旋转,旋转速度(鼠标左键)controls.enableRotate=truecontrols.rotateSpeed=0.3//controls.target=newTHREE.Vector();//相机聚焦于某一点//最大和最小相机移动距离(景深相机)controls.minDistance=10controls.maxDistance=100//最大仰角和俯角controls.minPolarAngle=Math.PI/4//45度视角controls.maxPolarAngle=Math.PI/1//75度视角//惯性滑动,滑动大小默认0.25controls.enableDamping=truecontrols.dampingFactor=0.25//是否可以平移,默认移动速度为7pxcontrols.enablePan=truecontrols.panSpeed=0.5//controls.screenSpacePanning=true;//滚轮缩放控制controls.enableZoom=truecontrols.zoomSpeed=1.5//水平视角限制//controls.minAzimuthAngle=-Math.PI/4;//controls.maxAzimuthAngle=Math.PI/4;//todo绑定到类that.scene=scenethat.camera=camerathat.renderer=rendererthat.controls=controls//鼠标移入移出事件高亮选中模型that.currentObjectColor=null//颜色themodelthatismovedinthat.currentObject=null//鼠标移动到的模型//初始化场景//加载到dom元素上that.threeRef.current.appendChild(that.renderer.domElement)that.start()that.resizeFunc1()that.resizeFunc2()})}).catch((err)=>{})window.addEventListener('resize',this.resizeFunc1,false)window.addEventListener('resize',this.resizeFunc2,false)}componentWillUnmount(){this.stop()this.renderer&&this.threeRef.current.removeChild(this.renderer.domElement)window.removeEventListener('resize',this.resizeFunc1,false)window.removeEventListener('resize',this.resizeFunc2,false)}//初始化start=()=>{if(!this.frameId){this.frameId=requestAnimationFrame(this.animate)}}//执行组件的时候去删除stop=()=>{cancelAnimationFrame(this.frameId)}//更新状态animate=()=>{this.controls.update()this.renderScene()this.frameId=requestAnimationFrame(this.animate)}renderScene=()=>{this.renderer.render(this.scene,this.camera)}closeModel=(e)=>{e.stopPropagation()if(this.controls&&!this.controls.autoRotate){this.controls.autoRotate=true}this.setState({isModel:false,})}resizeFunc1=()=>{this.controls.update()}resizeFunc2=(e)=>{constdom=document.getElementById('test_three')const{offsetWidth,offsetHeight}=domthis.camera.aspect=offsetWidth/offsetHeightthis.camera.updateProjectionMatrix()this.renderer.setSize(offsetWidth,offsetHeight)}render(){return()}}使用他