VUE3+ VITE 使用Three.js展示3D模型

学习主要文献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>

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值