fix(heatmap): 解决颜色插值问题,优化渲染性能

This commit is contained in:
mipha.ly 2019-02-28 11:55:04 +08:00
parent 852c21b312
commit d6829f30b9
8 changed files with 55 additions and 35 deletions

View File

@ -34,11 +34,11 @@ scene.on('loaded', () => {
.source(data) .source(data)
.size('mag', [ 0, 1 ]) // weight映射通道 .size('mag', [ 0, 1 ]) // weight映射通道
.style({ .style({
intensity: 1, intensity: 3,
radius: 10, radius: 20,
rampColors: { rampColors: {
colors: [ 'rgba(33,102,172,0)', 'rgb(103,169,207)', 'rgb(209,229,240)', 'rgb(253,219,199)', 'rgb(239,138,98)', 'rgb(178,24,43)' ], colors: [ 'rgba(33,102,172,0.0)', 'rgb(103,169,207)', 'rgb(209,229,240)', 'rgb(253,219,199)', 'rgb(239,138,98)', 'rgb(178,24,43,1.0)' ],
positions: [ 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 ] positions: [ 0, 0.2, 0.4, 0.6, 0.8, 1.0 ]
} }
}) })
.render(); .render();

View File

@ -8,21 +8,20 @@ export default class RenderPass {
this.clearColor = cfg.clear.clearColor; this.clearColor = cfg.clear.clearColor;
this.clearAlpha = cfg.clear.clearAlpha; this.clearAlpha = cfg.clear.clearAlpha;
this.size = cfg.size ? cfg.size : cfg.renderer.getSize(); this.size = cfg.size ? cfg.size : cfg.renderer.getSize();
const defaultRenderCfg = {
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat,
stencilBuffer: false,
depthBuffer: false
};
this.renderCfg = cfg.renderCfg ? cfg.renderCfg : defaultRenderCfg;
this._init(cfg); this._init(cfg);
} }
_init() { _init() {
this.scene = new THREE.Scene(); this.scene = new THREE.Scene();
const parameters = { this.pass = new THREE.WebGLRenderTarget(this.size.width, this.size.height, this.renderCfg);
// minFilter: THREE.NearestFilter,
// magFilter: THREE.NearestFilter,
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false,
depthBuffer: false
};
this.pass = new THREE.WebGLRenderTarget(this.size.width, this.size.height, parameters);
this.originClearColor = this.renderer.getClearColor(); this.originClearColor = this.renderer.getClearColor();
this.originClearAlpha = this.renderer.getClearAlpha(); this.originClearAlpha = this.renderer.getClearAlpha();
this.texture = this.pass.texture; this.texture = this.pass.texture;
@ -40,6 +39,5 @@ export default class RenderPass {
this.renderer.setClearColor(this.clearColor, this.clearAlpha); this.renderer.setClearColor(this.clearColor, this.clearAlpha);
this.renderer.render(this.scene, this.camera, this.pass, true); this.renderer.render(this.scene, this.camera, this.pass, true);
this.renderer.setClearColor(this.originClearColor, this.originClearAlpha); this.renderer.setClearColor(this.originClearColor, this.originClearAlpha);
this.texture = this.pass.texture;
} }
} }

View File

@ -60,9 +60,9 @@ function getColorRamp(name) {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
canvas.width = 256; canvas.width = 1;
canvas.height = 1; canvas.height = 256;
const gradient = ctx.createLinearGradient(0, 0, 256, 0); const gradient = ctx.createLinearGradient(0, 0, 0, 256);
let data = null; let data = null;
if (typeof (colorscale) === 'string') { if (typeof (colorscale) === 'string') {
colorscale = colorScales[name]; colorscale = colorScales[name];
@ -76,21 +76,23 @@ function getColorRamp(name) {
gradient.addColorStop(value, colorscale.colors[i]); gradient.addColorStop(value, colorscale.colors[i]);
} }
ctx.fillStyle = gradient; ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 1); ctx.fillRect(0, 0, 1, 256);
data = new Uint8ClampedArray(ctx.getImageData(0, 0, 256, 1).data); data = new Uint8ClampedArray(ctx.getImageData(0, 0, 1, 256).data);
} }
if (Object.prototype.toString.call(colorscale) === '[object Uint8Array]') { if (Object.prototype.toString.call(colorscale) === '[object Uint8Array]') {
data = ctx.createImageData(256, 1); data = ctx.createImageData(1, 256);
} }
return new ImageData(data, 16, 16); return new ImageData(data, 1, 256);
} }
function getTexture(image) { function getTexture(image) {
const texture = new THREE.Texture(image); const texture = new THREE.Texture(image);
texture.magFilter = THREE.LinearFilter; texture.wrapS = THREE.ClampToEdgeWrapping;
texture.minFilter = THREE.LinearFilter; texture.wrapT = THREE.ClampToEdgeWrapping;
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter;
texture.format = THREE.RGBAFormat; texture.format = THREE.RGBAFormat;
texture.type = THREE.UnsignedByteType; texture.type = THREE.UnsignedByteType;
texture.needsUpdate = true; texture.needsUpdate = true;

View File

@ -27,7 +27,8 @@ export function HeatmapColorizeMaterial(opt) {
u_colorRamp: { value: opt.colorRamp } u_colorRamp: { value: opt.colorRamp }
}, },
vertexShader: heatmap_colorize_vert, vertexShader: heatmap_colorize_vert,
fragmentShader: heatmap_colorize_frag fragmentShader: heatmap_colorize_frag,
transparent: true
}); });
return material; return material;
} }

