fix: 树在 Cesium 远看发黑 — 补 emissive 并导出切线
黑色色块修掉后仍存在:近看正常,远看整棵树是暗色块。逐项排除: - 贴图颜色全链路无偏移,源 4k / 降采样 2k / GLB 内 PNG 的 opaque 均值 都是 sRGB [0.409, 0.406, 0.362],不是 gamma 问题。 - 模拟 GPU mip 链,可见像素亮度 mip0→mip6 只从 0.127 变到 0.124, 覆盖率稳定 0.42,不是 mipmap 变暗。 - 法线贴图抠图区域是干净的平面法线 [0.494, 0.512, 0.988],无黑像素。 真实原因是缺 emissive 补偿。预览页 skyBox / skyAtmosphere / sun 全部关闭 且未配置环境贴图,Cesium 只剩很弱的默认球谐环境光,太阳直射不到的面接近 全黑——这正是 EXPORT_EMISSION_OVERRIDES 存在的原因(建筑 0.18,程序化树冠 0.015~0.02)。树冠绝大部分是背光叶片卡片,远看塌成一团暗色,近看能看到 向阳面所以还行。apple 材质不在那张表里。 - 抠图植被把 diffuse 接回 Emission Color,FOLIAGE_EMISSION = 0.22。 用带贴图的自发光而非平坦颜色:常量会把树干染成叶子绿,而这样每个像素 下限是自身反照率的一个比例。不增加字节,emissiveTexture 指向 base color 已在用的同一张图。 - 打开 export_tangents:apple 有法线贴图但图元无 TANGENT,缺失时切线由 渲染器推导,在双面薄片叶子卡上不可靠。49/102 图元带上切线,顺带修正 建筑法线贴图,GLB +0.83MB。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,12 @@ from osmassets.materials import link_alpha_clip # noqa: E402
|
|||||||
# mesh's shared slots can recognise its own output and leave it alone.
|
# mesh's shared slots can recognise its own output and leave it alone.
|
||||||
EXPORT_PREFIX = "Cesium "
|
EXPORT_PREFIX = "Cesium "
|
||||||
|
|
||||||
|
# Fraction of its own albedo a cut-out foliage material emits, to keep the
|
||||||
|
# shadowed side of a crown off Cesium's near-black ambient floor. Kept well
|
||||||
|
# under the 0.18 the buildings use: a tree still has to read as lit from one
|
||||||
|
# side, it just must not go to black.
|
||||||
|
FOLIAGE_EMISSION = 0.22
|
||||||
|
|
||||||
EXPORT_TINTS = {
|
EXPORT_TINTS = {
|
||||||
"Grass": ((0.12, 0.48, 0.08), 0.72),
|
"Grass": ((0.12, 0.48, 0.08), 0.72),
|
||||||
"Tree Crown Dark": ((0.06, 0.22, 0.05), 0.18),
|
"Tree Crown Dark": ((0.06, 0.22, 0.05), 0.18),
|
||||||
@@ -362,6 +368,25 @@ def make_export_material(material):
|
|||||||
# SpeedTree atlas are black, so Cesium draws black slabs.
|
# SpeedTree atlas are black, so Cesium draws black slabs.
|
||||||
link_alpha_clip(result, diffuse_node.outputs["Alpha"], bsdf,
|
link_alpha_clip(result, diffuse_node.outputs["Alpha"], bsdf,
|
||||||
cutoff=material.alpha_threshold)
|
cutoff=material.alpha_threshold)
|
||||||
|
# Lift the crown out of Cesium's ambient. The preview configures no
|
||||||
|
# environment map, so anything the sun does not hit directly falls to a
|
||||||
|
# weak default spherical-harmonic term — which is why every other
|
||||||
|
# material here carries an EXPORT_EMISSION_OVERRIDES entry. A crown is
|
||||||
|
# mostly self-shadowed leaf cards facing away from the sun, so at
|
||||||
|
# distance it collapses into one dark mass while a sunlit close-up
|
||||||
|
# still reads fine.
|
||||||
|
#
|
||||||
|
# Feed the diffuse back in as the emissive texture rather than using a
|
||||||
|
# flat colour: a constant would wash the bark with leaf green, whereas
|
||||||
|
# this floors every texel at a fraction of its own albedo. It costs no
|
||||||
|
# extra bytes — the exporter points emissiveTexture at the image the
|
||||||
|
# base colour already uses.
|
||||||
|
if "Emission Color" in bsdf.inputs:
|
||||||
|
links.new(diffuse_node.outputs["Color"], bsdf.inputs["Emission Color"])
|
||||||
|
elif "Emission" in bsdf.inputs:
|
||||||
|
links.new(diffuse_node.outputs["Color"], bsdf.inputs["Emission"])
|
||||||
|
if "Emission Strength" in bsdf.inputs:
|
||||||
|
bsdf.inputs["Emission Strength"].default_value = FOLIAGE_EMISSION
|
||||||
elif "Alpha" in bsdf.inputs:
|
elif "Alpha" in bsdf.inputs:
|
||||||
bsdf.inputs["Alpha"].default_value = 1.0
|
bsdf.inputs["Alpha"].default_value = 1.0
|
||||||
return result
|
return result
|
||||||
@@ -452,6 +477,11 @@ def export(args):
|
|||||||
export_normals=True,
|
export_normals=True,
|
||||||
export_materials="EXPORT",
|
export_materials="EXPORT",
|
||||||
export_image_format="AUTO",
|
export_image_format="AUTO",
|
||||||
|
# The foliage materials carry a normal map, and glTF leaves tangent
|
||||||
|
# derivation to the renderer when TANGENT is absent. On thin
|
||||||
|
# double-sided leaf cards that derivation is unreliable, so ship real
|
||||||
|
# tangents — it costs four floats a vertex on meshes this small.
|
||||||
|
export_tangents=True,
|
||||||
export_extras=True,
|
export_extras=True,
|
||||||
export_cameras=False,
|
export_cameras=False,
|
||||||
export_lights=False,
|
export_lights=False,
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-07-31(二)远看整棵树发黑
|
||||||
|
|
||||||
|
黑色色块修掉后,Cesium 里近看正常、远看整棵树是暗色块。逐项排查:
|
||||||
|
|
||||||
|
- 贴图颜色全链路无偏移:源 4k / 降采样 2k / GLB 里导出的 PNG,opaque 均值都是 sRGB `[0.409, 0.406, 0.362]`,不是 gamma 问题
|
||||||
|
- 模拟 GPU mip 链(逐级 box 降采样,按 0.5 cutoff 取可见像素):可见像素亮度 mip0→mip6 只从 0.127 变到 0.124,覆盖率稳定在 0.42,不是 mipmap 变暗
|
||||||
|
- 法线贴图抠图区域是干净的平面法线 `[0.494, 0.512, 0.988]`,无黑像素,mip 后趋于更平,不是法线污染
|
||||||
|
|
||||||
|
真实原因是**缺少 emissive 补偿**。预览页没有配置任何环境贴图(`skyBox` / `skyAtmosphere` / `sun` 全部关闭),Cesium 只剩一个很弱的默认球谐环境光,所以太阳直射不到的面接近全黑——这正是 `EXPORT_EMISSION_OVERRIDES` 存在的原因,建筑 0.18、程序化树冠 0.015~0.02。树冠绝大部分是背光的叶片卡片,远看整体塌成一团暗色,而近看能看到向阳面所以还行。apple 材质不在那张表里,一点补偿都没有。
|
||||||
|
|
||||||
|
- 抠图植被改为把 diffuse 接回 Emission Color,强度 `FOLIAGE_EMISSION = 0.22`。用带贴图的自发光而不是平坦颜色:常量会把树干也染成叶子绿,而这样每个像素的下限是它自身反照率的一个比例。不增加字节,导出器让 `emissiveTexture` 指向 base color 已经在用的那张图
|
||||||
|
- glTF 导出打开 `export_tangents`:apple 材质有法线贴图但图元没有 TANGENT,缺失时由渲染器自行推导切线,而在双面薄片叶子卡上这个推导不可靠。全场景 49/102 个图元带上切线,顺带修正建筑法线贴图,GLB +0.83MB
|
||||||
|
|
||||||
|
如果远处仍偏暗,调 `export_cesium.py` 的 `FOLIAGE_EMISSION` 一个常量即可。
|
||||||
|
|
||||||
## 2026-07-31
|
## 2026-07-31
|
||||||
|
|
||||||
- 树渲染改用两个第三方模型,`tree_style` 新增 `apple` / `fattree`:
|
- 树渲染改用两个第三方模型,`tree_style` 新增 `apple` / `fattree`:
|
||||||
|
|||||||
Reference in New Issue
Block a user