diff --git a/debug/gl/terrain-mask.html b/debug/gl/terrain-mask.html
index f96c2c79d7..15318de935 100644
--- a/debug/gl/terrain-mask.html
+++ b/debug/gl/terrain-mask.html
@@ -31,6 +31,7 @@
"zoom": 13,
"pitch": 10,
"bearing": 0,
+ renderer: 'gl',
queryTerrainInMapEvents: false
});
@@ -51,6 +52,7 @@
const terrain = {
debug: true,
+ shader: 'lit',
type: "mapbox",
urlTemplate: `https://{s}.tiles.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=${token}`,
subdomains: ["a", "b", "c", "d"]
@@ -65,11 +67,11 @@
type: "Polygon",
coordinates: [
[
- [94.50812103, 29.45095163, 3000],
- [94.59012103, 29.45095163, 3000],
- [94.59012103, 29.40095163, 3000],
- [94.50812103, 29.40095163, 3000],
- [94.50812103, 29.45095163, 3000]
+ [94.50812103, 29.45095163, 0],
+ [94.59012103, 29.45095163, 0],
+ [94.59012103, 29.40095163, 0],
+ [94.50812103, 29.40095163, 0],
+ [94.50812103, 29.45095163, 0]
]
]
},
@@ -99,11 +101,10 @@
renderPlugin: {
dataConfig: {
type: "fill",
+ altitudeOffset: 3000
},
sceneConfig: {},
type: "terrain-flat-mask",
- },
- symbol: {
}
}
]
diff --git a/packages/gl/src/layer/terrain/TerrainLitPainter.js b/packages/gl/src/layer/terrain/TerrainLitPainter.js
index 1e98fdaa27..6d0f645e24 100644
--- a/packages/gl/src/layer/terrain/TerrainLitPainter.js
+++ b/packages/gl/src/layer/terrain/TerrainLitPainter.js
@@ -105,11 +105,16 @@ class TerrainLitPainter extends TerrainPainter {
const material = new reshader.pbr.StandardMaterial(matInfo);
const mesh = new reshader.Mesh(geo, material);
mesh.properties.matVer = this._matVer;
+ if (!mesh.uniforms.flatMask) {
+ const emptyTexture = this.getEmptyTexture();
+ mesh.setUniform('flatMask', emptyTexture);
+ }
const defines = mesh.defines;
defines['HAS_UV_FLIP'] = 1;
defines['HAS_TERRAIN_NORMAL'] = 1;
defines['HAS_MAP'] = 1;
defines['HAS_LAYER_OPACITY'] = 1;
+ defines['HAS_TERRAIN_FLAT_MASK'] = 1;
mesh.defines = defines;
// mesh.setUniform('terrainTileResolution', tileInfo.res);
this.prepareMesh(mesh, tileInfo, terrainImage);
@@ -126,7 +131,10 @@ class TerrainLitPainter extends TerrainPainter {
mesh.properties.matVer = this._matVer;
}
if (tileImage.skin) {
- mesh.material.set('skinTexture', tileImage.skin);
+ mesh.material.set('skinTexture', tileImage.skin.color[0]);
+ }
+ if (tileImage.mask) {
+ mesh.setUniform('flatMask', tileImage.mask.color[0]);
}
mesh.setUniform('polygonOpacity', 1.0);
// const { skirtOffset, skirtCount } = mesh.properties;
diff --git a/packages/reshader.gl/src/pbr/glsl/standard.vert b/packages/reshader.gl/src/pbr/glsl/standard.vert
index 3d1e342aa0..674251014d 100644
--- a/packages/reshader.gl/src/pbr/glsl/standard.vert
+++ b/packages/reshader.gl/src/pbr/glsl/standard.vert
@@ -4,8 +4,13 @@ precision highp float;
attribute vec3 aPosition;
-#if defined(HAS_MAP)
+#if defined(HAS_MAP) || defined(HAS_TERRAIN_FLAT_MASK)
attribute vec2 aTexCoord;
+ #include
+#endif
+
+#if defined(HAS_MAP)
+
uniform vec2 uvOrigin;
uniform vec2 uvScale;
uniform vec2 uvOffset;
diff --git a/packages/reshader.gl/src/pbr/wgsl/standard_vert.wgsl b/packages/reshader.gl/src/pbr/wgsl/standard_vert.wgsl
index 51defac84f..702578b99b 100644
--- a/packages/reshader.gl/src/pbr/wgsl/standard_vert.wgsl
+++ b/packages/reshader.gl/src/pbr/wgsl/standard_vert.wgsl
@@ -8,6 +8,7 @@
#include
#endif
#include
+#include
struct VertexInput {
#ifdef POSITION_IS_INT
@@ -16,8 +17,11 @@ struct VertexInput {
@location($i) aPosition: vec3f,
#endif
- #if HAS_MAP
+ #if HAS_MAP || HAS_TERRAIN_FLAT_MASK
@location($i) aTexCoord: vec2f,
+ #endif
+ #if HAS_MAP
+
#ifdef HAS_I3S_UVREGION
@location($i) uvRegion: vec4f,
#endif
diff --git a/packages/reshader.gl/src/shaderlib/glsl/output.vert b/packages/reshader.gl/src/shaderlib/glsl/output.vert
index c9fcada760..35fe7804d9 100644
--- a/packages/reshader.gl/src/shaderlib/glsl/output.vert
+++ b/packages/reshader.gl/src/shaderlib/glsl/output.vert
@@ -69,7 +69,11 @@ mat4 getPositionMatrix() {
}
#ifdef HAS_MIN_ALTITUDE
-uniform float minAltitude;
+ uniform float minAltitude;
+#endif
+
+#ifdef HAS_TERRAIN_FLAT_MASK
+ uniform sampler2D flatMask;
#endif
vec4 getPosition(vec3 aPosition) {
@@ -84,6 +88,15 @@ vec4 getPosition(vec3 aPosition) {
#ifdef HAS_TERRAIN_ALTITUDE
POSITION.z += aTerrainAltitude * 100.0;
#endif
+ #ifdef HAS_TERRAIN_FLAT_MASK
+ vec2 uv = aTexCoord;
+ uv.y = 1.0 - uv.y;
+ vec4 encodedHeight = texture2D(flatMask, uv);
+ if (length(encodedHeight) < 2.0) {
+ float maskHeight = decodeFloat32(encodedHeight);
+ POSITION.z = min(POSITION.z, maskHeight);
+ }
+ #endif
#ifdef HAS_MIN_ALTITUDE
POSITION.z += minAltitude * 100.0;
#endif
diff --git a/packages/reshader.gl/src/shaderlib/wgsl/common_pack_float.ts b/packages/reshader.gl/src/shaderlib/wgsl/common_pack_float.ts
index cb8fefceb5..809133f8cb 100644
--- a/packages/reshader.gl/src/shaderlib/wgsl/common_pack_float.ts
+++ b/packages/reshader.gl/src/shaderlib/wgsl/common_pack_float.ts
@@ -67,6 +67,34 @@ fn common_encodeDepth(depth: f32) -> vec4f {
fn common_decodeDepth(pack: vec4f) -> f32 {
return pack.r + pack.g / 255.0;
}
+
+// https://cloud.tencent.com/developer/ask/sof/103481834
+fn encodeFloat32(f: f32) -> vec4f {
+ var e = 5.0;
+
+ var F = abs(f);
+ var Sign = step(0.0, -f);
+ var Exponent = floor(log2(F));
+ var Mantissa = (exp2(- Exponent) * F);
+ Exponent = floor(log2(F) + 127.0) + floor(log2(Mantissa));
+ var rgba = vec4(0.0);
+ rgba[0] = 128.0 * Sign + floor(Exponent*exp2(-1.0));
+ rgba[1] = 128.0 * mod(Exponent,2.0) + mod(floor(Mantissa*128.0),128.0);
+ rgba[2] = floor(mod(floor(Mantissa*exp2(23.0 -8.0)),exp2(8.0)));
+ rgba[3] = floor(exp2(23.0)*mod(Mantissa,exp2(-15.0)));
+ return rgba / 255.0;
+}
+
+fn decodeFloat32(rgba: vec4f) -> f32 {
+ rgba *= 255.0;
+ var Sign = 1.0 - step(128.0,rgba[0])*2.0;
+ var Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0;
+ var Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000);
+ var Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 ));
+ return Result;
+}
+
+
`;
const frag = vert;
diff --git a/packages/reshader.gl/src/shaderlib/wgsl/output.ts b/packages/reshader.gl/src/shaderlib/wgsl/output.ts
index ce5d6d108e..169442dd2b 100644
--- a/packages/reshader.gl/src/shaderlib/wgsl/output.ts
+++ b/packages/reshader.gl/src/shaderlib/wgsl/output.ts
@@ -31,6 +31,11 @@ const vert = /* wgsl */`
@group(0) @binding($b) var altitudeUniforms: AltitudeUniforms;
#endif
+#ifdef HAS_TERRAIN_FLAT_MASK
+ @group(0) @binding($b) var flatMask: texture_2d;
+ @group(0) @binding($b) var flatMaskSampler: sampler;
+#endif
+
fn getPositionMatrix(input: VertexInput, vertexOutput: ptr, positionMatrix: mat4x4f) -> mat4x4f {
var worldMatrix: mat4x4f;
#ifdef HAS_INSTANCE
@@ -79,6 +84,15 @@ fn getPosition(inputPosition: vec3f, vertexInput: VertexInput) -> vec4f {
#ifdef HAS_TERRAIN_ALTITUDE
outputPosition.z += vertexInput.aTerrainAltitude * 100.0;
#endif
+ #ifdef HAS_TERRAIN_FLAT_MASK
+ var uv = aTexCoord;
+ uv.y = 1.0 - uv.y;
+ let encodedHeight = textureSample(flatMask, flatMaskSampler, uv);
+ if (length(encodedHeight) < 2.0) {
+ float maskHeight = decodeFloat32(encodedHeight);
+ outputPosition.z = min(outputPosition.z, maskHeight);
+ }
+ #endif
#ifdef HAS_MIN_ALTITUDE
outputPosition.z += altitudeUniforms.minAltitude * 100.0;
#endif
diff --git a/packages/vt/src/layer/layer/VectorTileLayer.ts b/packages/vt/src/layer/layer/VectorTileLayer.ts
index 75abdf06e8..2df1806870 100644
--- a/packages/vt/src/layer/layer/VectorTileLayer.ts
+++ b/packages/vt/src/layer/layer/VectorTileLayer.ts
@@ -1291,6 +1291,9 @@ class VectorTileLayer extends maptalks.TileLayer {
) {
throw new Error(`Invalid filter at ${i} : ${JSON.stringify(filter)}`);
}
+ if (!styles[i].symbol) {
+ styles[i].symbol = {};
+ }
//TODO 如果定义了renderPlugin就必须定义symbol
}
}
diff --git a/packages/vt/test/integration/fixtures/terrain/terrain-lit-mask/expected.png b/packages/vt/test/integration/fixtures/terrain/terrain-lit-mask/expected.png
new file mode 100644
index 0000000000..2b00d505a6
Binary files /dev/null and b/packages/vt/test/integration/fixtures/terrain/terrain-lit-mask/expected.png differ
diff --git a/packages/vt/test/integration/fixtures/terrain/terrain-lit-mask/index.js b/packages/vt/test/integration/fixtures/terrain/terrain-lit-mask/index.js
new file mode 100644
index 0000000000..1e53df74b7
--- /dev/null
+++ b/packages/vt/test/integration/fixtures/terrain/terrain-lit-mask/index.js
@@ -0,0 +1,49 @@
+const data = {
+ type: 'FeatureCollection',
+ features: [
+ { type: 'Feature', geometry: { type: 'Polygon', coordinates: [
+ [[91.14478,29.696272], [91.14778,29.696272], [91.14778,29.690272], [91.14478,29.690272], [91.14478,29.696272]]]
+ }, properties: { type: 1 } }
+ ]
+
+};
+
+const style = [
+ {
+ filter: true,
+ renderPlugin: {
+ type: 'fill',
+ dataConfig: {
+ type: 'fill'
+ }
+ },
+ symbol: {
+ polygonFill: '#f00',
+ polygonOpacity: 0.5
+ }
+ },
+ {
+ filter: true,
+ renderPlugin: {
+ type: 'terrain-flat-mask',
+ dataConfig: {
+ type: 'fill',
+ altitudeOffset: 3500
+ }
+ },
+ symbol: {}
+ }
+];
+
+module.exports = {
+ style,
+ data,
+ lit: true,
+ renderingCount: 10,
+ view: {
+ center: [91.14478,29.708272],
+ zoom: 12,
+ pitch: 20,
+ bearing: 0,
+ }
+};
diff --git a/packages/vt/test/integration/fixtures/terrain/terrain-mask/expected.png b/packages/vt/test/integration/fixtures/terrain/terrain-mask/expected.png
new file mode 100644
index 0000000000..bbc7413347
Binary files /dev/null and b/packages/vt/test/integration/fixtures/terrain/terrain-mask/expected.png differ
diff --git a/packages/vt/test/integration/fixtures/terrain/terrain-mask/index.js b/packages/vt/test/integration/fixtures/terrain/terrain-mask/index.js
new file mode 100644
index 0000000000..8ec3ca2026
--- /dev/null
+++ b/packages/vt/test/integration/fixtures/terrain/terrain-mask/index.js
@@ -0,0 +1,48 @@
+const data = {
+ type: 'FeatureCollection',
+ features: [
+ { type: 'Feature', geometry: { type: 'Polygon', coordinates: [
+ [[91.14478,29.696272], [91.14778,29.696272], [91.14778,29.690272], [91.14478,29.690272], [91.14478,29.696272]]]
+ }, properties: { type: 1 } }
+ ]
+
+};
+
+const style = [
+ {
+ filter: true,
+ renderPlugin: {
+ type: 'fill',
+ dataConfig: {
+ type: 'fill'
+ }
+ },
+ symbol: {
+ polygonFill: '#f00',
+ polygonOpacity: 0.5
+ }
+ },
+ {
+ filter: true,
+ renderPlugin: {
+ type: 'terrain-flat-mask',
+ dataConfig: {
+ type: 'fill',
+ altitudeOffset: 3500
+ }
+ },
+ symbol: {}
+ }
+];
+
+module.exports = {
+ style,
+ data,
+ renderingCount: 10,
+ view: {
+ center: [91.14478,29.708272],
+ zoom: 12,
+ pitch: 20,
+ bearing: 0,
+ }
+};
diff --git a/packages/vt/test/integration/terrain.spec.js b/packages/vt/test/integration/terrain.spec.js
index 6c8b1700a1..fb14ec4a2b 100644
--- a/packages/vt/test/integration/terrain.spec.js
+++ b/packages/vt/test/integration/terrain.spec.js
@@ -23,6 +23,8 @@ const DEFAULT_VIEW = {
}
};
+const TEST_CANVAS = document.createElement('canvas');
+
describe('vector tile on terrain integration specs', () => {
let map, container, server;
const containerSize = 128;
@@ -51,6 +53,7 @@ describe('vector tile on terrain integration specs', () => {
options.lights = DEFAULT_VIEW.lights;
}
options.devicePixelRatio = 1;
+ options.renderer = 'canvas';
const limit = style.renderingCount || 6;
map = new maptalks.Map(container, options);
@@ -76,18 +79,29 @@ describe('vector tile on terrain integration specs', () => {
fadeAnimation: false
// shader: 'lit'
};
+ if (style.lit) {
+ terrain.shader = 'lit';
+ }
const group = new GroupGLLayer('group', [layer], { terrain });
group.addTo(map);
+
const terrainLayer = group.getTerrainLayer();
let count = 0;
let ended = false;
terrainLayer.on('terrainreadyandrender', () => {
count++;
- const canvas = map.getRenderer().canvas;
+ const mapCanvas = map.getRenderer().canvas;
const expectedPath = style.expected;
if (!ended && count >= limit) {
ended = true;
+
+ const canvas = TEST_CANVAS;
+ canvas.width = mapCanvas.width;
+ canvas.height = mapCanvas.height;
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(mapCanvas, 0, 0);
+
//比对测试
match(canvas, expectedPath, (err, result) => {
if (err) {
diff --git a/packages/vt/test/specs/update.vector.symbol.spec.js b/packages/vt/test/specs/update.vector.symbol.spec.js
index 25d26340fd..9950a72999 100644
--- a/packages/vt/test/specs/update.vector.symbol.spec.js
+++ b/packages/vt/test/specs/update.vector.symbol.spec.js
@@ -73,6 +73,7 @@ describe('vector layers symbol update specs', () => {
count++;
});
let updated = false;
+ let doneCalled = false;
group.on('layerload', () => {
if (count >= 1 && !updated) {
const pixel = readPixel(layer.getRenderer().canvas, x + 20, y);
@@ -83,11 +84,12 @@ describe('vector layers symbol update specs', () => {
markerHeight: 60
});
updated = true;
- } else if (updated && count >= 4) {
+ } else if (updated && count >= 4 && !doneCalled) {
const pixel = readPixel(renderer.canvas, x + 20, y);
//中心点往外40,能读到像素了
assert.deepEqual(pixel, [255, 0, 0, 255]);
assert(!partialUpdate);
+ doneCalled = true;
done();
}
});
@@ -123,6 +125,7 @@ describe('vector layers symbol update specs', () => {
});
let updated = false;
let partialUpdate = false;
+ let doneCalled = false;
layer.on('partialupdate', () => {
partialUpdate = true;
});
@@ -151,12 +154,13 @@ describe('vector layers symbol update specs', () => {
},
]);
updated = true;
- } else if (updated && count >= 3) {
+ } else if (updated && count >= 3 && !doneCalled) {
const pixel = readPixel(renderer.canvas, x + 20, y);
assert.deepEqual(pixel, [0, 255, 0, 255]);
const pixel1 = readPixel(renderer.canvas, x, y);
assert.deepEqual(pixel1, [255, 0, 0, 255]);
assert(!partialUpdate);
+ doneCalled = true;
done();
}
});