View File

@ -5,5 +5,5 @@ varying vec2 v_uv;
void main(){ void main(){
float intensity = texture2D(u_texture,v_uv).r; float intensity = texture2D(u_texture,v_uv).r;
vec4 color = texture2D(u_colorRamp,vec2(0.5,1.0-intensity)); vec4 color = texture2D(u_colorRamp,vec2(0.5,1.0-intensity));
gl_FragColor = color * intensity; gl_FragColor = color;
} }

View File

@ -1,4 +1,5 @@
precision highp float; precision highp float;
uniform float u_intensity;
varying float v_weight; varying float v_weight;
varying vec2 v_extrude; varying vec2 v_extrude;
@ -6,6 +7,6 @@ varying vec2 v_extrude;
void main(){ void main(){
float GAUSS_COEF = 0.3989422804014327; float GAUSS_COEF = 0.3989422804014327;
float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude); float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude);
float val = v_weight * 10.0 * GAUSS_COEF * exp(d); float val = v_weight * u_intensity * GAUSS_COEF * exp(d);
gl_FragColor = vec4(val, val, val, 1.0); gl_FragColor = vec4(val, val, val, val);
} }

View File

@ -16,7 +16,7 @@ void main(){
vec2 extrude_dir = normalize(vec2(extrude_x,extrude_y)); vec2 extrude_dir = normalize(vec2(extrude_x,extrude_y));
float S = sqrt(-2.0 * log(ZERO / a_weight / u_intensity / GAUSS_COEF)) / 3.0; float S = sqrt(-2.0 * log(ZERO / a_weight / u_intensity / GAUSS_COEF)) / 3.0;
v_extrude = extrude_dir * S; v_extrude = extrude_dir * S;
vec2 extrude = v_extrude * u_radius * pow(2.0,20.0-min(u_zoom,9.0)); vec2 extrude = v_extrude * u_radius * pow(2.0,20.0-u_zoom);
vec4 pos = vec4( position.xy+ extrude, 0.0, 1.0); vec4 pos = vec4( position.xy+ extrude, 0.0, 1.0);
gl_Position = projectionMatrix * modelViewMatrix * pos; gl_Position = projectionMatrix * modelViewMatrix * pos;
} }

View File

@ -37,16 +37,30 @@ function createIntensityPass(layer, bbox) {
const passOrth = new THREE.OrthographicCamera(bbox.width / -2, bbox.width / 2, bbox.height / 2, bbox.height / -2, 1, 10000); const passOrth = new THREE.OrthographicCamera(bbox.width / -2, bbox.width / 2, bbox.height / 2, bbox.height / -2, 1, 10000);
passOrth.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 1000); passOrth.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 1000);
// renderpass // renderpass
const renderer = layer.scene._engine._renderer;
// get extension for bilinear texture interpolation:https://threejs.org/docs/#api/en/textures/DataTexture
const gl = renderer.domElement.getContext('webgl') ||
renderer.domElement.getContext('experimental-webgl');
gl.getExtension('OES_texture_float_linear');
const renderpass = new Renderpass({ const renderpass = new Renderpass({
renderer: layer.scene._engine._renderer, renderer,
camera: passOrth, camera: passOrth,
size: { size: {
width: 10000, width: 2000,
height: 10000 * (bbox.height / bbox.width) height: 2000 * (bbox.height / bbox.width)
}, },
clear: { clear: {
clearColor: 0x000000, clearColor: 0x000000,
clearAlpha: 1.0 clearAlpha: 0.0
},
renderCfg: {
wrapS: THREE.ClampToEdgeWrapping,
wrapT: THREE.ClampToEdgeWrapping,
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false,
depthBuffer: false
} }
}); });
renderpass.add(mesh); renderpass.add(mesh);
@ -56,8 +70,12 @@ function createIntensityPass(layer, bbox) {
render(); render();
function render() { function render() {
requestAnimationFrame(render); requestAnimationFrame(render);
const zoom = scene.getZoom();
mesh.material.uniforms.u_zoom.value = zoom;
const passWidth = Math.min(10000, Math.pow(zoom, 2.0) * 200);
const passHeight = passWidth * (bbox.height / bbox.width);
renderpass.pass.setSize(passWidth, passHeight);
renderpass.render(); renderpass.render();
mesh.material.uniforms.u_zoom.value = scene.getZoom();
} }
} }
function createColorizePass(layer, bbox) { function createColorizePass(layer, bbox) {