两个模型重叠的模型,通过浏览器旋转预览,会发现模型旋转的时候会发生闪烁。
这种情况,主要是两个模型重合,电脑分不清谁在前谁在后,这种情况,可以理解为深度冲突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);
}
效果:
适当偏移,解决深度冲突,偏移尺寸相对模型尺寸比较小,视觉上两个几何体近似还是重合效果。
mesh2.position.z = 1;
这种情况我这里遇到过一次,通过压缩模型后进行放大缩小会发现出现模型闪烁的 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);
这里拿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>