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)
.size('mag', [ 0, 1 ]) // weight映射通道
.style({
intensity: 1,
radius: 10,
intensity: 3,
radius: 20,
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)' ],
positions: [ 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 ]
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.2, 0.4, 0.6, 0.8, 1.0 ]
}
})
.render();

View File

@ -8,21 +8,20 @@ export default class RenderPass {
this.clearColor = cfg.clear.clearColor;
this.clearAlpha = cfg.clear.clearAlpha;
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);
}
_init() {
this.scene = new THREE.Scene();
const parameters = {
// 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.pass = new THREE.WebGLRenderTarget(this.size.width, this.size.height, this.renderCfg);
this.originClearColor = this.renderer.getClearColor();
this.originClearAlpha = this.renderer.getClearAlpha();
this.texture = this.pass.texture;
@ -40,6 +39,5 @@ export default class RenderPass {
this.renderer.setClearColor(this.clearColor, this.clearAlpha);
this.renderer.render(this.scene, this.camera, this.pass, true);
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 ctx = canvas.getContext('2d');
canvas.width = 256;
canvas.height = 1;
const gradient = ctx.createLinearGradient(0, 0, 256, 0);
canvas.width = 1;
canvas.height = 256;
const gradient = ctx.createLinearGradient(0, 0, 0, 256);
let data = null;
if (typeof (colorscale) === 'string') {
colorscale = colorScales[name];
@ -76,21 +76,23 @@ function getColorRamp(name) {
gradient.addColorStop(value, colorscale.colors[i]);
}
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 1);
data = new Uint8ClampedArray(ctx.getImageData(0, 0, 256, 1).data);
ctx.fillRect(0, 0, 1, 256);
data = new Uint8ClampedArray(ctx.getImageData(0, 0, 1, 256).data);
}
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) {
const texture = new THREE.Texture(image);
texture.magFilter = THREE.LinearFilter;
texture.minFilter = THREE.LinearFilter;
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter;
texture.format = THREE.RGBAFormat;
texture.type = THREE.UnsignedByteType;
texture.needsUpdate = true;

View File

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

View File

@ -5,5 +5,5 @@ varying vec2 v_uv;
void main(){
float intensity = texture2D(u_texture,v_uv).r;
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;
uniform float u_intensity;
varying float v_weight;
varying vec2 v_extrude;
@ -6,6 +7,6 @@ varying vec2 v_extrude;
void main(){
float GAUSS_COEF = 0.3989422804014327;
float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude);
float val = v_weight * 10.0 * GAUSS_COEF * exp(d);
gl_FragColor = vec4(val, val, val, 1.0);
}
float val = v_weight * u_intensity * GAUSS_COEF * exp(d);
gl_FragColor = vec4(val, val, val, val);
}

View File

@ -16,7 +16,7 @@ void main(){
vec2 extrude_dir = normalize(vec2(extrude_x,extrude_y));
float S = sqrt(-2.0 * log(ZERO / a_weight / u_intensity / GAUSS_COEF)) / 3.0;
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);
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);
passOrth.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 1000);
// 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({
renderer: layer.scene._engine._renderer,
renderer,
camera: passOrth,
size: {
width: 10000,
height: 10000 * (bbox.height / bbox.width)
width: 2000,
height: 2000 * (bbox.height / bbox.width)
},
clear: {
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);
@ -56,8 +70,12 @@ function createIntensityPass(layer, bbox) {
render();
function 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();
mesh.material.uniforms.u_zoom.value = scene.getZoom();
}
}
function createColorizePass(layer, bbox) {