学习主要文献: 1. threejs文件包下载和目录简介 | Three.js中文网
3D模型这里有下载网站:Sketchfab - The best 3D viewer on the web (邮箱注册后有免费的模型下载)
3D模型编辑软件:Blender windows环境微软应用市场可以直接获取安装最新版本。
里面有详细的安装环境介绍和各个功能组件的介绍,相对简单移动。还可以结合学习网站(bilibili)视频综合学习一下,感觉还不错~
这里主要记录一些比较容易出现的问题:
1. 画面不显示:展示要有渲染器(WebGLRenderer),渲染器里面有两个参数对象:
场景(Scene),场景里面可以添加光源(Light)、辅助线(AxesHelper)、模型(Group),模型加载3D模型OBJ文件加载器(OBJLoader和MTLLoader),GLTF和GLB文件加载器(GLTFLoader)。
相机(Camera),position.set设置坐标很重要,设置不对可能因为太小,或者位置不对造成看不到模型。
跟着中文网内容走,可以画出一个基本的3D图形(角度看起来像平面,结合组件事件监听和11. 动画渲染循环 | Three.js中文网 和这章内容可以旋转起来看)。详细的下方代码是加载的3D模型 ,可以直接放入模型后使用。
2. 发布打包的时候本地资源引用异常:
把3D的本地资源引用放入public文件夹中。load函数的路径在外面单独声明,就好了。
3. light的打光位置,这个因3D模型而异,我这边办法只能慢慢调,不知道咋引用Blender里面的灯光角度。
4. 3D模型的默认显示位置:
调整相机调整
完整VUE代码:
<script setup>
import {onMounted, ref, reactive} from 'vue'
import * as THREE from 'three';
//加载自定义3D模型
// 引入gltf模型加载库GLTFLoader.js
import {GLTFLoader} from 'three/addons/loaders/GLTFLoader.js';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
//加载OBJ3D
import {MTLLoader} from 'three/examples/jsm/loaders/MTLLoader'
import {OBJLoader} from "three/examples/jsm/loaders/OBJLoader"
const three9038 = "./59_9038.glb";
//创建场景载体
const scene = new THREE.Scene();
const loader = new GLTFLoader();//三维模型加载器
const model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景
const data = reactive({
index: 2,
x: 5,
y: 5,
z: 5,
isHelper: false,//是否开启了辅助线
isAutoRotate: false,//是否开启了自动旋转
})
const mtlLoader2 = new MTLLoader()
const objLoader2 = new OBJLoader()
//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
//光源设置
// const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// directionalLight.position.set(92, 100, 100);
// scene.add(directionalLight);
// const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
// directionalLight2.position.set(-92, -100, -100);
// scene.add(directionalLight2);
const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight2.position.set(50, 100, -100);
scene.add(directionalLight2);
//渲染器和相机
const width = window.innerWidth;
const height = width / 1.5 > 500 ? 500 : width / 1.5;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(150, 300, 200);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xffffff);//画布颜色
renderer.setSize(width, height);
renderer.antialias = true;
renderer.alpha = true;
renderer.precision = 'mediump'
renderer.setPixelRatio(window.devicePixelRatio);
//解决加载gltf格式模型颜色偏差问题
renderer.outputEncoding = THREE.sRGBEncoding;
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// controls.maxPolarAngle = 1.5 // 上下翻转的最大角度
// controls.minPolarAngle = -1.5 // 上下翻转的最小角度
// 渲染循环
function render() {
renderer.render(scene, camera);
if (data.isAutoRotate) {
controls.autoRotate = true // 是否自动旋转
controls.update();
} else {
controls.autoRotate = false // 是否自动旋转
}
const id = requestAnimationFrame(render);
// console.log("render--->" + id)
}
render();
// // 画布跟随窗口变化
// window.onresize = function () {
// renderer.setSize(window.innerWidth, window.innerHeight);
// camera.aspect = window.innerWidth / window.innerHeight;
// camera.updateProjectionMatrix();
// };
defineProps({
msg: '上面传下来的',
})
function addUI() {
console.log("开始加载渲染-->")
document.getElementById('webgl1').appendChild(renderer.domElement);
document.getElementById('webgl1').addEventListener('click', function (e) {
console.log("x------>" + camera.position.x)
console.log("y------>" + camera.position.y)
console.log("z------>" + camera.position.z)
// data.x = camera.position.x + 1;
// data.y = camera.position.y;
// data.z = camera.position.z;
// camera.position.set(data.x, data.y, data.z); //x轴方向观察
// camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
}
onMounted(() => {
addUI();
helperControl(false);
autoRotateControl(true);
draw3D();
})
//辅助函数
function helperControl(isOpen) {
if (data.isHelper === isOpen) return;
data.isHelper = isOpen;
if (data.isHelper) {
scene.add(axesHelper);
} else {
scene.remove(axesHelper);
}
}
function autoRotateControl(isOpen) {
console.log("----->" + isOpen);
if (data.isAutoRotate === isOpen) return;
data.isAutoRotate = isOpen;
}
function draw3D() {
data.index++;
if (data.index === 1) {
mtlLoader2.load('../../static/9038.mtl', material => {
material.preload()
//mtl文件中的材质设置到obj加载器
console.log(material.materials)
objLoader2.setMaterials(material)
objLoader2.load(
'../../static/9038.obj',
loadedMesh => {
console.log(loadedMesh)
//设置模型大小
loadedMesh.scale.set(1, 1, 1)
//设置模型位置
loadedMesh.position.set(5, 5, 5);
scene.add(loadedMesh)
camera.position.set(400, 400, 400);
}
)
})
} else if (data.index === 2) {
// 加载gltf/glb三维模型
loader.load('../../static/scene.gltf', function (gltf) {
console.log('gltf load ---->', gltf.scene);
model.add(gltf.scene);
})
scene.add(model); // 模型对象添加到场景中
camera.position.set(data.x, data.y, data.z);
} else if (data.index === 3) {
// 加载gltf/glb三维模型
loader.load(three9038, function (gltf) {
console.log('gltf load ---->', gltf.scene);
model.add(gltf.scene);
})
scene.add(model); // 模型对象添加到场景中
}
}
</script>
<template>
<h1>{{ msg }}----{{ data.index }}</h1>
<div id="webgl1" class="divThree"></div>
<br>
<button @click="helperControl(true)">开启坐标辅助线</button>
<button @click="helperControl(false)">关闭坐标辅助线</button>
<button @click="autoRotateControl(true)">开启自动旋转</button>
<button @click="autoRotateControl(false)">停止自动旋转</button>
<button @click="draw3D()">换一个3D模型</button>
</template>
<style scoped>
root {
padding: 0px;
}
.divThree {
width: auto;
height: auto;
align-items: center;
margin: 0px auto;
background-color: green;
}
button {
margin-left: 1em;
margin-top: 1em;
}
</style>