3D人物建模与WebGL渲染实战

发布于:2025-06-25 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、建模

模型地址:https://models.readyplayer.me/685a49eb55c53bb7dad7a44a.glb
创建模型的工具: Ready Player Me - Create a Full-Body 3D Avatar From a Photo
我使用以上工具临时创建了一个3D人物,有想法的自行去尝试一下。
在这里插入图片描述

二、渲染模型

实现:渲染器(WebGLRenderer)和加载 GLTF 模型的方法

在这里插入图片描述

完整代码

<template>
  <div class="peopleModel" id="peopleModel"></div>
</template>

<script setup>
import { nextTick, onMounted } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";

let scene, camera, renderer, model, controls, amlight, light, pointLight;
let boxWidth, boxHeight;

function init() {
  // 获取容器宽高
  boxWidth = document.querySelector("#peopleModel").clientWidth;
  boxHeight = document.querySelector("#peopleModel").clientHeight;

  // 创建场景
  scene = new THREE.Scene();
  //   背景颜色
  scene.background = new THREE.Color(0xffffff);
  // 添加环境光、平行光和点光源
  amlight = new THREE.AmbientLight(0xffffff, 1); // 环境光
  scene.add(amlight); // 将环境光添加到场景中

  light = new THREE.DirectionalLight(0xffffff, 2); // 增强平行光的强度

  // 添加一个点光源
  pointLight = new THREE.PointLight(0xffffff, 2, 100); // 点光源:颜色强度,最大光照范围

  // 创建相机
  camera = new THREE.PerspectiveCamera(5, boxWidth / boxHeight, 0.1, 1000); //参数:视角,宽高比,近截面,远截面
  camera.position.set(0, 1, 5); // 适当设置相机位置

  // 创建渲染器
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(boxWidth, boxHeight);
  document.querySelector("#peopleModel").appendChild(renderer.domElement);

  // 加载 GLB 模型---员工模型
  const loader = new GLTFLoader();
  loader.load(
    new URL("../assets/json/user.glb", import.meta.url).href,
    (gltf) => {
      model = gltf.scene; // 获取模型
      scene.add(model); // 将模型添加到场景中

      model.position.set(0, -1.5, 0); // 调整模型位置
      // 遍历模型的所有网格,设置材质
      model.traverse((child) => {
        if (child.isMesh) {
          child.material = new THREE.MeshPhysicalMaterial({
            color: child.material.color.getHex(), // 保持原有的颜色: 使用 getHex() 方法获取十六进制颜色值
            roughness: 0.67, // 设置材质的粗糙度
            roughnessMap: child.material.roughnessMap, // 使用原有的粗糙度贴图
            metalness: 0, // 设置材质的金属度
            map: child.material.map, // 如果有纹理贴图也需要传递
          });
        }
      });

      camera.lookAt(model.position); // 在模型加载后调整相机视角
      //   设置点光源的位置正对模型
      pointLight.position.set(
        model.position.x,
        model.position.y,
        model.position.z
      );
      scene.add(pointLight); // 将点光源添加到场景中
      light.position.set(model.position.x, model.position.y + 3, -model.position.z + 4); // 调整平行光的位置
      scene.add(light);
    },
    undefined,
    (error) => {
      console.error("Error loading GLTF model:", error);
    }
  );

  // 创建辅助坐标系
  const axesHelper = new THREE.AxesHelper(150);
    // scene.add(axesHelper);

  // 初始化OrbitControls
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
}

function animate() {
  requestAnimationFrame(animate);
  if (model) {
    // model.rotation.y += 0.01; // 增加一些旋转效果
  }
  controls.update(); // 更新控制器
  renderer.render(scene, camera);
}

onMounted(() => {
  nextTick(() => {
    init();
    animate();
  });
});

// 响应式窗口变化
window.onresize = function () {
  boxWidth = document.querySelector("#peopleModel").clientWidth;
  boxHeight = document.querySelector("#peopleModel").clientHeight;
  renderer.setSize(boxWidth, boxHeight);
  camera.aspect = boxWidth / boxHeight;
  camera.updateProjectionMatrix();
};
</script>
<style scoped>
.peopleModel {
  width: 100%;
  height: 100vh;
}
</style>

网站公告

今日签到

点亮在社区的每一天
去签到