Threejs - 14. Sobre conflito profundo, sobreposição e implementação do efeito da barra de progresso do modelo de carregamento (código completo em anexo)

conflito profundo

Para dois modelos sobrepostos, se você visualizar o modelo girando-o no navegador, verá que o modelo piscará quando for girado.
Neste caso, a principal razão é que os dois modelos se sobrepõem e o computador não consegue dizer quem está na frente e quem está atrás, situação que pode ser entendida como um conflito profundo 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);
}

Efeito:
Adicione a descrição da imagem

Distância de malha entre duas entidades geométricas

O deslocamento apropriado pode resolver o conflito de profundidade. O tamanho do deslocamento é relativamente pequeno comparado ao tamanho do modelo. Visualmente, as duas geometrias ainda se aproximam do efeito de sobreposição.

mesh2.position.z = 1;

Adicione a descrição da imagem

renderizador webgl define buffer de profundidade logarítmica

Eu encontrei esta situação aqui uma vez: ao compactar o modelo e, em seguida, aumentar e diminuir o zoom, você encontrará um bug de oscilação do modelo, então você pode usar este método para logarithmicDepthBufferresolver o problema de conflito.
Nota: Se a lacuna entre as duas superfícies do modelo for muito pequena ou se sobrepuser, o buffer de profundidade logarítmica deste renderizador não terá efeito.

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

a diferença:

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

Adicione a descrição da imagem

Não adicionelogarithmicDepthBuffer
Adicione a descrição da imagem

Barra de progresso de carregamento do modelo

GLTFLoaderObtenha aqui para teste

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

Você pode fazer um julgamento aqui. Se loadedDatafor igual a 100, ou seja, quando o modelo for carregado, esse texto ficará oculto.
O código completo está em anexo:

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


Acho que você gosta

Origin blog.csdn.net/nanchen_J/article/details/131759611
Recomendado
Clasificación