Merge branch 'dev-vertex-compression' into 'master'

Dev vertex compression

对于 point layer(circle) 压缩顶点数据
https://yuque.antfin-inc.com/yuqi.pyq/fgetpa/wxv543#xzVLo

优化后每个顶点只需要一个 vec4 存储颜色、pickingId 等数据:
vec4(color, color, pickingId, (extrude.x, extrude.y, radius))

See merge request !31
This commit is contained in:
thinkinggis 2019-05-30 16:45:40 +08:00
commit 336146e4c3
6 changed files with 99 additions and 30 deletions

View File

@ -1,25 +1,46 @@
import { packUint8ToFloat } from '../../../util/vertex-compress';
const LEFT_SHIFT18 = 262144.0;
const LEFT_SHIFT20 = 1048576.0;
export default function circleBuffer(layerData) {
const index = [];
const aExtrude = [];
const aRadius = [];
const aColor = [];
const aPickingId = [];
const aPosition = [];
const aPackedData = [];
layerData.forEach(({ size = 0, color, id, coordinates }, i) => {
if (isNaN(size)) {
size = 0;
}
// pack color(vec4) into vec2
const packedColor = [
packUint8ToFloat(color[0] * 255, color[1] * 255),
packUint8ToFloat(color[2] * 255, color[3] * 255)
];
// construct point coords
aExtrude.push(-1, -1, 1, -1, 1, 1, -1, 1);
aRadius.push(size, size, size, size);
aColor.push(...color, ...color, ...color, ...color);
aPickingId.push(id, id, id, id);
[
[ -1, -1 ],
[ 1, -1 ],
[ 1, 1 ],
[ -1, 1 ]
].forEach(extrude => {
// vec4(color, color, (4-bit extrude, 16-bit size), id)
aPackedData.push(
...packedColor,
(extrude[0] + 1) * LEFT_SHIFT20 + (extrude[1] + 1) * LEFT_SHIFT18 + size,
id
);
});
// TODO如果使用相对瓦片坐标还可以进一步压缩
aPosition.push(...coordinates, ...coordinates, ...coordinates, ...coordinates);
index.push(...[ 0, 1, 2, 0, 2, 3 ].map(n => n + i * 4));
});
return {
aExtrude,
aRadius,
aColor,
aPickingId,
aPosition,
index
index,
aPackedData
};
}

View File

@ -1,6 +1,4 @@
attribute float a_radius;
attribute vec2 a_shape;
attribute vec4 a_color;
attribute vec4 a_packed_data;
uniform float u_zoom : 1;
uniform float u_stroke_width : 2;
@ -11,24 +9,44 @@ varying vec3 v_data;
varying vec4 v_color;
varying float v_radius;
void main() {
v_color = a_color;
v_radius = a_radius;
#pragma include "decode"
void main() {
// unpack color(vec2)
v_color = decode_color(a_packed_data.xy);
// unpack picking_id
float picking_id = a_packed_data.w;
// unpack data(extrude(4-bit), radius(16-bit))
float compressed = a_packed_data.z;
// extrude(4-bit)
vec2 extrude;
extrude.x = floor(compressed * SHIFT_RIGHT20);
compressed -= extrude.x * SHIFT_LEFT20;
extrude.x = extrude.x - 1.;
extrude.y = floor(compressed * SHIFT_RIGHT18);
compressed -= extrude.y * SHIFT_LEFT18;
extrude.y = extrude.y - 1.;
// radius(16-bit)
float radius = compressed;
v_radius = radius;
// extrude
float zoom_scale = pow(2., 20. - u_zoom);
vec2 offset = a_shape * (a_radius + u_stroke_width) * zoom_scale;
vec2 offset = extrude * (radius + u_stroke_width) * zoom_scale;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xy + offset, 0.0, 1.0);
// anti-alias
float antialiasblur = 1.0 / (a_radius + u_stroke_width);
float antialiasblur = 1.0 / (radius + u_stroke_width);
// construct point coords
v_data = vec3(a_shape, antialiasblur);
v_data = vec3(extrude, antialiasblur);
// picking
if(pickingId == u_activeId) {
if(picking_id == u_activeId) {
v_color = u_activeColor;
}
worldId = id_toPickColor(pickingId);
worldId = id_toPickColor(picking_id);
}

View File

@ -51,9 +51,12 @@ import mask_quard_frag from '../shader/tile/mask_quard_frag.glsl';
import common from './common.glsl';
import { registerModule } from '../../util/shaderModule';
import pick_color from './shaderChunks/pick_color.glsl';
import decode from './shaderChunks/decode.glsl';
export function compileBuiltinModules() {
registerModule('point', { vs: point_vert, fs: point_frag });
registerModule('common', { vs: common, fs: common });
registerModule('decode', { vs: decode, fs: '' });
registerModule('pick_color', { vs: pick_color, fs: pick_color });
registerModule('circle', { vs: circle_vert, fs: circle_frag });
registerModule('polygon', { vs: polygon_vert, fs: polygon_frag });

View File

@ -0,0 +1,17 @@
#define SHIFT_RIGHT18 1.0 / 262144.0
#define SHIFT_RIGHT20 1.0 / 1048576.0
#define SHIFT_LEFT18 262144.0
#define SHIFT_LEFT20 1048576.0
vec2 unpack_float(const float packedValue) {
int packedIntValue = int(packedValue);
int v0 = packedIntValue / 256;
return vec2(v0, packedIntValue - v0 * 256);
}
vec4 decode_color(const vec2 encodedColor) {
return vec4(
unpack_float(encodedColor[0]) / 255.0,
unpack_float(encodedColor[1]) / 255.0
);
}

View File

@ -9,14 +9,11 @@ export default function drawCircle(layerData, layer) {
const style = layer.get('styleOptions');
const activeOption = layer.get('activedOptions');
const { aColor, aExtrude, aPickingId, aPosition, index, aRadius } = PointBuffer.CircleBuffer(layerData, style);
const { aPosition, aPackedData, index } = PointBuffer.CircleBuffer(layerData, style);
const geometry = new THREE.BufferGeometry();
geometry.setIndex(index);
geometry.addAttribute('position', new THREE.Float32BufferAttribute(aPosition, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(aColor, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(aPickingId, 1));
geometry.addAttribute('a_shape', new THREE.Float32BufferAttribute(aExtrude, 2));
geometry.addAttribute('a_radius', new THREE.Float32BufferAttribute(aRadius, 1));
geometry.addAttribute('a_packed_data', new THREE.Float32BufferAttribute(aPackedData, 4));
const material = new CircleMaterial({
u_opacity: style.opacity,

View File

@ -0,0 +1,13 @@
import clamp from '@antv/util/lib/clamp';
/**
* encode 2 8-bit unsigned int into a 16-bit float
* @param {number} a 8-bit int
* @param {number} b 8-bit int
* @return {number} float
*/
export function packUint8ToFloat(a, b) {
a = clamp(Math.floor(a), 0, 255);
b = clamp(Math.floor(b), 0, 255);
return 256 * a + b;
}