Threejs - 14. About deep conflict, overlap, and implementation of loading model progress bar effect (complete code attached)

deep conflict

For two overlapping models, if you preview the model by rotating it through the browser, you will find that the model will flicker when it is rotated.
In this case, the main reason is that the two models overlap and the computer cannot tell who is in front and who is behind. This situation can be understood as a deep conflict 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);
}

Effect:
Please add image description

Mesh distance between two geometric entities

Appropriate offset can solve the depth conflict. The offset size is relatively small compared to the model size. Visually, the two geometries still approximate the overlapping effect.

mesh2.position.z = 1;

Please add image description

webgl renderer sets logarithmic depth buffer

I have encountered this situation here once. By compressing the model and then zooming in and out, you will find a bug of model flickering, so you can use this method to logarithmicDepthBuffersolve the conflict problem.
Note: If the gap between the two model surfaces is too small or overlaps, this renderer's logarithmic depth buffer will have no effect.

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

the difference:

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);

Please add image description

do not addlogarithmicDepthBuffer
Please add image description

Model loading progress bar

GLTFLoaderGet it here for testing

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("加载发生错误");
    }
  );

You can make a judgment here. If it loadedDatais equal to 100, that is, when the model is loaded, then this text will be hidden.
The complete code is attached:

/*
 * @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>


Guess you like

Origin blog.csdn.net/nanchen_J/article/details/131759611