fix: Plumb material prop to MeshTextureLayer so rasters can render unlit#613
Open
charlieforward9 wants to merge 1 commit into
Open
Conversation
…nlit
Raster imagery drawn through MeshTextureLayer is darkened by any scene
LightingEffect with ambient intensity < 1: the phong ambient term is
material.ambient * ambientIntensity * surfaceColor, so the ambient-only
default material is only lighting-neutral at intensity 1.0.
Expose the standard deck.gl `material` prop on RasterTileLayer and
RasterLayer, forwarded (only when set, preserving current defaults) down
to MeshTextureLayer. COGLayer inherits the prop via RasterTileLayer.
Because deck.gl v9 forwards a raw `material: false` to luma.gl where
falsy module props are coerced to {} (re-applying the default lit phong
material), MeshTextureLayer.draw() translates a disabled material into
phongMaterial {unlit: true}, which the shader already honors.
Closes developmentseed#612
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kylebarron
reviewed
Jul 6, 2026
Comment on lines
+178
to
+190
| // deck.gl documents `material: false` as the way to render a mesh unlit, | ||
| // but in deck.gl v9 the LightingEffect forwards the raw `false` to | ||
| // luma.gl's ShaderInputs, which coerces falsy module props to `{}` and so | ||
| // silently re-applies the *default* phong material (ambient 0.35, | ||
| // diffuse 0.6). Translate a disabled material into the phongMaterial | ||
| // module's `unlit` flag ourselves so raster values render verbatim (like | ||
| // `BitmapLayer`). This runs after the LightingEffect's module props are | ||
| // applied for the frame (`Layer._drawLayer` sets effect shaderModuleProps | ||
| // before calling `draw`), so it reliably wins. | ||
| if (!this.props.material) { | ||
| shaderProps.phongMaterial = { unlit: true }; | ||
| } | ||
|
|
Member
There was a problem hiding this comment.
this seems like an upstream bug? Do you expect third party layers to have to know all this?
Member
|
Unless you can explain in plain language, without AI, what the problem is, we need this change, how we can test it, and how we can avoid regressions in the future, I'm going to close this. Because I don't understand what it's doing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #612
Problem
Raster imagery drawn through
MeshTextureLayer(soRasterLayer,RasterTileLayer, andCOGLayer) is uniformly darkened whenever the deck.gl scene has aLightingEffectwith ambient intensity < 1 — a common setup when the same scene lights 3D extrusions. Rendered pixels come out at roughlyfileValue × ambientIntensity(we measured 40% and 60% in two production views), whileBitmapLayerimagery in the same scene shows true values.The default
material: { ambient: 1.0, diffuse: 0.0, ... }intends to neutralize lighting, but the phong ambient term ismaterial.ambient × ambientLight.color × ambientLight.intensity × surfaceColor— neutral only when the scene's ambient intensity is exactly 1.0. And there is no consumer-facing escape hatch:_subLayerPropscan't reach the mesh layer through the tile-layer indirection.Change
RasterTileLayer/RasterLayer: new optionalmaterial?: Materialprop (deck.gl's standard type;false= unlit), forwarded down the chain only when set (...(material !== undefined && { material })) so the current default behavior is untouched for existing consumers.COGLayerinherits the prop viaRasterTileLayerwith no deck.gl-geotiff changes.MeshTextureLayer.draw(): translates a falsymaterialintophongMaterial: { unlit: true }shader-module props.The translation is needed because deck.gl v9 regressed
material: false:LightingEffect.getShaderModuleProps()forwards the layer's rawmaterialprop as thephongMaterialmodule props, and luma.gl'sShaderInputs.setProps()coerces falsy module props to{}—— which re-applies the default lit phong material (
ambient 0.35, diffuse 0.6). The unlit escape hatch already exists in the shader (if (material.unlit) return surfaceColor;in@luma.gl/shadertools); it's just unreachable viamaterial: falsein v9.MeshTextureLayer.draw()already sets per-frame module props after the effect's props are applied (Layer._drawLayerorder), so the translation deterministically wins. This also fixesmaterial: falsefor anyone passing it directly toMeshTextureLayertoday.Result:
We considered a raster-specific boolean (e.g.
lighting: false) instead — happy to rename, butmaterialfollows theSimpleMeshLayerconvention and gives custom-material control for free.Testing
tests/raster-layer.test.ts: forwardsmaterial: false/ material object toMeshTextureLayer; key absent (notundefined) when unset, pinning the default-preserving conditional spread.tests/raster-tile-layer/material-forwarding.test.ts(new): same assertions acrossRasterTileLayer._renderSubLayers→RasterLayer.tests/mesh-layer.test.ts(new):material: false→setPropscalled withphongMaterial: {unlit: true}; default and custom materials leavephongMaterialuntouched.pnpm --filter @developmentseed/deck.gl-raster test(146 passed),pnpm lint,pnpm --filter @developmentseed/deck.gl-raster typecheckall green (thedocsworkspace typecheck failure pre-exists on main — missing generated typedoc sidebar).Verified end-to-end in our production app (AGROZOOM COG imagery over a scene lit at ambient 0.4/0.6):
material: falserenders identically to a patched unlit shader; omitting the prop reproduces today's behavior exactly.