Skip to content

Commit

Permalink
Add hillshading support to the DeckGL map (#294)
Browse files Browse the repository at this point in the history
* Initial 2d hillshading iteration.

* Use separate shader for colormap, like the hillshading

* Clear depth in minimap

* Add value decoder params

* Add missing newline

* Add hillshading in the python example

* Merge valueDecoder object with defaultProps
  • Loading branch information
alexandruandrei91 authored Feb 18, 2021
1 parent cadadf6 commit 66cee7f
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 41 deletions.
11 changes: 10 additions & 1 deletion examples/example_deckgl_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ def array2d_to_png(Z):

min_value = np.nanmin(map_data)
max_value = np.nanmax(map_data)
value_range = max_value - min_value

# Shift the values to start from 0 and scale them to cover
# the whole RGB range for increased precision.
# The client will need to reverse this operation.
scale_factor = (256*256*256 - 1) / (max_value - min_value)
scale_factor = (256*256*256 - 1) / value_range
map_data = (map_data - min_value) * scale_factor

map_data = array2d_to_png(map_data)
Expand All @@ -88,6 +89,14 @@ def array2d_to_png(Z):
"bounds": [-50, 50, 50, -50],
"image": map_data,
"colormap": colormap
},
{
"@@type": "Hillshading2DLayer",
"id": "hillshading-layer",
"bounds": [-50, 50, 50, -50],
"opacity": 1.0,
"valueRange": value_range,
"image": map_data
}
],
"views": [
Expand Down
11 changes: 10 additions & 1 deletion src/demo/example-data/deckgl-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@
"bounds": [-50, 50, 50, -50],
"image": "https://i.imgur.com/Dx8eseE.png",
"colormap": "https://cdn.jsdelivr.net/gh/kylebarron/deck.gl-raster/assets/colormaps/plasma.png"
},
{
"@@type": "Hillshading2DLayer",
"id": "hillshading-layer",
"bounds": [-50, 50, 50, -50],
"valueRange": 731.0,
"opacity": 1.0,
"image": "https://i.imgur.com/Dx8eseE.png"
}
],
"views": [
Expand All @@ -75,7 +83,8 @@
"width": "20%",
"height": "25%",
"clear": {
"color": [0.9, 0.9, 0.9, 1]
"color": [0.9, 0.9, 0.9, 1],
"depth": true
},
"viewState": {
"id": "main",
Expand Down
25 changes: 25 additions & 0 deletions src/lib/components/DeckGLMap/layers/colormap/colormap.fs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#define SHADER_NAME colormap-shader

#ifdef GL_ES
precision highp float;
#endif

varying vec2 vTexCoord;

uniform sampler2D bitmapTexture;
uniform sampler2D colormap;

uniform float opacity;

void main(void) {
vec4 bitmapColor = texture2D(bitmapTexture, vTexCoord);

float val = decode_rgb2float(bitmapColor.rgb);
vec4 color = texture2D(colormap, vec2(val, 0.5));

gl_FragColor = vec4(color.rgb, color.a * bitmapColor.a * opacity);

geometry.uv = vTexCoord;
DECKGL_FILTER_COLOR(gl_FragColor, geometry);

}
43 changes: 26 additions & 17 deletions src/lib/components/DeckGLMap/layers/colormap/colormapLayer.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// DeckGL typescript declarations are not great, so for now it's just js.

import { BitmapLayer } from "@deck.gl/layers";
import { picking, project32, gouraudLighting } from "@deck.gl/core";

import { Texture2D } from "@luma.gl/core";
import GL from "@luma.gl/constants";
import { Texture2D } from "@luma.gl/core";

import { decoder, colormap } from "../../webgl";
import { decoder } from "../shader_modules";
import fsColormap from "./colormap.fs.glsl";

const DEFAULT_TEXTURE_PARAMETERS = {
[GL.TEXTURE_MIN_FILTER]: GL.LINEAR_MIPMAP_LINEAR,
Expand All @@ -17,15 +17,31 @@ const DEFAULT_TEXTURE_PARAMETERS = {

const defaultProps = {
colormap: { type: "object", value: null, async: true },
valueDecoder: {
type: "object",
value: {
rgbScaler: [1, 1, 1],
// Scale [0, 256*256*256-1] to [0, 1]
floatScaler: 1.0 / (256.0 * 256.0 * 256.0 - 1.0),
offset: 0,
},
},
};

export default class ColormapLayer extends BitmapLayer {
draw({ uniforms }) {
const { gl } = this.context;
draw({ moduleParameters, uniforms, context }) {
const mergedDecoder = {
...defaultProps.valueDecoder.value,
...moduleParameters.valueDecoder,
};
super.setModuleParameters({
...moduleParameters,
valueDecoder: mergedDecoder,
});
super.draw({
uniforms: {
...uniforms,
u_colormap: new Texture2D(gl, {
colormap: new Texture2D(context.gl, {
data: this.props.colormap,
parameters: DEFAULT_TEXTURE_PARAMETERS,
}),
Expand All @@ -34,17 +50,10 @@ export default class ColormapLayer extends BitmapLayer {
}

getShaders() {
return {
...super.getShaders(),
inject: {
"fs:#decl": `uniform sampler2D u_colormap;`,
"fs:DECKGL_FILTER_COLOR": `
float val = decoder_rgb2float(color.rgb, vec3(1.0, 1.0, 1.0), 0.0, 1.0 / (256.0*256.0*256.0 - 1.0));
color = vec4(lin_colormap(u_colormap, val).rgb, color.a);
`,
},
modules: [picking, project32, gouraudLighting, decoder, colormap],
};
let parentShaders = super.getShaders();
parentShaders.fs = fsColormap;
parentShaders.modules.push(decoder);
return parentShaders;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#define SHADER_NAME hillshading2d-shader

#ifdef GL_ES
precision highp float;
#endif

varying vec2 vTexCoord;

uniform sampler2D bitmapTexture;
uniform vec2 bitmapResolution;

uniform float valueRange;

uniform vec3 lightDirection;
uniform float ambientLightIntensity;
uniform float diffuseLightIntensity;
uniform float opacity;

vec3 normal(float val) {
vec2 dr = 1.0 / bitmapResolution;
float p0 = valueRange * val;
float px = valueRange * decode_rgb2float(texture2D(bitmapTexture, vTexCoord + vec2(1.0, 0.0) / bitmapResolution).rgb);
float py = valueRange * decode_rgb2float(texture2D(bitmapTexture, vTexCoord + vec2(0.0, 1.0) / bitmapResolution).rgb);
vec3 dx = vec3(1.0, 0.0, px - p0);
vec3 dy = vec3(0.0, 1.0, py - p0);

return normalize(cross(dx, dy));
}

float shadow(vec3 normal) {
float diffuse = diffuseLightIntensity * dot(normal, normalize(lightDirection));
return clamp(ambientLightIntensity + diffuse, 0.0, 1.0);
}

void main(void) {
vec4 bitmapColor = texture2D(bitmapTexture, vTexCoord);

float val = decode_rgb2float(bitmapColor.rgb);
float shadow = shadow(normal(val));

gl_FragColor = vec4(vec3(0.0), (1.0-shadow) * bitmapColor.a * opacity);

geometry.uv = vTexCoord;
DECKGL_FILTER_COLOR(gl_FragColor, geometry);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// DeckGL typescript declarations are not great, so for now it's just js.

import { BitmapLayer } from "@deck.gl/layers";

import { decoder } from "../shader_modules";
import fsHillshading from "./hillshading2d.fs.glsl";

const defaultProps = {
valueRange: { type: "number" },
lightDirection: { type: "array", value: [1, 1, 1] },
ambientLightIntensity: { type: "number", value: 0.5 },
diffuseLightIntensity: { type: "number", value: 0.5 },
opacity: { type: "number", min: 0, max: 1, value: 1 },
valueDecoder: {
type: "object",
value: {
rgbScaler: [1, 1, 1],
// Scale [0, 256*256*256-1] to [0, 1]
floatScaler: 1.0 / (256.0 * 256.0 * 256.0 - 1.0),
offset: 0,
},
},
};

export default class Hillshading2DLayer extends BitmapLayer {
draw({ moduleParameters, uniforms }) {
if (this.state.bitmapTexture) {
// The prop objects are not merged with the defaultProps by default.
// See https://github.com/facebook/react/issues/2568
const mergedDecoder = {
...defaultProps.valueDecoder.value,
...moduleParameters.valueDecoder,
};
super.setModuleParameters({
...moduleParameters,
valueDecoder: mergedDecoder,
});
super.draw({
uniforms: {
...uniforms,
bitmapResolution: [
this.state.bitmapTexture.width,
this.state.bitmapTexture.height,
],
valueRange: this.props.valueRange,
lightDirection: this.props.lightDirection,
ambientLightIntensity: this.props.ambientLightIntensity,
diffuseLightIntensity: this.props.diffuseLightIntensity,
opacity: this.props.opacity,
},
});
}
}

getShaders() {
let parentShaders = super.getShaders();
parentShaders.fs = fsHillshading;
parentShaders.modules.push(decoder);
return parentShaders;
}
}

Hillshading2DLayer.layerName = "Hillshading2DLayer";
Hillshading2DLayer.defaultProps = defaultProps;
1 change: 1 addition & 0 deletions src/lib/components/DeckGLMap/layers/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as ColormapLayer } from "./colormap/colormapLayer";
export { default as Hillshading2DLayer } from "./hillshading2d/hillshading2dLayer";
17 changes: 17 additions & 0 deletions src/lib/components/DeckGLMap/layers/shader_modules/decoder.fs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
struct Decoder
{
vec3 rgbScaler;
float floatScaler;
float offset;
};

uniform Decoder decoder;

float decode_rgb2float(vec3 rgb, Decoder dec) {
rgb *= dec.rgbScaler * vec3(16711680.0, 65280.0, 255.0); //255*256*256, 255*256, 255
return (rgb.r + rgb.g + rgb.b + dec.offset) * dec.floatScaler;
}

float decode_rgb2float(vec3 rgb) {
return decode_rgb2float(rgb, decoder);
}
30 changes: 30 additions & 0 deletions src/lib/components/DeckGLMap/layers/shader_modules/decoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import fs from "./decoder.fs.glsl";

const DEFAULT_DECODER = {
rgbScaler: [1, 1, 1],
floatScaler: 1,
offset: 0,
};

function getUniforms(opts) {
if (opts && opts.valueDecoder) {
const {
rgbScaler = DEFAULT_DECODER.rgbScaler,
floatScaler = DEFAULT_DECODER.floatScaler,
offset = DEFAULT_DECODER.offset,
} = opts.valueDecoder;
return {
"decoder.rgbScaler": rgbScaler,
"decoder.floatScaler": floatScaler,
"decoder.offset": offset,
};
}

return {};
}

export default {
name: "decoder",
fs,
getUniforms,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as decoder } from "./decoder";
2 changes: 0 additions & 2 deletions src/lib/components/DeckGLMap/webgl/index.js

This file was deleted.

4 changes: 0 additions & 4 deletions src/lib/components/DeckGLMap/webgl/modules/colormap.fs.glsl

This file was deleted.

6 changes: 0 additions & 6 deletions src/lib/components/DeckGLMap/webgl/modules/colormap.js

This file was deleted.

4 changes: 0 additions & 4 deletions src/lib/components/DeckGLMap/webgl/modules/decoder.fs.glsl

This file was deleted.

6 changes: 0 additions & 6 deletions src/lib/components/DeckGLMap/webgl/modules/decoder.js

This file was deleted.

0 comments on commit 66cee7f

Please sign in to comment.