three.js+WebGL踩坑经验合集(8.1):用于解决z-fighting叠面问题的polygonOffset远没我们想象中那么简单

初八开工后,笔者又停了下来,今天总算又抽出来了一丢丢的时间继续。今天打算给大家聊聊困扰很多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来以上文为方向单独研究这两个变量了。

下一篇,笔者会跟大家一起探讨这个坑爹玩意儿的工作原理,敬请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970830.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2025年-G4-Lc78--121. 买卖股票的最佳时机--(java版)

1.题目描述 2.思路 思路1: 做两轮排序&#xff0c;第一轮排序找到最小的那个数&#xff0c;然后再判断最小的那个数之后还有其他数吗&#xff0c;如果有在进行排序&#xff0c;选出最大的那个数&#xff0c;然后值相减。 问题要点&#xff1a; &#xff08;1&#xff09;你需要…

AI 编程工具—Cursor 进阶篇 数据分析

AI 编程工具—Cursor 进阶篇 数据分析 上一节课我们使用Cursor 生成了北京房产的销售数据,这一节我们使用Cursor对这些数据进行分析,也是我们尝试使用Cursor 去帮我们做数据分析,从而进一步发挥Cursor的能力,来帮助我们完成更多的事情 案例一 房产销售数据分析 @北京202…

【Python】错误异常

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Python 文章目录 1. 错误和异常的概念1.1 错误1.2 异常 2. 常见的内置异常类型2.1 ZeroDivisionError2.2 IndexError2.3 KeyError2.4 TypeError 3. 异常处理机制3.1 try-except 语句3.2 try-except-else 语句3.3 try-except-fin…

ICASSP2023 | IE-FGSM | 通过增强欧拉方法提高对抗样本的可迁移性

Boosting Transferability of Adversarial Example via an Enhanced Euler’s Method 摘要-Abstract引言-Introduction相关工作-Related Work方法-Methodology实验-Experiments结论-Conclusion 论文链接 本文 “Boosting Transferability of Adversarial Example via an Enhan…

力扣 470. 用 Rand7() 实现 Rand10() 拒绝采样 等概率随机数生成

Problem: 470. 用 Rand7() 实现 Rand10() 文章目录 &#x1f37b; k 进制诸位生成 拒绝采样&#x1f37a; 朴素版&#x1f37a; 优化版 &#x1f37b; 等概率生成任何数大法 &#x1f37b; k 进制诸位生成 拒绝采样 &#x1f469;‍&#x1f3eb; 参考题解 ⏰ 时间复杂度&a…

Jvascript网页设计案例:通过js实现一款密码强度检测,适用于等保测评整改

本文目录 前言功能预览样式特点总结&#xff1a;1. 整体视觉风格2. 密码输入框设计3. 强度指示条4. 结果文本与原因说明 功能特点总结&#xff1a;1. 密码强度检测2. 实时反馈机制3. 详细原因说明4. 视觉提示5. 交互体验优化 密码强度检测逻辑总Html代码Javascript代码 前言 能…

无人机航迹规划: 梦境优化算法(Dream Optimization Algorithm,DOA)求解无人机路径规划MATLAB

一、梦境优化算法 梦境优化算法&#xff08;Dream Optimization Algorithm&#xff0c;DOA&#xff09;是一种新型的元启发式算法&#xff0c;其灵感来源于人类的梦境行为。该算法结合了基础记忆策略、遗忘和补充策略以及梦境共享策略&#xff0c;通过模拟人类梦境中的部分记忆…

【c++】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗?

【c】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗&#xff1f; 1.线程终止会导致进程终止吗&#xff1f; 在操作系统中&#xff0c;线程是进程的基本执行单元&#xff0c;一个进程可以包含一个或多个线程。 当一个子线程终止时&#xff0c;进程并不会因此自动终…

【动手学运动规划】5.5 基于PiecewiseJerk的路径优化方法

知我者&#xff0c;谓我心忧. 不知我者&#xff0c;谓我何求。— 佚名 黍离 &#x1f3f0;代码及环境配置&#xff1a;请参考 环境配置和代码运行! PiecewiseJerkOptimizer是Apollo中planning模块生成Path/Speed曲线的优化方法. 基于Frenet坐标系, 生成平滑, 安全的目标曲线. …

图论入门算法:拓扑排序(C++)

上文中我们了解了图的遍历(DFS/BFS), 本节我们来学习拓扑排序. 在图论中, 拓扑排序(Topological Sorting)是对一个有向无环图(Directed Acyclic Graph, DAG)的所有顶点进行排序的一种算法, 使得如果存在一条从顶点 u 到顶点 v 的有向边 (u, v) , 那么在排序后的序列中, u 一定…

