three.js篇之模型加载

文章主要是加载了一个模型,并对其进行了一些美化操作

主要加载了2个模型,一个是头发,一个是脸,因为模型是电脑下载下来的,内部没有其他节点,所以对于更改模型颜色不生效

 

 

<template>
  <div class="root">
    <div id="box"></div>
  </div>
</template>

<script>
// 方式 1: 导入整个 three.js核心库
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import {
  DirectionalLight,
  HemisphereLight,
  PlaneGeometry,
  MeshPhongMaterial,
  Mesh,
  Vector2,
  Vector3,
  Raycaster,
  Color
} from "three";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
export default {
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      box: null,
      gltf: null,
      composer: null
    };
  },
  async mounted() {
    this.box = document.getElementById("box");
    this.init();
    this.animate();
  },
  methods: {
    // 初始化
    init() {
      this.getScene();
      this.getCamera();
      this.getRender();
      this.getModel();
      this.addLight();
      this.addShadow();
      this.controlsCamera();
      document.body.addEventListener("click", this.changeSkinColor, false);
    },
    //   4.Animate -渲染场景
    animate() {
      requestAnimationFrame(this.animate);
      this.renderer.render(this.scene, this.camera);
      if (this.composer) {
        this.composer.render();
      }
    },
    // 创建场景
    getScene() {
      // 1.Scene-创建场景
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(0xb3cefb);
      this.scene.fog = new THREE.Fog(this.scene.background, 1, 100); //雾化效果
    },
    // 照相机
    getCamera() {
      //2. Camera   第一个参数是视野角度  第二个参数是长宽比 接下来的两个参数是近截面(near)和远截面(far)
      this.camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        1000
      );
      this.camera.position.set(0, 0, 15);
    },
    // 渲染器
    getRender() {
      // 3.renderer - 渲染器
      this.renderer = new THREE.WebGLRenderer({
        alpha: true,
        antialias: true
      });
      this.renderer.setPixelRatio(window.devicePixelRatio);
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      // 首先渲染器开启阴影
      this.renderer.shadowMap.enabled = true;
      this.renderer.outputEncoding = THREE.sRGBEncoding;
      this.box.appendChild(this.renderer.domElement);
    },
    // 加载模型
    getModel() {
      const loader = new GLTFLoader();
      loader.load(
        // resource URL
        "../../../static/tails.glb",
        // called when the resource is loaded
        gltf => {
          this.gltf = gltf;
          // 模型太小,会导致页面看不见模型,缩放模型可显示
          gltf.scene.scale.set(5, 5, 5);
          // 模型Mesh开启阴影
          gltf.scene.traverse(obj => {
            if (obj.isMesh) {
              obj.castShadow = true;
              obj.receiveShadow = true;
            }
          });
          this.scene.add(gltf.scene);
        },
        // called while loading is progressing
        function(xhr) {
          // console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
        },
        // called when loading has errors
        function(error) {
          console.log("An error happened", error);
        }
      );
      loader.load(
        // resource URL
        "../../../static/HeartEyesFace.glb",
        // called when the resource is loaded
        gltf => {
          this.gltf = gltf;
          // 模型太小,会导致页面看不见模型,缩放模型可显示
          gltf.scene.scale.set(150, 150, 150);
          gltf.scene.position.set(0.1,0.9,0);
          // 模型Mesh开启阴影
          gltf.scene.traverse(obj => {
            if (obj.isMesh) {
              obj.castShadow = true;
              obj.receiveShadow = true;
            }
          });
          this.scene.add(gltf.scene);
        },
        // called while loading is progressing
        function(xhr) {
          // console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
        },
        // called when loading has errors
        function(error) {
          console.log("An error happened", error);
        }
      );
    },
    // 添加灯光
    addLight() {
      // 平行光是沿着特定方向发射的光。.光颜色    光照的强度。缺省值为1
      const directionalLight = new DirectionalLight(0xffffff, 1);
      directionalLight.position.set(-4, 5, 20);
      this.scene.add(directionalLight);
      // 光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。
      let hemisphereLight = new HemisphereLight(0xffffff, 0xffffff, 0.4);
      hemisphereLight.position.set(0, 5, 0);

      // 光源开启阴影
      directionalLight.castShadow = true;
      directionalLight.shadow.mapSize = new Vector2(1024, 1024);
      // 模型身上很多条纹状黑线,因为渲染阴影中产生了伪影
      directionalLight.shadow.bias = -0.001; // value 自行调节

      this.scene.add(directionalLight);
      this.scene.add(hemisphereLight);
    },
    // 添加阴影 阴影显示需要光源和投射地(阴影显示的地方),有了光源差投射地,所以创建一个地板,让阴影投射至地板上
    addShadow() {
      // 生成一个平面几何
      let floorGeometry = new PlaneGeometry(5000, 5000, 1);
      // 给平面添加材质
      let floorMaterial = new MeshPhongMaterial({
        color: 0x77f28f,
        shininess: 0
        // wireframe: true
      });
      let floor = new Mesh(floorGeometry, floorMaterial);
      floor.rotation.x = -0.5 * Math.PI;
      floor.position.y = -2.1;
      // 地板接受阴影开启
      floor.receiveShadow = true;
      this.scene.add(floor);
      // 添加影子  对光源、渲染器、模型、地板进行设置
    },
    // 换肤功能 想要实现各个部件换肤功能,我们需要选中部件,修改选中部件材质来达到我们换肤的功能。
    changeSkinColor(ev) {
      // Raycaster 光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。
      // 1.选中不见,在场景中加入射线检测就可以了
      let raycaster = new Raycaster(); //鼠标移入过了什么物体
      let pointer = new Vector2();
      // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
      pointer.x = (ev.clientX / window.innerWidth) * 2 - 1;
      pointer.y = -(ev.clientY / window.innerHeight) * 2 + 1;
      // 通过摄像机和鼠标位置更新射线
      raycaster.setFromCamera(pointer, this.camera);

      // 计算物体和射线的焦点 gltf.scene.children只需要获取模型的位置,如果scene则是获取全部相交点,模型+阴影
      let intersects = raycaster.intersectObjects(
        this.gltf.scene.children,
        true
      );

      let selectedObjects = null;
      // 红 绿 蓝 骚粉
      let colocs = [0xffa500, 0x008000, 0x87ceeb, 0xff1493];
      console.log("intersects: ", intersects);
      if (intersects.length > 0) {
        selectedObjects = intersects[0].object;
        selectedObjects.material.color.set(0x87ceeb);
      }
      // 2.设置颜色或者纹理 修改材质颜色
      // let newMaterial = selectedObjects.material.clone();
      // newMaterial.needsUpdate = true;
      // newMaterial.color = new Color("#FFC0CB"); //重新修改颜色
      // selectedObjects.material = newMaterial;

      // 3.添加选中效果 给选中的加线&高亮
      this.composer = new EffectComposer(this.renderer);
      let renderPass = new RenderPass(this.scene, this.camera);
      this.composer.addPass(renderPass);
      let outlinePass = new OutlinePass(
        new Vector2(window.innerWidth, window.innerHeight),
        this.scene,
        this.camera
      );
      outlinePass.renderToScreen = true;
      outlinePass.edgeStrength = 5; //粗
      outlinePass.edgeGlow = 2; //发光
      outlinePass.visibleEdgeColor.set("#130AF2"); // 设置显示的颜色

      this.composer.addPass(outlinePass);
    },
    // 旋转控制
    controlsCamera() {
      let controls = new OrbitControls(this.camera, this.renderer.domElement);
      controls.enablePan = false;
      controls.maxPolarAngle = Math.PI / 2;
      controls.minPolarAngle = Math.PI / 3;
      controls.enableZoom = false;

      controls.update();
    }
  }
};
</script>

<style lang="less" scoped>
.root {
  background: white;
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}
</style>

最终效果图

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值