Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。你可以在它的主页上看到许多精彩的演示。官方地址:http://www.webgl3d.cn/
这里会说到导入fbx模型,以及在开发中遇到的问题,最后是怎么解决的
npm install three
npm install --save @types/three
<section class="pane-box" id="threeBox">
<div id="myThree" />
</section>
代码如下(示例):
import * as THREE from 'three'
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader"
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
代码如下(示例):
import BG from "@/assets/fbxResource/envImg/bg.jpeg";
import negx from "@/assets/img/negx.png";
import negy from "@/assets/img/negy.png";
import negz from "@/assets/img/negz.png";
import posx from "@/assets/img/posx.png";
import posy from "@/assets/img/posy.png";
import posz from "@/assets/img/posz.png";
//模型加载器
let FBXModule = new FBXLoader();
//模型,这里可以引入多个模型
const models = {name:'像素人',path:"./public/blueMan.fbx",position:[0, 0, 0],type:'fbx'}
这里写了加载了3中背景,我的项目中只用到了背景图片
Scene(){
this.Scene = new THREE.Scene()
//设置背景色
// this.Scene.background = new THREE.Color(0xffffff);
//设置背景图
this.Scene.background = new THREE.TextureLoader().load(BG)
//设置3d环境背景图
// this.Scene.background = new THREE.CubeTextureLoader().load([posx,negx,posy,negy,posz,negz,]);
THREE.Cache.enabled = true;
console.log("scene...",this.Scene)
// this.Scene.background = textureCube
}
Renderer(){
this.Renderer = new THREE.WebGLRenderer({antialias: true,alpha: true,premultipliedAlpha:true,precision: 'highp'})
this.Renderer.setPixelRatio(window.devicePixelRatio);
this.Renderer.setSize(threeBox.clientWidth, threeBox.clientHeight - 20);
this.Renderer.setClearColor(0x00ff00);
//允许在场景中使用阴影贴图
this.Renderer.shadowMap.enabled = true;
//是否使用物理上正确的光照模式
this.Renderer.physicallyCorrectLights = true;
//定义渲染器的输出编码
this.Renderer.outputEncoding = THREE.sRGBEncoding;
myThree.appendChild(this.Renderer.domElement);
}
这里提到两种相机,不知道区别的小伙伴 去官网看看
Camera(){
let canvasSize = threeBox.clientWidth / threeBox.clientHeight; //窗口宽高比
//透视摄像机
this.Camera = new THREE.PerspectiveCamera(45, canvasSize,1, 100000)
//正交摄像机
//let k = 500 / 600;
//let s = 10;
//this.Camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 2000);//创建相机对象
this.Camera.position.set(200, 500, 300);
this.Camera.lookAt(this.Scene.position)
}
//包围盒全自动计算:模型整体居中
let ModelAutoCenter = function(group:any){
let box3 = new THREE.Box3()
// 计算层级模型group的包围盒
// 模型group是加载一个三维模型返回的对象,包含多个网格模型
box3.expandByObject(group)
// 计算一个层级模型对应包围盒的几何体中心在世界坐标中的位置
let center = new THREE.Vector3()
box3.getCenter(center)
// 重新设置模型的位置,使之居中。
group.position.x = group.position.x - center.x
group.position.y = group.position.y - center.y
group.position.z = group.position.z - center.z
console.log("center.x", group.position.y,center.y)
}
modelLoader(MODEL:any){
const loadTip:any = this.addLoadTip();
this.Controls.autoRotate = false;
let MTYPE = MODEL.type;
console.log("Model22222---",MTYPE)
FBXModule.load(MODEL.path, (geometry:any)=> {
loadTip.textContent='加载完成!';
//移除模型
// this.Model && this.Scene.remove(this.Model);
console.log("Model111---",this.Model)
//@ts-ignore
this.Model && myThree.children[0].remove();
//设置相机位置
this.Camera.position.set(...MODEL.position);
//当前模型
this.Model = 'fbx'.indexOf(MTYPE)!=-1?geometry:geometry.scene;
console.log("Model22---",this.Model)
//初始化当前模型
MODEL.init && MODEL.init(this.Model,geometry)
//默认遍历模型字节点,获取相关参数设置 特殊模型前往init回调中设置
let that = this;
this.Model.traverse((child:any) => {
if(child.isMesh) {
child.material.emissiveMap = child.material.map;
}
})
//模型自动居中
ModelAutoCenter(geometry)
//加载完成后开始自动播放
setTimeout(() => {
loadTip.style.display = 'none';
}, 1000);
this.Scene.add(this.Model);
},
(xhr:any)=>{
//加载进度
//@ts-ignore
loadTip.textContent=(parseInt(xhr.loaded/xhr.total*100)+'%加载中...');
},
(err:any)=>{
loadTip.textContent='模型加载失败!'
}
);
}
addLight(){
this.Lights = [
//平行光(DirectionalLight)
// color 光的颜色。 缺省值为 0xffffff (白色)。intensity - (可选参数) 光照的强度。缺省值为1。
{name:'AmbientLight',obj:new THREE.AmbientLight(0xFFFFFF,2.2)},
{name:'DirectionalLight_top',obj:new THREE.DirectionalLight(0xFFFFFF,2.2),position:[10, 80,65]},
{name:'DirectionalLight_bottom',obj:new THREE.DirectionalLight(0x1B1B1B,2.2),position:[10, 80,65]},
{name:'DirectionalLight_right1',obj:new THREE.DirectionalLight(0xFFFFFF,2.2),position:[10, 80,65]},
{name:'DirectionalLight_right2',obj:new THREE.DirectionalLight(0xFFFFFF,2.2),position:[10, 80,65]},
];
this.Lights.map((item:any)=>{
item.obj.name=item.name;
item.position && item.obj.position.set(...item.position);
item.Helper = new THREE.PointLightHelper( item.obj );
this.Scene.add(item.obj);
})
}
addControls() {
this.Controls = new OrbitControls(this.Camera, this.Renderer.domElement);
// 如果使用animate方法时,将此函数删除
//controls.addEventListener( 'change', render );
// 使动画循环使用时阻尼或自转 意思是否有惯性
this.Controls.enableDamping = false;
//是否可以缩放
this.Controls.enableZoom = true;
//设置相机距离原点的最远距离-可以控制缩放程度
this.Controls.minDistance = 0;
//设置相机距离原点的最远距离
this.Controls.maxDistance = 3000;//800
//是否开启右键拖拽
this.Controls.enablePan = true;
//动态阻尼系数 就是鼠标拖拽旋转灵敏度
this.Controls.dampingFactor = 0.5;
//是否自动旋转
this.Controls.autoRotate = false;
this.Controls.autoRotateSpeed = 1;
}
addLoadTip(){
document.querySelector('.loadTip') && myThree.removeChild(document.querySelector('.loadTip'));
let loadTip = document.createElement('div');
loadTip.className='loadTip'
loadTip.style.cssText+='position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);border-radius:5px;background-color:rgba(0,0,0,0.5);padding:5px 10px;color:#fff;';
myThree.appendChild(loadTip);
return loadTip;
}
animation(){
//更新控制器
this.Renderer.render(this.Scene, this.Camera);
this.Controls.update();
this.AnimationMixer && this.AnimationMixer.update(this.Tclock.getDelta());
requestAnimationFrame(()=>this.animation());
},
onWindowResize() {
//@ts-ignore
this.Camera.aspect = threeBox.clientWidth / threeBox.clientHeight ;
this.Camera.updateProjectionMatrix();
//@ts-ignore
this.Renderer.setSize(threeBox.clientWidth, threeBox.clientHeight - 20);
this.Renderer.render(this.Scene, this.Camera);
},
run(){
return new Promise((resolve, reject) => {
this.init.Renderer.call(this)
this.init.Scene.call(this)
this.init.Camera.call(this)
this.addControls();
//添加环境光
this.addLight()
this.modelLoader(models);
this.animation();
//添加辅助面板
window.onresize = ()=>this.onWindowResize();
resolve(modelScene)
})
}
import { modelScene } from "./loadFbx";
setTimeout(()=>{
modelScene.run()
},1000)
例如:以上就是今天要讲的内容,本文仅仅简单介绍了three的导入fbx的使用