conflicto profundo
Para dos modelos superpuestos, si obtiene una vista previa del modelo girándolo a través del navegador, encontrará que el modelo parpadeará cuando se gire.
En este caso, la razón principal es que los dos modelos se superponen y la computadora no puede distinguir quién está delante y quién detrás, situación que puede entenderse como un conflicto 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);
}
Efecto:
Distancia de malla entre dos entidades geométricas
Un desplazamiento apropiado puede resolver el conflicto de profundidad. El tamaño del desplazamiento es relativamente pequeño en comparación con el tamaño del modelo. Visualmente, las dos geometrías aún se aproximan al efecto de superposición.
mesh2.position.z = 1;
El renderizador webgl establece un búfer de profundidad logarítmica
Me he encontrado con esta situación aquí una vez. Al comprimir el modelo y luego acercarlo y alejarlo, encontrará un error de parpadeo del modelo, por lo que puede usar este método para logarithmicDepthBuffer
resolver el problema del conflicto.
Nota: Si el espacio entre las dos superficies del modelo es demasiado pequeño o se superpone, el búfer de profundidad logarítmica de este renderizador no tendrá ningún efecto.
// WebGL渲染器设置
const renderer = new THREE.WebGLRenderer({
// 设置对数深度缓冲区,优化深度冲突问题
logarithmicDepthBuffer: true,
});
la diferencia:
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);
no añadalogarithmicDepthBuffer
Barra de progreso de carga del modelo
GLTFLoader
Consíguelo aquí para probarlo
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("加载发生错误");
}
);
Puedes hacer un juicio aquí. Si es loadedData
igual a 100, es decir, cuando se carga el modelo, entonces este texto se ocultará.
Se adjunta el código completo:
/*
* @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>