Threejs–Fourteen, about depth conflict, overlap, and the realization of the effect of loading model progress bar (with complete code)

Deep conflict

Two overlapping models, through browser rotation preview, will find that the model will flicker when rotating.
In this case, 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);
  // material
  const material = new THREE. MeshPhysicalMaterial({<!-- -->
    color: 0x51efe4, //0x51efe4 sets the material color
  });
  // network model
  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 a picture description

The distance between the two geometric Mesh

Appropriate offset to solve the depth conflict, the offset size is relatively small compared to the model size, and the visual approximation of the two geometric bodies is still a coincidence effect.

mesh2.position.z = 1;

Please add a picture description

The webgl renderer sets the logarithmic depth buffer

I have encountered this kind of situation here once, and after zooming in and out after compressing the model, I will find a bug that the model flickers, so here you can use logarithmicDepthBuffer to solve the conflict problem.
Note: If the gap between the two model surfaces is too small, or coincident, the logarithmic depth buffer of this renderer has no effect

// WebGL renderer settings
const renderer = new THREE. WebGLRenderer({<!-- -->
  // Set the logarithmic depth buffer to optimize the depth conflict problem
  logarithmicDepthBuffer: true,
});

the difference:

const geometry = new THREE. BoxGeometry(10, 10, 10);
// material
const material = new THREE. MeshPhysicalMaterial({<!-- -->
  color: 0x51efe4, //0x51efe4 sets the material color
});
// network model
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; // add Y axis
scene. add(mesh);
scene. add(mesh2);

Please add a picture description

Do not add logarithmicDepthBuffer
Please add a picture description

Model loading progress bar

Here take GLTFLoader to test

let loadedData = 0
loader.load(new URL(`../assets/model.glb`, import.meta.url).href, function (gltf) {<!-- -->
      scene. add(gltf. scene);
      render();
    },
    function (xhr) {<!-- -->
      // Print in the background to view the loading progress of the model file
    // console.log("Percentage of loading completed" + (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("Loading error occurred");
    }
  );

You can judge here, if loadedData is equal to 100, that is, when the model is loaded, then this text will be hidden
Attach the complete code:

/*
 * @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">yellow</el-button>
  <el-button class="green-btn" type="success" plain @click="greenBtn">green</el-button>
  <el-button class="save-btn" @click="saveFile">Download</el-button>
  <div class="container" ref="container"></div>
</template>

<script setup>
import * as THREE from "three";
// track
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";
// three required parameters
let scene,
  camera,
  renderer,
  controls,
  mesh,
  material,
  group,
  texture,
  gui,
  textureCube;

onMounted(() => {<!-- -->
  // The outer layer needs to get the dom element and the width and height of the browser to set the length and width of the canvas
  // clientWidth is equivalent to container.value.clientWidth
  let container = document. querySelector(". container");
  const {<!-- --> clientWidth, clientHeight } = container;
  console.log(clientHeight);
  // First you need to get the scene, here the public method is placed in the init function
  const init = () => {<!-- -->
    scene = new THREE. Scene();
    // set a background for the camera
    scene.background = new THREE.Color(0xaaaaaa);
    // perspective projection camera PerspectiveCamera
    // Supported parameters: fov, aspect, near, far
    camera = new THREE. PerspectiveCamera(
      60,
      clientWidth / clientHeight,
      0.001,
      6000
    );
    // camera coordinates
    camera.position.set(30, 30, 30);

    // The camera observes the target
    camera. lookAt(scene. position);
    // Renderer
    renderer = new THREE. WebGLRenderer({<!-- -->
      antialias: true,
      preserveDrawingBuffer: true,
      logarithmicDepthBuffer: true
    });
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    // how big to render
    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("View the current screen device pixel ratio", 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);
    // material
    const material = new THREE. MeshPhysicalMaterial({<!-- -->
      color: 0x51efe4, //0x51efe4 sets the material color
    });
    // network model
    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);
  }

  // camera controls
  const control = () => {<!-- -->
    controls = new OrbitControls(camera, renderer.domElement);
    controls.addEventListener("change", function () {<!-- -->});
  };
  control();

  // light source
  const linght = () => {<!-- -->
    const pointLight = new THREE. PointLight(0xffffff, 1.0);
    // pointLight.position.set(400, 0, 0);//The point light source is placed on the x-axis
    pointLight.position.set(100, 60, 50); //Set the position of the light source
    // The light source and the mesh model Mesh are part of the 3D scene, and naturally need to be added to the 3D scene to work.
    scene.add(pointLight); // add light to the scene

    /* 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", () => {<!-- -->
    // update camera
    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");
  // Through the hyperlink herf attribute, set the data to be saved to the file
  var canvas = renderer.domElement; //Get the canvas object
  link.href = canvas.toDataURL("image/png");
  link.download = "threejs.png"; //Download file name
  link.click(); //js code triggers the mouse click event of hyperlink element a, and starts to download the file to the local

  // Through the hyperlink herf attribute, set the data to be saved to the file
  // link.href = window.URL.createObjectURL(new Blob([JSON.stringify(scene),JSON.stringify(mesh)]));
  // link.download = 'model data.txt';//download file name
  // link.download = 'threejs.png';
  // const canvas = renderer.domElement; //Get the canvas object
  // link.href = canvas.toDataURL("image/png");
  // link.click();//js code triggers the mouse click event of hyperlink element a, and starts to download the file to the local
};
</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>