网站建设应该应聘什么岗位北京网站建设制作开发
初八开工后,笔者又停了下来,今天总算又抽出来了一丢丢的时间继续。今天打算给大家聊聊困扰很多3D开发者的z-fighting叠面闪烁问题。
该问题从严格意义上说,是属于业务问题,因为现实中是不会有完全重叠的两个平面物体存在(总得有厚度差吧,哪怕很小)。所以笔者的想法跟很多博主一样,应该在业务上尽可能避免出现叠面场景的出现,不然问题永远解决不完。
笔者先来跟大家探讨前端开发用得特别频繁,网上文章也最多见的polygonOffset方法。不得不说,这个方法能快速解决大家的燃眉之急。但如果你的项目是规模较大的,需要长时间维护的那种类型,就会发现,这样的方法适应的场景很有限,并且用多了之后多个polygonOffset之间会相互打架。
废话少说,下面上demo。
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>three_cameraNear</title><style>body {margin: 0;overflow: hidden;}</style><script src="three/build/three.js"></script><script src="three/examples/js/controls/OrbitControls.js"></script><script src="three/examples/js/libs/dat.gui.min.js"></script>
</head><body><script>var scene = new THREE.Scene();var geometry = new THREE.PlaneGeometry(100, 100);var srcColor = 0xFF6600;var material = new THREE.MeshBasicMaterial({color: srcColor});var mesh = new THREE.Mesh(geometry, material);material.polygonOffset = true;material.polygonOffsetFactor = 0;material.polygonOffsetUnits = 0;scene.add(mesh);var geometry2 = new THREE.PlaneGeometry(50, 50);var srcColor2 = 0xFFFFFF;var material2 = new THREE.MeshBasicMaterial({color: srcColor2});var mesh2 = new THREE.Mesh(geometry2, material2);scene.add(mesh2);var width = window.innerWidth; var height = window.innerHeight; var camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 20000);camera.position.set(0, 0, 150); var renderer = new THREE.WebGLRenderer();renderer.setSize(width, height);renderer.setClearColor(0x000000, 1); document.body.appendChild(renderer.domElement); var gui = new dat.GUI(),folderCamera = gui.addFolder("相机"),propsCamera = {get '裁剪'() {return camera.near;},set '裁剪'( v ) {camera.near = v;camera.updateProjectionMatrix();},}; folderCamera.add( propsCamera, '裁剪', 0.01, 0.1 ); folderCamera.open();var folderPolygonOffset = gui.addFolder("polygonOffset");var propsPolygonOffset = {get 'polygonOffsetFactor'() {return material.polygonOffsetFactor;},set 'polygonOffsetFactor'( v ) {material.polygonOffsetFactor = v;},get 'polygonOffsetUnits'() {return material.polygonOffsetUnits;},set 'polygonOffsetUnits'( v ) {material.polygonOffsetUnits = v;},}folderPolygonOffset.add(propsPolygonOffset, 'polygonOffsetFactor', 0, 5);folderPolygonOffset.add(propsPolygonOffset, 'polygonOffsetUnits', 0, 5);folderPolygonOffset.open();function render() {renderer.render(scene, camera);requestAnimationFrame(render);}render();var controls = new THREE.OrbitControls(camera,renderer.domElement);controls.addEventListener('change', render);var raycaster = new THREE.Raycaster(); </script>
</body>
</html>
这段代码创建了两个大小不一样,但是位置上是重叠的两个平面,运行起来的效果如下:
可以看到,在旋转相机的时候,两个面的深度会不停交替,来回闪烁,这就是经典的z-fighting叠面问题。
然后网上给的解决方案是给其中一个面设置上polygonOffset,并且那个被抄到烂大家的文章,给polygonOffset对应的两个参数:polygonOffsetFactor和polygonOffsetUnits都设置为1,那这里我们也这样试试。
调整到1之后,叠面基本消失,场景拉远之后,我们发现还是有些角度产生了叠面。然后我们再把两个参数都调整到2,发现这下好了很多。
然而事实并没有我们想象中那么简单,注意到笔者还加了个裁剪的滑动条。
我们项目最初用的camera.near值是0.001,而不是我们现在给的0.1。我们很意外地发现,这个值对叠面的效果竟然也有影响,并且还不小。
这样下来,影响叠面的因素又多了一个。所以在笔者同事遇到这些问题时,他们都会尽可能地把polygonOffset的两个参数往大里调,从而规避这个问题。
但很不幸,我们项目玩得很花,好些功能会把三四个面叠在一起,这时候,不管参数值调大调小,我们都很容易顾此失彼,无法正确处理多个面之间的冲突。
笔者有段时间费了很大力气去查找跟polygonOffset相关的资料,但天下文章一大抄,找回来的都是webgl官方提供的那条公式m*polygonOffsetFactor+r*polygonOffsetUnits,并且两个不可控的变量m和r也描述得不清楚。
讲得相对深入一点的,是这篇:
深度冲突--threejs(webgl)_polygonoffsetfactor-CSDN博客
以下是公式中几个变量的讲解。
m: 表示最大深度斜率(Maximum Depth Slope)的值,是一个根据当前渲染的多边形相对于视线的角度自动计算出来的值。它基本上表示该多边形表面有多倾斜;如果表面与视线平行,则m值小,如果表面近乎垂直于视线,则m值大。
factor: 这是一个你可以控制的变量,对应于Three.js中的material.polygonOffsetFactor。这个数值会乘以上述的m值,也就是说,它表示深度偏移量将随着多边形的视觉倾斜程度而增加。
r: 这是指解析度,表示深度缓冲区每个单位的更改所能表示的最小深度差异。不同的系统和深度缓冲区的配置可能具有不同的解析度。
units: 同样是一个你可以控制的数值,对应于Three.js中的material.polygonOffsetUnits。这个数值会乘以r,提供了一个恒定的深度偏移,这个偏移与多边形的倾斜无关。
————————————————版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_45705239/article/details/138075785
不得不说,这里的说明让笔者对polygonOffset的理解深刻了一些。尽管在找到这篇文章之前,笔者就已经知道camera的near也是一个因素,但所幸的是,笔者完全可以通过先固定camera.near来以上文为方向单独研究这两个变量了。
下一篇,笔者会跟大家一起探讨这个坑爹玩意儿的工作原理,敬请期待!