ThreeJS之GLB 预览

主要介绍了预览 3D 文件的插件,如 vue-model-viewer、vue-3d-model、@google/model-viewer;也介绍了 three.js 的基础使用及配置,例如场景、相机、渲染器、轨道控制器、灯光等等

第三方插件

找到了如下第三方插件,用起来挺方便的,支持多种 3D 文件格式,包括 glb、gltf 等

但是不支持vue2.x,只支持vue3.x版

  1. vue-model-viewer:提供了一个 Vue 组件,使在 Vue 项目中集成和使用更加方便;支持多种 3D 文件格式,包括 glb、gltf 等
  2. vue-3d-model:简单易用,适合快速集成 3D 模型预览功能;支持多种 3D 文件格式
  3. @google/model-viewer:提供了丰富的交互和功能,如 AR 支持、动画、交互等。

正方体预览(three.js)

有一个红色的正方体 Box.glb 文件,

GLTF 在线编辑器中预览效果如下所示:

项目之前用的是vue2.x版本,没法用上面的第三方工具,用three.js渲染展示

使用 three.js 预览,代码如下所示:

html 复制代码
<template>
  <div ref="container" style="width: 400px; height: 300px;"></div>
</template>

<script lang="ts">
// 导入three.js
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 导入gltf加载器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";

// 使用的是vue2.6.11版本
@Component
export default class bookUpload extends Vue {
  mounted() {
    this.initScene();
  }

  initScene() {
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机
    const camera = new THREE.PerspectiveCamera(75, 400 / 300, 0.1, 1000);
    // 创建渲染器
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(400, 300);
    // 获取渲染元素
    const container = this.$refs.container as HTMLElement;
    container.appendChild(renderer.domElement);

    // 添加光源
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    scene.add(ambientLight);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); // 方向光颜色和强度
    directionalLight.position.set(1, 1, 1); // 光源位置
    scene.add(directionalLight);

    // 创建控制器
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true; // 允许阻尼效果,使动画更平滑
    controls.dampingFactor = 0.05; // 阻尼系数
    controls.rotateSpeed = 0.1; // 旋转速度

    // 加载3D模型
    const loader = new GLTFLoader();
    loader.load("/Box.glb", (gltf) => {
      console.log("gltf.scene", gltf.scene);
      scene.add(gltf.scene);
    });

    // 设置相机在 z 轴上的位置
    camera.position.z = 5;

    const animate = () => {
      requestAnimationFrame(animate);
      controls.update(); // 更新控制器状态
      renderer.render(scene, camera);
    };

    animate();
  }
}
</script>

预览效果如下图所示:

3. 3D 图形预览(three.js)

js 复制代码
// 初始化
this.$nextTick(() => {
  this.list.forEach((item) => {
    this.initScene(item);
  });
});

// 渲染3D
initScene(item) {
  // 1. 创建场景
  const scene = new THREE.Scene();
  // 设置背景色
  scene.background = new THREE.Color(0xffffff);
  // 设置背景图片(CubeTexture立方纹理 创建一个由6张图片所组成的纹理对象 左右上下前后)
  // 设置背景图片(没生效,估计地址配置的不对 /public/img)
  // scene.background = new THREE.CubeTextureLoader()
  //     .setPath("/img/")
  //     .load(["1.png", "2.png", "3.png", "4.png", "5.png", "6.png"]);
  // 添加雾(配置的7,视角远一点 可以看到效果)
  const fog = new THREE.Fog(0xcccccc, 0, 7);
  scene.fog = fog;

  // 2. 创建相机
  // PerspectiveCamera透视相机,模拟人眼看到的景象,是3D场景中使用最普遍的投影模式
  const camera = new THREE.PerspectiveCamera(75, 300 / 300, 0.1, 1000);
  camera.position.z = 3; // 设置相机在 z 轴上的位置
  camera.position.y = 1;

  // (1)创建立方体
  const box = new THREE.BoxGeometry();
  // 创建材质(MeshBasicMaterial基础网格材质 不受光照影响)
  const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

  // 创建网格
  const cube = new THREE.Mesh(box, material);
  cube.position.set(1, 1, 0);
  scene.add(cube);

  // 3. 创建渲染器
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(300, 300); // 设置大小
  renderer.setClearColor(0xffffff, 0); // 设置背景颜色 默认黑色
  renderer.shadowMap.enabled = true; // 添加阴影的渲染

  // 获取渲染元素
  const container = document.getElementById(item.id) as HTMLElement;
  container.appendChild(renderer.domElement);

  // 添加网格地面
  const gridHelper = new THREE.GridHelper(10, 10);
  scene.add(gridHelper);

  // 添加坐标轴
  const axesHelper = new THREE.AxesHelper(5);
  scene.add(axesHelper);

  // 添加环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight);

  // 添加平行光(需要设置位置)
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); // 光颜色和强度
  directionalLight.position.set(1, 1, 1); // 光源位置
  scene.add(directionalLight);
  // 添加灯光辅助
  scene.add(new THREE.PointLightHelper(pointLight, 100));

  // 添加点光源(看投影效果)
  const pointLight = new THREE.PointLight(0xffffff, 1);
  pointLight.power = 500; // 设置亮度
  pointLight.castShadow = true;
  pointLight.position.set(2, 2, 2);
  scene.add(pointLight);

  // 4. 创建轨道控制器(调整相机位置,即视角位置)
  const controls = new OrbitControls(camera, renderer.domElement);
  // 监听控制器改变事件
  // controls.addEventListener("change", () => {
  //   console.log("change");
  // });
  controls.enableDamping = true; // 允许阻尼效果,使动画更平滑
  controls.dampingFactor = 0.05; // 阻尼系数
  controls.rotateSpeed = 0.1; // 旋转速度
  controls.autoRotate = true; // 自动旋转
  controls.autoRotateSpeed = 0.5; // 自动旋转速度

  // (2)加载3D模型
  // 创建GLTF实例
  const loader = new GLTFLoader();
  // 加载模型
  loader.load(
    item.nftFileUrl,
    (glb) => {
      console.log("glb.scene", glb.scene);
      // 遍历模型中的物体
      glb.scene.traverse((child) => {
        child.castShadow = true; // 设置物体投影
        child.receiveShadow = true; // 设置物体接收阴影
      })
      // 添加到场景
      scene.add(glb.scene);
    }
  );

  // 5. 动起来
  const animate = () => {
    requestAnimationFrame(animate);
    controls.update(); // 更新控制器状态
    cube.rotation.x += 0.01; // 让立方体旋转起来
    renderer.render(scene, camera); // 重新渲染
  };

  animate();
}

注意:通过 GLTFLoader 加载模型后,是一片黑色的,首先考虑灯光问题,需要添加灯光。AmbientLight 为环境光;DirectionalLight 为平行光;PointLight为点光源

  • 官方文档:Three.js
  • Blender是一款免费开源三维图形图像软件,提供从建模、动画、材质、渲染、到音频处理、视频剪辑等一系列动画短片制作解决方案。
相关推荐
mldong28 分钟前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排1 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60612 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角3 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!3 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰3 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi5 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen5 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马6 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒6 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端