Threejs——十四、关于深度冲突、重叠、以及加载模型进度条效果实现(附完整代码)

深度冲突

两个模型重叠的模型,通过浏览器旋转预览,会发现模型旋转的时候会发生闪烁。
这种情况,主要是两个模型重合,电脑分不清谁在前谁在后,这种情况,可以理解为深度冲突Z-fighting

function addBox() {
  const geometry = new THREE.BoxGeometry(10, 10, 10);
  // 材质
  const material = new THREE.MeshPhysicalMaterial({
    color: 0x51efe4, //0x51efe4设置材质颜色
  });
  // 网络模型
  mesh = new THREE.Mesh(geometry, material);
  mesh.position.set(0, 10, 0);
  const mesh2 = mesh.clone();
  mesh2.geometry = mesh.geometry.clone();
  mesh2.material = mesh.material.clone();
  mesh2.position.x = 5;
  mesh2.material.color.set(0xffff00);
  scene.add(mesh);
  scene.add(mesh2);
}

效果:

两个几何体 Mesh 拉开距离

适当偏移,解决深度冲突,偏移尺寸相对模型尺寸比较小,视觉上两个几何体近似还是重合效果。

mesh2.position.z = 1;

Threejs——十四、关于深度冲突、重叠、以及加载模型进度条效果实现(附完整代码)_第1张图片

webgl 渲染器设置对数深度缓冲区

这种情况我这里遇到过一次,通过压缩模型后进行放大缩小会发现出现模型闪烁的 bug,所以这里可以用logarithmicDepthBuffer解决冲突问题。
注意:如果两模型面间隙过小,或者重合,,此渲染器对数深度缓冲区也是没有效果的

// WebGL渲染器设置
const renderer = new THREE.WebGLRenderer({
  // 设置对数深度缓冲区,优化深度冲突问题
  logarithmicDepthBuffer: true,
});

区别:

const geometry = new THREE.BoxGeometry(10, 10, 10);
// 材质
const material = new THREE.MeshPhysicalMaterial({
  color: 0x51efe4, //0x51efe4设置材质颜色
});
// 网络模型
mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 10, 0);
const mesh2 = mesh.clone();
mesh2.geometry = mesh.geometry.clone();
mesh2.material = mesh.material.clone();
mesh2.position.x = 5;
mesh2.material.color.set(0xffff00);
mesh2.position.z = 1;
mesh.position.y = 10.01;  // 加Y轴
scene.add(mesh);
scene.add(mesh2);

Threejs——十四、关于深度冲突、重叠、以及加载模型进度条效果实现(附完整代码)_第2张图片

不加logarithmicDepthBuffer
Threejs——十四、关于深度冲突、重叠、以及加载模型进度条效果实现(附完整代码)_第3张图片

模型加载进度条

这里拿GLTFLoader来测试

let loadedData = 0
loader.load(new URL(`../assets/model.glb`, import.meta.url).href,function (gltf) {
      scene.add(gltf.scene);
      render();
    },
    function (xhr) {
      // 后台打印查看模型文件加载进度
    //   console.log("加载完成的百分比" + (xhr.loaded / xhr.total) * 100 + "%");
      loadedData = Math.floor((xhr.loaded / xhr.total) * 100);
    //   console.log(Math.floor((xhr.loaded / xhr.total) * 100));
      if (Math.floor((xhr.loaded / xhr.total) * 100) == 100) {
        setTimeout(() => {
          data.statu = false;
        }, 1000);
      }
    },
    function (err) {
      console.error("加载发生错误");
    }
  );

这里可以进行判断,如果loadedData等于100,也就是模型加载完毕的时候,那么这段文字就隐藏起来
附完整代码:

/*
 * @Author: SouthernWind 
 * @Date: 2023-06-14 16:38:59 
 * @Last Modified by: SouthernWind 
 * @Last Modified time: 2023-06-20 14:39:07
 */

<template>
  <el-button class="yellow-btn" type="warning" plain @click="yellowBtn">黄色el-button>
  <el-button class="green-btn" type="success" plain @click="greenBtn">绿色el-button>
  <el-button class="save-btn" @click="saveFile">下载el-button>
  <div class="container" ref="container">div>
template>

<script setup>
import * as THREE from "three";
// 轨道
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { GUI } from "three/addons/libs/lil-gui.module.min.js";

import { ref, reactive, onMounted } from "vue";
// 三个必备的参数
let scene,
  camera,
  renderer,
  controls,
  mesh,
  material,
  group,
  texture,
  gui,
  textureCube;

