developmentseed / developmentseed/deck.gl-raster

Raster imagery darkened by scene LightingEffect; no consumer control over mesh material/lighting

Open
#612 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
228
Forks
29
Avg merge
12h 27m
Merged PRs (30d)
4

Description

## Problem

Image

Raster imagery rendered through `RasterLayer`/`MeshTextureLayer` (and therefore `COGLayer`) is uniformly darkened whenever the deck.gl scene has a `LightingEffect` with ambient intensity < 1 — a common setup when the same scene lights 3D extrusions. Rendered pixels come out at roughly `fileValue × ambientIntensity` (we measured 40% and 60% in two views), while `BitmapLayer`-based imagery in the same scene shows true values. Downloading the GeoTIFF shows correct pixels; only the on-screen render is dark.

## Root cause

The vendored mesh fragment shader (`packages/deck.gl-raster/src/mesh-layer/mesh-layer-fragment.glsl.ts`) runs the sampled color through phong lighting:

```glsl
vec3 lightColor = lighting_getLightColor(color.rgb, cameraPosition, position_commonspace.xyz, normal);
fragColor = vec4(lightColor, color.a * layer.opacity);
```

`MeshTextureLayer`'s default `material: { ambient: 1.0, diffuse: 0.0, ... }` intends to neutralize lighting, but the phong ambient term is `material.ambient × ambientLight.color × ambientLight.intensity × surfaceColor` — it's only neutral when the scene's ambient intensity is exactly 1.0.

There is also no consumer-facing escape hatch: the mesh layer sits behind `COGLayer → TileLayer → RasterLayer → MeshTextureLayer`, the `TileLayer` is constructed bare, and per-tile sublayer ids are dynamic, so `_subLayerProps` can't reach it with a `material` override.

## Related deck.gl v9 regression (affects the fix design)

Even where `material` *can* be passed (directly to `MeshTextureLayer`), deck.gl's documented `material: false` ("disable lighting") is silently broken in v9:

- `LightingEffect.getShaderModuleProps()` forwards the layer's raw `material` prop as the `phongMaterial` module props (`@deck.gl/core` `effects/lighting/lighting-effect.ts`).
- luma.gl's `ShaderInputs.setProps()` coerces falsy module props to `{}`:
```js
const moduleProps = props[moduleName] || {};
```
so `false` → `{}` → `getUniforms({})` → the **default lit** phong material (`ambient 0.35, diffuse 0.6`) — arguably darker still.

The unlit escape hatch exists in the shader (`if (material.unlit) return surfaceColor;` in `@luma.gl/shadertools` phong module); it's just unreachable via `material: false` in v9.

## Proposal

Keep the current default (no visual change for existing consumers), and expose deck.gl's standard `material` prop on `RasterTileLayer` and `RasterLayer`, forwarded conditionally down to `MeshTextureLayer` (following the existing `debugOpacity` pattern; forwarded only when set so the current default is preserved). `COGLayer` extends `RasterTileLayer`, so it inherits the prop with zero deck.gl-geotiff changes.

To make `material: false` actually mean "unlit" despite the v9 regression above, `MeshTextureLayer.draw()` (which already sets per-frame shader module props after the effect's props are applied) translates a falsy material into `phongMaterial: { unlit: true }`.

Result: `new COGLayer({ ..., material: false })` renders file values verbatim — parity with `BitmapLayer`.

We considered a raster-specific boolean (e.g. `lighting: false`) instead; `material` follows the `SimpleMeshLayer` convention and gives custom-material control for free, but happy to rename if you prefer a raster-specific term.

**PR incoming from us implementing the above.**

## Workaround (0.7.x)

pnpm patch on `dist/mesh-layer/mesh-layer-fragment.glsl.js` replacing the lit `fragColor` with `vec4(color.rgb, color.a * layer.opacity)`.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with packages/deck.gl-raster/src/mesh-layer/mesh-layer-fragment.glsl.ts and MeshTextureLayer.draw(), then trace material and debugOpacity forwarding through RasterLayer, RasterTileLayer, COGLayer, and TileLayer. Review @deck.gl/core effects/lighting/lighting-effect.ts and the luma.gl phong module behavior. Done means existing defaults remain unchanged and material: false produces raster pixels matching the source values under a LightingEffect.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
data-visualization, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.