透明物体renderOrder:深度缓冲区depthWrite、depthTest

子级继承父级renderOrder:

大概意思就是 如果父级renderOrder不是默认值 会先考虑父级的renderOrder,之后在父级对应的renderOrder下,再依据renderOrder进行渲染

 

在 Three.js 中,当一个 mesh 的材质属性设置为 depthWrite: falsedepthTest: true 时,其渲染顺序不仅仅由自身的 renderOrder 决定,还可能受到父级对象的 renderOrder 和渲染顺序逻辑的影响。这是因为 Three.js 的渲染流程会综合考虑场景层次结构、物体排序以及透明物体的渲染规则。

1. 继承性

Three.js 渲染的流程遵循场景图的层次结构(Scene Graph)。子对象的渲染行为可能受到父对象的一些设置影响,特别是以下情况:

  • 父级 renderOrder 的优先级高于子级: 如果父级的 renderOrder 被设置为一个非默认值,Three.js 会优先根据父级的 renderOrder 确定渲染顺序,然后再按照子级的 renderOrder 排序。

  • 父级影响整个子树: 父级的 renderOrder 会成为子对象排序的一个参考基准,从而影响子对象的实际渲染顺序。

2. 透明物体的特殊排序规则

透明物体的渲染逻辑与不透明物体不同:

  • 不透明物体的渲染顺序是基于深度缓冲区的,无需特别的 renderOrder 控制。

  • 透明物体由于需要混合颜色,需要按照距离摄像机的远近排序(默认行为),除非 renderOrder 被显式设置。

在层次场景中,透明物体的渲染顺序会参考父级的 renderOrder,因为透明物体通常需要遵循场景的整体渲染逻辑。

3. 渲染逻辑中的场景树遍历

Three.js 的渲染器会按照以下顺序处理场景树:

  1. 遍历整个场景树,收集所有需要渲染的物体。

  2. 将物体按照 renderOrder 和深度信息(depthTest)排序。

  3. 执行绘制。

在这种遍历和排序过程中:

  • 父对象的 renderOrder 被优先采纳,作为子对象渲染的“参考框架”。

  • 如果父级的 renderOrder 不为默认值 0,子级即使有自己的 renderOrder,也可能无法完全脱离父级的影响。

4. 解决方法

方法 1:分离父子关系

方法 2:显式控制子对象的 renderOrder(待考量)

方法 3:通过 onBeforeRender 动态调整渲染顺序

如果复杂场景中无法分离,可以使用 onBeforeRender 在渲染时动态调整物体的属性:

childMesh.onBeforeRender = function () {
  this.renderOrder = 5; // 临时调整
};

 

 

depthTestdepthWrite 是控制 WebGL 深度缓冲区的两个关键属性,它们直接影响 3D 场景中物体的渲染顺序和遮挡关系。

 

1. depthTest 的作用

depthTest 决定了一个片段在绘制时,是否需要与深度缓冲区的值进行比较。

  • 默认值:true
    启用深度测试,片段会根据当前深度缓冲区的值决定是否需要渲染。

  • 关闭:false
    禁用深度测试,片段会直接渲染到屏幕,无视深度缓冲区的值。

常见用途

  • 启用 (depthTest: true):适用于大多数非透明物体,确保近处的物体能够正确遮挡远处的物体。

  • 禁用 (depthTest: false):适用于始终需要显示的物体(例如 HUD、光效等),无论深度缓冲区如何都直接渲染。

示例

const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
material.depthTest = false; // 禁用深度测试

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
  • 启用 depthTest:当前片段仅在通过深度测试时渲染(即片段深度值小于等于深度缓冲区的值)。

  • 禁用 depthTest:当前片段直接渲染,无视深度缓冲。

 

2. depthWrite 的作用

depthWrite 决定了一个片段在绘制时,是否将其深度值写入深度缓冲区。

  • 默认值:true
    启用深度写入,片段的深度值会存储到深度缓冲区中,用于后续渲染的深度测试。

  • 关闭:false
    禁用深度写入,片段的深度值不会存储到深度缓冲区中,不会影响后续的深度测试。

常见用途

  • 启用 (depthWrite: true):适用于大多数非透明物体,使它们参与深度缓冲区的写入和后续深度测试。

  • 禁用 (depthWrite: false):适用于透明物体或特殊效果,避免它们覆盖深度缓冲区,允许后续物体覆盖。

示例

const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.5 });
material.depthWrite = false; // 禁用深度写入

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
  • 启用 depthWrite:片段深度会记录在缓冲区中,影响后续物体的渲染。

  • 禁用 depthWrite:片段深度不会记录,但片段仍可被渲染。

 

3. depthTestdepthWrite 的关系

两者独立工作,但常配合使用以实现复杂的渲染效果:

depthTest depthWrite 效果说明
true true 默认设置,物体会进行深度测试并写入深度缓冲区,确保遮挡正确。
true false 物体参与深度测试但不更新深度缓冲区,适合透明物体。
false true 物体无视深度缓冲区直接渲染,但更新深度缓冲区,效果不常见。
false false 物体无视深度缓冲区直接渲染,且不影响深度缓冲区,适合 HUD 或特殊效果。

4. 示例应用场景

非透明物体

  • 典型设置:depthTest: true, depthWrite: true

  • 确保正确的遮挡关系,常用于普通物体。

透明物体

  • 推荐设置:depthTest: true, depthWrite: false

  • 透明物体通常需要参与深度测试(避免穿模),但不写入深度缓冲区(避免影响后续物体)。

始终显示的物体

  • 推荐设置:depthTest: false, depthWrite: false

  • HUD、光效等始终显示的物体。

复杂效果

  • 例如描边效果,可以禁用深度测试并启用深度写入:

const outlineMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
outlineMaterial.depthTest = false; // 不进行深度测试
outlineMaterial.depthWrite = true; // 写入深度缓冲区

5. 总结

  • depthTest 控制是否参与深度测试,决定片段是否被渲染。

  • depthWrite 控制是否写入深度缓冲区,影响后续物体的深度测试。

  • 通常,非透明物体需要 depthTest: truedepthWrite: true

  • 透明物体则需要 depthTest: truedepthWrite: false

  • 通过灵活调整两者,可以实现各种遮挡与显示效果。

posted @ 2025-05-07 10:12  SimoonJia  阅读(63)  评论(0)    收藏  举报