onMounted(() => {
  // 外层需要获取到dom元素以及浏览器宽高,来对画布设置长宽
  // clientWidth等同于container.value.clientWidth
  let container = document.querySelector(".container");
  const { clientWidth, clientHeight } = container;
  console.log(clientHeight);
  // 首先需要获取场景,这里公共方法放在init函数中
  const init = () => {
    scene = new THREE.Scene();
    // 给相机设置一个背景
    scene.background = new THREE.Color(0xaaaaaa);
    // 透视投影相机PerspectiveCamera
    // 支持的参数:fov, aspect, near, far
    camera = new THREE.PerspectiveCamera(
      60,
      clientWidth / clientHeight,
      0.001,
      6000
    );
    // 相机坐标
    camera.position.set(30, 30, 30);

    // 相机观察目标
    camera.lookAt(scene.position);
    // 渲染器
    renderer = new THREE.WebGLRenderer({
      antialias: true,
      preserveDrawingBuffer: true,
      logarithmicDepthBuffer: true
    });
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    // 渲染多大的地方
    renderer.setClearAlpha(0.0);
    renderer.setSize(clientWidth, clientHeight);
    /* renderer.outputEncoding = THREE.sRGBEncoding; */
    // const axesHelper = new THREE.AxesHelper(150);
    // scene.add(axesHelper);
    container.appendChild(renderer.domElement);
    addBox();
    console.log("查看当前屏幕设备像素比", window.devicePixelRatio);
  };
  init();
  function addBox() {
    /* gui = new GUI();
    const geometry = new THREE.TorusKnotGeometry(10, 3, 100, 16);
    const material = new THREE.MeshPhysicalMaterial({
      color: 0x30cff8,
      metalness: 0,
      roughness: 0,
      transmission: 0.5,
      ior: 1.5,
    });
    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
    gui.add(material, "transmission", 0, 1);
    gui.add(material, "ior", 1, 2.333); */

    const geometry = new THREE.BoxGeometry(10, 10, 10);
    // 材质
    const material = new THREE.MeshPhysicalMaterial({
      color: 0x51efe4, //0x51efe4设置材质颜色
    });
    // 网络模型
    mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(0, 10, 0);
    const mesh2 = mesh.clone();
    mesh2.geometry = mesh.geometry.clone();
    mesh2.material = mesh.material.clone();
    mesh2.position.x = 5;
    mesh2.material.color.set(0xffff00);
    mesh2.position.z = 1;
    mesh.position.y = 10.01;
    scene.add(mesh);
    scene.add(mesh2);
    // camera.position.set(292*5, 223*5, 185*5);
  }

  // 相机控件
  const control = () => {
    controls = new OrbitControls(camera, renderer.domElement);
    controls.addEventListener("change", function () {});
  };
  control();

  // 光源
  const linght = () => {
    const pointLight = new THREE.PointLight(0xffffff, 1.0);
    // pointLight.position.set(400, 0, 0);//点光源放在x轴上
    pointLight.position.set(100, 60, 50); //设置光源的位置
    // 光源和网格模型Mesh对应一样是三维场景的一部分,自然需要添加到三维场景中才能起作用。
    scene.add(pointLight); // 添加光源到场景中

    /*  const pointLight = new THREE.AmbientLight(0xffffff, 1.0);
    pointLight.position.set(150, 150, 150);
        scene.add(pointLight); */
    const pointLightHelper = new THREE.PointLightHelper(pointLight, 1);
    scene.add(pointLightHelper);
  };
  linght();
  const render = () => {
    renderer.render(scene, camera);
    requestAnimationFrame(render);
  };
  render();
  window.addEventListener("resize", () => {
    // 更新摄像头
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });
});
const yellowBtn = () => {
  console.log(mesh);
  mesh.material.color.set(0xe5a144);
};
const greenBtn = () => {
  console.log(mesh);
  mesh.material.color.set(0x69c242);
};
const saveFile = () => {
  const link = document.createElement("a");
  // 通过超链接herf属性,设置要保存到文件中的数据
  var canvas = renderer.domElement; //获取canvas对象
  link.href = canvas.toDataURL("image/png");
  link.download = "threejs.png"; //下载文件名
  link.click(); //js代码触发超链接元素a的鼠标点击事件,开始下载文件到本地

  // 通过超链接herf属性,设置要保存到文件中的数据
  // link.href = window.URL.createObjectURL(new Blob([JSON.stringify(scene),JSON.stringify(mesh)]));
  // link.download = '模型数据.txt';//下载文件名
  // link.download = 'threejs.png';
  // const canvas = renderer.domElement; //获取canvas对象
  // link.href = canvas.toDataURL("image/png");
  // link.click();//js代码触发超链接元素a的鼠标点击事件,开始下载文件到本地
};
script>

<style>
.container {
  width: 100%;
  height: 100vh;
  position: relative;
  z-index: 1;
  /* background: #ff5810; */
}
.yellow-btn {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 99;
}
.green-btn {
  position: absolute;
  top: 0;
  left: 50px;
  z-index: 99;
}
.save-btn {
  position: absolute;
  top: 0;
  left: 111px;
  z-index: 99;
}
style>


你可能感兴趣的:(Vue3,ThreeJS,javascript,前端,3d)