英国学术论文规范,学术来源的基本知识

学术来源&#xff08;scholarly source&#xff09;&#xff0c;指的是在某一特定的学术研究领域由专家所写&#xff0c;给同行或者对此专业领域有兴趣的人所阅读&#xff0c;提供相关分析素材的研究成果。在国外留学中&#xff0c;虽然平时学校要求完成的作业多为reports&…

Java运维实战:问题定位-CPU突增排查

java程序最常见的故障场景就是CPU徒增的情况了&#xff0c;本片文章为你讲解java程序CPU突增的情况怎么进行排查 1、获取CPU消耗高的线程ID top -Hp 进程ID 然后输入大写P&#xff08;shiftp&#xff09;&#xff0c;就会将这个进程下的线程按照CPU消耗进行排序展示。 举例 然…

使用 Ansys MotorCAD 进行轴向磁通电机设计

新的 MotorCAD 机器拓扑&#xff1a;轴向磁通电机 轴向磁通量可用拓扑 Ansys MotorCAD支持3种不同的轴向磁通拓扑&#xff0c;包括&#xff08;双转子 - 单定子&#xff09;、&#xff08;单转子 - 单定子&#xff09;和&#xff08;单转子 - 双定子&#xff09; 双转子 - 单…

【深度学习】深度学习和强化学习算法——深度 Q 网络DQN

深度 Q 网络&#xff08;Deep Q-Network, DQN&#xff09; 详解 什么是DQNDQN 的背景DQN 训练流程 2 DQN 的核心思想2.1 经验回放&#xff08;Experience Replay&#xff09;2.2 目标网络&#xff08;Target Network&#xff09;2.3 ε-贪心策略&#xff08;ε-Greedy Policy&a…

学习数据结构(10)栈和队列下+二叉树(堆)上

1.关于栈和队列的算法题 &#xff08;1&#xff09;用队列实现栈 解法一&#xff1a;&#xff08;参考代码&#xff09; 题目要求实现六个函数&#xff0c;分别是栈初始化&#xff0c;入栈&#xff0c;移除并返回栈顶元素&#xff0c;返回栈顶元素&#xff0c;判空&#xff0…

芯片引脚描述或电路原理图中的Ipd、Ipu是什么意思?

问&#xff1a;物理层芯片KSZ8081RNB的Data Sheet对某些引脚类型的说明如下&#xff1a; 请说明其中Ipd、Ipu的意思是什么&#xff1f; 答&#xff1a; I&#xff1a;表示该引脚是一个 输入引脚&#xff0c;即该引脚用于接收信号。O&#xff1a;表示该引脚是一个 输出引脚&a…

[操作系统] 基础IO:系统文件I/O

在 Linux 操作系统中&#xff0c;文件 I/O&#xff08;输入/输出&#xff09;是程序与文件系统交互的基础。理解文件 I/O 的工作原理对于编写高效、可靠的程序至关重要。本文将深入探讨系统文件 I/O 的机制。 一种传递标志位的方法 在 Linux 中&#xff0c;文件的打开操作通常…

Mybatis-扩展功能

逻辑删除乐观锁 MyBatisPlus从入门到精通-3&#xff08;含mp代码生成器&#xff09; Db静态工具类 Spring依赖循环问题 代码生成器 MybatisPlus代码生成器 枚举处理器 我们这里用int来存储状态 需要注解&#xff0c;很不灵活 希望用枚举类来代替这个Integer 这样的话我…

ECharts 实战指南:组件封装+地图轮廓高亮 + 自定义 Tooltip+轮播+锥形柱子

大家好&#xff0c;我是一诺。今天我们将深入探讨 ECharts&#xff0c;这个功能强大的数据可视化库。 无论你是已经在使用 ECharts&#xff0c;还是正计划用它来创建一些炫酷的图表&#xff0c;这篇文章都会对你有所帮助。 我们将从渲染模式开始&#xff0c;逐步深入到如何封…

【MyBatis】_使用XML实现MyBatis

目录 1. 配置yml配置文件 1.2 配置数据库 1.3 配置xml的路径 2. xml文件中实现数据库的增删查改操作 2.1 各文件内容 2.2 编写细节 MyBatis作为一个持久层框架&#xff0c;用于进行数据库操作。 MyBatis的实现方式有两种&#xff1a;&#xff08;1&#xff09;注解&…