经纬志
首页 / 实战手册 / three.js 渲染

半透明玻璃叠在一起,看不见背面

先看结论

给玻璃幕墙设了 opacity: 0.4,结果每一层玻璃都像实心板,后面的楼完全被挡住。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文
半透明玻璃叠在一起,看不见背面 的可运行示例截图

现象

单块玻璃看起来正常,两块前后叠放时,后一块完全不可见, 或者前后关系随相机角度跳变。透过玻璃看不到内部的家具和结构。

原因

transparent: true 只影响混合,不改变深度写入。 three.js 的透明物体默认仍然 depthWrite: true, 先画的玻璃把深度写进了缓冲,后画的玻璃在深度测试中被剔除。

同时,透明物体按对象中心排序,不按面排序。 一个由很多面组成的玻璃盒,其各个面无法正确前后排序, 就会出现“某几面消失、某几面又叠出新颜色”的情况。

排查过程

  1. 把 depthWrite 设为 false,观察背面是否出现,以确认是深度写入问题。
  2. 把 transparent 暂时设为 false、opacity 设 1,确认几何与朝向正常。
  3. 用 material.side 试 THREE.DoubleSide,判断是否因背面剔除导致缺面。

解决方案

常规玻璃材质:关闭深度写入、双面渲染,并让透明层统一排在最后:

var glassMat = new THREE.MeshPhysicalMaterial({
  color: 0x9fc6e8,
  transparent: true,
  opacity: 0.35,
  roughness: 0.1,
  metalness: 0,
  depthWrite: false,        // 关键
  side: THREE.DoubleSide,
  transmission: 0.6
});
glassMat.renderOrder = 10;   // 数值大的后画

多层玻璃需要正确的层次时,把每一层拆成独立网格,按距离相机由远到近绘制。 简单可控的做法是逐层设置 renderOrder:

glassLayers.forEach(function (mesh, i) {
  mesh.material.depthWrite = false;
  mesh.renderOrder = 100 - i;   // 远景先画
});

如果材质只有“透明/不透明”两种状态,不需要渐变,用 alphaTest 走不透明管线,性能更好也不会排序出错:

var foliageMat = new THREE.MeshStandardMaterial({
  map: leafTexture,
  alphaTest: 0.5,       // 低于 0.5 的像素直接丢弃
  transparent: false,
  side: THREE.DoubleSide
});

可运行示例

复现器保留了本页的故障输入:给玻璃幕墙设了 opacity: 0.4 ,结果每一层玻璃都像实心板,后面的楼完全被挡住。点「修复后」可以看到同样的输入在正确配置下的结果。

问题复现器新窗口打开

修复后:常规玻璃材质:关闭深度写入、双面渲染,并让透明层统一排在最后:

验证

绕建筑旋转一周,透过玻璃应始终能看到内部的柱子,不会出现某角度突然变实心。 两块玻璃前后叠放时,叠合区颜色应比单层更深,符合叠加规律。 用 renderer.info.render.calls 确认没有因为拆层导致调用数失控。

性能提醒:透明物体越多,overdraw 越严重。 大片玻璃幕墙建议只在近景开启透明,远景改用半透明贴图烘焙进材质, 避免整个城市都在混合计算。

引用本文

经纬志(2026)。《半透明玻璃叠在一起,看不见背面》。https://www.jingweizhi.com/cookbook/three-material-transparent.html(访问日期 2026-11-03)。