3d模型展示-初探

发布于:2024-12-18 ⋅ 阅读:(92) ⋅ 点赞:(0)

由于工作原因,近一年没怎么写代码,有朋友问你做过3D模型展示吗,之前都是做以vue为框架做定制业务,这次抽时间试试3d模型展示。

软件功能

使用ThreeJS框架实现加载GLB模型,并添加动画效果,实现3d展示模型。使用GLTFLoader加载模型,并使用OrbitControls实现鼠标拖拽旋转,滚轮缩放,点击模型显示信息等功能。参考代码

软件架构

工程化

使用webpack做工程化,安装webpack webpack-cli webpack-dev-server html-webpack-plugin @babel/core @babel/preset-env babel-loader

编写webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/app.js', // 入口文件路径
  output: {
    filename: 'bundle.js', // 输出文件名
    path: path.resolve(__dirname, 'dist'), // 输出目录
    clean: true, // 自动清理输出目录
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.(glb|gltf)$/,
        type: 'asset/resource', // 确保可以加载GLB等资源文件
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html', // 模板文件路径
      filename: 'index.html', // 输出的 HTML 文件名
    }),
  ],
  resolve: {
    extensions: ['.js', '.json'], // 解析模块时尝试这些扩展名
    alias: {
      three: path.resolve(__dirname, 'node_modules/three'), // 如果需要,可以指定Three.js的位置
    },
  },
  devServer: {
    static: {
      directory: path.join(__dirname, 'assets'), // 静态文件夹
    },
    open: true, // 启动时打开浏览器
    hot: true, // 热更新
  },
  mode: 'development', // 开发模式
};

主程序代码

import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

// 创建场景、相机、渲染器等...
console.log("THREE version:", THREE.REVISION);

// 创建场景
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 设置场景背景色
scene.background = new THREE.Color(0xcccccc);

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

// 场景中增加四个点光源
const pointLight1 = new THREE.PointLight(0xffffff, 0.3, 100);
pointLight1.position.set(5, 5, 5);
scene.add(pointLight1);

const pointLight2 = new THREE.PointLight(0xffffff, 0.3, 100);
pointLight2.position.set(-5, -5, -5);
scene.add(pointLight2);

const pointLight3 = new THREE.PointLight(0xffffff, 0.3, 100);
pointLight3.position.set(-5, 5, 5);
scene.add(pointLight3);

const pointLight4 = new THREE.PointLight(0xffffff, 0.3, 100);
pointLight4.position.set(5, -5, -5);
scene.add(pointLight4);

// 场景中增加四个平行光
const light1 = new THREE.DirectionalLight(0x001dff, 1);
light1.position.set(5, 5, 5).normalize();
scene.add(light1);
const light2 = new THREE.DirectionalLight(0xffe8e8, 1);
light2.position.set(5, -5, 5).normalize();
scene.add(light2);
const light3 = new THREE.DirectionalLight(0xfff8ef, 1);
light3.position.set(-5, 5, 5).normalize();
scene.add(light3);
const light4 = new THREE.DirectionalLight(0xffffff, 1);
light4.position.set(5, 5, -5).normalize();
scene.add(light4);

// 添加坐标轴辅助器
// const axesHelper = new THREE.AxesHelper(2)
// scene.add(axesHelper)

let model; // 用于存储加载的模型
// 加载GLB模型
const loader = new GLTFLoader();
loader.load(
  "test2.glb", // 确保路径正确
  function (gltf) {
    model = gltf.scene; // 将加载的模型赋值给变量
    scene.add(gltf.scene);

    // 将模型的中心点设置为控制器中心点
    const box = new THREE.Box3().setFromObject(model);
    if (box !== null) {
        const center = new THREE.Vector3();
        box.getCenter(center);
        
        // 将 OrbitControls 的 target 设置为模型的中心
        controls.target.copy(center);
    }
    // 如果需要立即生效,可以调用 update 方法
    controls.update();
  },
  undefined,
  function (error) {
    console.error(error);
  }
);

// 创建 OrbitControls 实例,控制场景中的模型
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;

controls.autoRotate = true
controls.autoRotateSpeed = 3
controls.target = new THREE.Vector3(0, 0, 0)

// 调整相机位置以适应模型
camera.position.z = 2;

// let time = 0;
function animate() {
  requestAnimationFrame(animate);

  if (model) {
    // 更新时间变量
    // time += 0.01;
    // 让模型旋转
    // model.rotation.x += 0.01;
    // model.rotation.y += 0.01;
    // 让模型上下浮动
    // model.position.y = Math.sin(time) * 0.2;
  }

  renderer.render(scene, camera);
  controls.update()
}

animate();

// 监听窗口大小变化
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});