diff --git a/demos/03_choropleths_polygon.html b/demos/03_choropleths_polygon.html
index 0700fcf2b9..a9c6ba4da4 100644
--- a/demos/03_choropleths_polygon.html
+++ b/demos/03_choropleths_polygon.html
@@ -81,7 +81,6 @@ scene.on('loaded', () => {
}
})
.shape('fill')
- .pattern('id1')
.active(true)
.style({
opacity: 1
diff --git a/demos/grid.html b/demos/grid.html
index ba02a4fa0e..d64144ef14 100644
--- a/demos/grid.html
+++ b/demos/grid.html
@@ -53,16 +53,19 @@ scene.on('loaded', () => {
},
{
type: 'grid',
- size: 15000,
+ size: 160000,
field:'v',
method:'sum'
}
]
})
- .shape('grid')
+ .shape('squareColumn')
+ .size('count',(value)=>{
+ return value * 1000;
+ })
.active({fill:'red'})
.style({
- coverage: 0.8
+ coverage: 0.6
})
.color('count', ["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"])
.render();
diff --git a/src/core/engine/renderer.js b/src/core/engine/renderer.js
index d1c689441f..aedae63622 100644
--- a/src/core/engine/renderer.js
+++ b/src/core/engine/renderer.js
@@ -8,7 +8,7 @@ export default class Renderer {
}
initRender() {
this.renderer = new THREE.WebGLRenderer({
- antialias: false,
+ antialias: true,
alpha: true,
autoClear: false
});
diff --git a/src/geom/buffer/heatmap/grid_3d.js b/src/geom/buffer/heatmap/grid_3d.js
new file mode 100644
index 0000000000..01b1e0bc51
--- /dev/null
+++ b/src/geom/buffer/heatmap/grid_3d.js
@@ -0,0 +1,89 @@
+import BufferBase from '../buffer';
+export default class Grid3D extends BufferBase {
+ _buildFeatures() {
+ const layerData = this.get('layerData');
+ this._offset = 0;
+ const shapeType = this.get('shapeType');
+ layerData.forEach(feature => {
+ this._calculateTop(feature);
+ if (shapeType === 'squareColumn') {
+ this._calculateWall(feature);
+ }
+ delete feature.bufferInfo;
+ });
+ }
+ _initAttributes() {
+ super._initAttributes();
+ this.attributes.miters = new Float32Array(this.verticesCount * 3);
+ this.attributes.normals = new Float32Array(this.verticesCount * 3);
+ }
+ _calculateFeatures() {
+ const layerData = this.get('layerData');
+ const shapeType = this.get('shapeType');
+ if (shapeType === 'squareColumn') {
+ this.verticesCount = layerData.length * 20;
+ } else {
+ this.verticesCount = layerData.length * 4;
+ }
+ this.indexCount = this.verticesCount * 1.5;
+ }
+ _calculateTop(feature) {
+ const [ x, y ] = feature.coordinates;
+ let { size } = feature;
+
+ feature.bufferInfo = {
+ verticesOffset: this._offset
+ };
+ const shapeType = this.get('shapeType');
+ if (shapeType !== 'squareColumn') {
+ size = 0;
+ }
+ this._encodeArray(feature, 4);
+ this.attributes.positions.set([ x, y, size, x, y, size, x, y, size, x, y, size ], this._offset * 3);
+ this.attributes.miters.set([ -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1 ], this._offset * 3);
+ this.attributes.normals.set([ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 ], this._offset * 3); // top normal
+ const indexArray = [ 0, 2, 1, 2, 3, 1 ].map(v => { return v + this._offset; });
+ this.indexArray.set(indexArray, this._offset * 1.5);
+ this._offset += 4;
+ }
+ _calculateWall(feature) {
+ const { size } = feature;
+ const [ x, y ] = feature.coordinates;
+ const vertices = [ 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1 ];
+ feature.bufferInfo = {
+ verticesOffset: this._offset
+ };
+ this._encodeArray(feature, 20);
+ // front left, back right
+ this.attributes.normals.set([
+ 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // bottom
+ -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // left
+ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // top
+ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 // right
+ ], this._offset * 3); // top normal
+
+ for (let i = 0; i < 4; i++) {
+ this.attributes.positions.set([ x, y, 1, x, y, 1, x, y, 1, x, y, 1 ], this._offset * 3);
+ const prePoint = vertices.slice(i * 3, i * 3 + 3);
+ const nextPoint = vertices.slice(i * 3 + 3, i * 3 + 6);
+ this._calculateExtrudeFace(prePoint, nextPoint, this._offset, this._offset * 1.5, size);
+ this._offset += 4;
+ }
+ }
+ _calculateExtrudeFace(prePoint, nextPoint, positionOffset, indexOffset, size) {
+ this.attributes.miters.set([
+ prePoint[0], prePoint[1], size,
+ nextPoint[0], nextPoint[1], size,
+ prePoint[0], prePoint[1], 0,
+ nextPoint[0], nextPoint[1], 0
+ ],
+ positionOffset * 3);
+ const indexArray = [ 0, 1, 2, 1, 3, 2 ].map(v => { return v + positionOffset; });
+ if (this.get('uv')) {
+ // temp 点亮城市demo
+ this.attributes.uv.set([ 0.1, 0, 0, 0, 0.1, size / 2000, 0, size / 2000 ], positionOffset * 2);
+ }
+ this.indexArray.set(indexArray, indexOffset);
+ }
+
+}
diff --git a/src/geom/buffer/heatmap/hexagon.js b/src/geom/buffer/heatmap/hexagon.js
index eb95ef5d5b..68cb3555ff 100644
--- a/src/geom/buffer/heatmap/hexagon.js
+++ b/src/geom/buffer/heatmap/hexagon.js
@@ -1,4 +1,4 @@
-import { fill } from '../../shape/polygon';
+import { fill, extrude } from '../../shape/polygon';
export default function hexagonBuffer(layerData) {
const attribute = {
vertices: [],
diff --git a/src/geom/buffer/heatmap/hexagon_3d.js b/src/geom/buffer/heatmap/hexagon_3d.js
new file mode 100644
index 0000000000..ccbf30cbc0
--- /dev/null
+++ b/src/geom/buffer/heatmap/hexagon_3d.js
@@ -0,0 +1,33 @@
+import BufferBase from '../buffer';
+import { fill, extrude } from '../../shape/polygon';
+import { fillPolygon, extrude_Polygon } from '../../extrude';
+import { polygonPath } from '../../shape/path';
+export default class Grid3D extends BufferBase {
+ _buildFeatures() {
+ const layerData = this.get('layerData');
+ this._offset = 0;
+
+ layerData.forEach(feature => {
+
+ });
+ }
+ _initAttributes() {
+ super._initAttributes();
+ this.attributes.miters = new Float32Array(this.verticesCount * 3);
+ this.attributes.normals = new Float32Array(this.verticesCount * 3);
+ }
+ _calculateFeatures() {
+ const hexgonPoints = polygonPath(6);
+ const hexgonFill = fillPolygon([ hexgonPoints ]);
+ const layerData = this.get('layerData');
+ this.verticesCount = hexgonFill.positions.length / 3 * layerData.length;
+ this.indexCount = hexgonFill.indexArray * layerData.length;
+ this.featureBuffer = hexgonFill;
+ }
+ _calculatefill(feature) {
+ // this.
+ }
+ _getPoints(num) {
+ return polygonPath(num);
+ }
+}
diff --git a/src/geom/buffer/index.js b/src/geom/buffer/index.js
index bb38e3e071..55c3ff3090 100644
--- a/src/geom/buffer/index.js
+++ b/src/geom/buffer/index.js
@@ -9,6 +9,10 @@ import ExtrudeBuffer from './polygon/extrude_buffer';
import MeshLineBuffer from './line/meshline';
import ArcLineBuffer from './line/arcline';
+// heatmap
+
+import Grid3D from './heatmap/grid_3d';
+
import { registerBuffer, getBuffer } from './factory';
registerBuffer('polygon', 'fill', FillBuffer);
@@ -20,4 +24,9 @@ registerBuffer('line', 'line', MeshLineBuffer);
registerBuffer('line', 'arc', ArcLineBuffer);
registerBuffer('line', 'greatCircle', ArcLineBuffer);
+// heatmap
+
+registerBuffer('heatmap', 'square', Grid3D);
+registerBuffer('heatmap', 'squareColumn', Grid3D);
+
export { getBuffer };
diff --git a/src/geom/extrude copy.js b/src/geom/extrude copy.js
new file mode 100644
index 0000000000..85fc86cad9
--- /dev/null
+++ b/src/geom/extrude copy.js
@@ -0,0 +1,107 @@
+import earcut from 'earcut';
+
+/**
+ * 计算是否拉伸
+ * @param {Array} points 点坐标数组
+ * @param {boolean} extrude 是否拉伸
+ * @return {object} 顶点坐标顶点索引
+ */
+export default function extrudePolygon(points, extrude) {
+ // height += Math.random() * 100; // 解决 depth
+ const p1 = points[0][0];
+ const p2 = points[0][points[0].length - 1];
+ const faceUv = [];
+ if (p1[0] === p2[0] && p1[1] === p2[1]) {
+ points[0] = points[0].slice(0, points[0].length - 1);
+ }
+ const n = points[0].length;
+ const flattengeo = earcut.flatten(points);
+ const positions = [];
+ let cells = [];
+ const { dimensions } = flattengeo;
+ const triangles = earcut(flattengeo.vertices, flattengeo.holes, flattengeo.dimensions);
+ cells = triangles;
+
+ const pointCount = flattengeo.vertices.length / dimensions;
+ const { vertices } = flattengeo;
+ extrude ? full() : flat();
+
+
+ function flat() {
+ for (let i = 0; i < pointCount; i++) {
+ positions.push([ vertices[ i * dimensions ], vertices[i * dimensions + 1 ], 0 ]);
+ }
+ }
+ function full() {
+ // 顶部纹理
+ triangles.forEach(() => {
+ faceUv.push(-1, -1);
+ });
+ // 顶部坐标
+
+ for (let i = 0; i < pointCount; i++) {
+ positions.push([ vertices[ i * dimensions ], vertices[i * dimensions + 1 ], 1 ]);
+ }
+ for (let i = 0; i < pointCount; i++) {
+ positions.push([ vertices[ i * dimensions ], vertices[i * dimensions + 1 ], 0 ]);
+ }
+ for (let i = 0; i < n; i++) {
+ if (i === (n - 1)) {
+ cells.push(i, n, i + n);
+ faceUv.push(1, 0, 0, 1, 1, 1);
+ cells.push(i, 0, n);
+ faceUv.push(1, 0, 0, 0, 0, 1);
+ } else {
+ cells.push(i + n, i, i + n + 1);
+ faceUv.push(1, 1, 1, 0, 0, 1);
+ cells.push(i, i + 1, i + n + 1);
+ faceUv.push(1, 0, 0, 0, 0, 1);
+ }
+ }
+ }
+ points = [];
+ return {
+ positions,
+ faceUv,
+ positionsIndex: cells
+ };
+}
+
+export function extrudePolygonLine(points, extrude) {
+ // height += Math.random() * 100; // 解决 depth
+ const p1 = points[0][0];
+ const p2 = points[0][points[0].length - 1];
+ if (p1[0] === p2[0] && p1[1] === p2[1]) {
+ points[0] = points[0].slice(0, points[0].length - 1);
+ }
+
+ const n = points[0].length;
+ const flattengeo = earcut.flatten(points);
+ const positions = [];
+ let cells = [];
+ const triangles = earcut(flattengeo.vertices, flattengeo.holes, flattengeo.dimensions);
+ cells = triangles.map(e => e);
+ extrude === 0 ? flat() : full();
+
+ function flat() {
+ points[0].forEach(p => { positions.push([ p[0], p[1], 0 ]); }); // top
+ }
+ function full() {
+ points[0].forEach(p => { positions.push([ p[0], p[1], 1 ]); }); // top
+ points[0].forEach(p => { positions.push([ p[0], p[1], 0 ]); }); // bottom
+ for (let i = 0; i < n; i++) {
+ if (i === (n - 1)) {
+ cells.push(i + n, n, i);
+ cells.push(0, i, n);
+ } else {
+ cells.push(i + n, i + n + 1, i);
+ cells.push(i + 1, i, i + n + 1);
+ }
+ }
+ }
+ points = [];
+ return {
+ positions,
+ positionsIndex: cells
+ };
+}
diff --git a/src/geom/extrude.js b/src/geom/extrude.js
index 85fc86cad9..452c82f0ee 100644
--- a/src/geom/extrude.js
+++ b/src/geom/extrude.js
@@ -105,3 +105,38 @@ export function extrudePolygonLine(points, extrude) {
positionsIndex: cells
};
}
+
+export function fillPolygon(points) {
+ const flattengeo = earcut.flatten(points);
+ const triangles = earcut(flattengeo.vertices, flattengeo.holes, flattengeo.dimensions);
+ return {
+ positions: flattengeo.vertices,
+ indexArray: triangles
+ };
+}
+
+export function extrude_Polygon(points) {
+ const p1 = points[0][0];
+ const p2 = points[0][points[0].length - 1];
+ if (p1[0] === p2[0] && p1[1] === p2[1]) {
+ points[0] = points[0].slice(0, points[0].length - 1);
+ }
+ const n = points[0].length;
+ const flattengeo = earcut.flatten(points);
+ const positions = [];
+ const indexArray = [];
+ positions.push(...flattengeo.vertices);
+ const triangles = earcut(flattengeo.vertices, flattengeo.holes, flattengeo.dimensions);
+ indexArray.push(...triangles);
+ for (let i = 0; i < n; i++) {
+ const prePoint = flattengeo.vertices.slice(i * 3, i * 3 + 3);
+ const nextPoint = flattengeo.vertices.slice(i * 3 + 3, i * 3 + 6);
+ const indexOffset = positions.length;
+ positions.push(prePoint[0], prePoint[1], 1, nextPoint[0], nextPoint[1], 1, prePoint[0], prePoint[1], 0, nextPoint[0], nextPoint[1], 0);
+ indexArray.push([ 1, 2, 0, 3, 2, 1 ].map(v => { return v + indexOffset; }));
+ }
+ return {
+ positions: flattengeo.vertices,
+ indexArray: triangles
+ };
+}
diff --git a/src/geom/material/grid.js b/src/geom/material/grid.js
index 44f3985be6..938b4edb32 100644
--- a/src/geom/material/grid.js
+++ b/src/geom/material/grid.js
@@ -1,5 +1,6 @@
import Material from './material';
-import { getModule } from '../../util/shaderModule';
+import { getModule, wrapUniforms } from '../../util/shaderModule';
+import merge from '@antv/util/lib/deep-mix';
export default class GridMaterial extends Material {
getDefaultParameters() {
return {
@@ -19,9 +20,9 @@ export default class GridMaterial extends Material {
}
constructor(_uniforms, _defines, parameters) {
super(parameters);
- const { uniforms, defines } = this.getDefaultParameters();
- const { vs, fs } = getModule('grid');
- this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
+ const { defines } = this.getDefaultParameters();
+ const { vs, fs, uniforms } = getModule('grid');
+ this.uniforms = wrapUniforms(merge(uniforms, _uniforms));
this.type = 'GridMaterial';
this.defines = Object.assign(defines, _defines);
this.vertexShader = vs;
diff --git a/src/geom/shader/grid_vert.glsl b/src/geom/shader/grid_vert.glsl
index 81ae913d6a..35fba3dc04 100644
--- a/src/geom/shader/grid_vert.glsl
+++ b/src/geom/shader/grid_vert.glsl
@@ -1,5 +1,5 @@
precision highp float;
-attribute vec2 miter;
+attribute vec3 miter;
attribute vec4 a_color;
uniform float u_xOffset;
uniform float u_yOffset;
@@ -9,15 +9,27 @@ uniform float u_activeId;
uniform vec4 u_activeColor;
varying vec4 v_color;
+#pragma include "lighting"
+
void main() {
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
v_color = a_color;
v_color.a *= u_opacity;
- if(pickingId == u_activeId) {
+
+ if(pickingId == u_activeId) {
v_color = u_activeColor;
- }
+ }
float x = position.x + miter.x * u_xOffset * u_coverage;
float y = position.y + miter.y * u_yOffset * u_coverage;
- gl_Position = matModelViewProjection * vec4(x, y, position.z, 1.0);
+ float z = position.z + miter.z;
+
+ #ifdef LIGHTING
+ vec3 viewDir = normalize(cameraPosition - vec3(x, y, z));
+ v_color.rgb *= calc_lighting(vec3(x, y, z), normal, viewDir);
+ #endif
+
+
+
+ gl_Position = matModelViewProjection * vec4(x, y, z, 1.0);
worldId = id_toPickColor(pickingId);
}
\ No newline at end of file
diff --git a/src/layer/render/heatmap/gird.js b/src/layer/render/heatmap/gird.js
index 04b31b40bf..865b995ffe 100644
--- a/src/layer/render/heatmap/gird.js
+++ b/src/layer/render/heatmap/gird.js
@@ -1,24 +1,37 @@
import * as THREE from '../../../core/three';
-import gridBuffer from '../../../geom/buffer/heatmap/grid';
import GridMaterial from '../../../geom/material/grid';
-export default function DrawGrid(layerdata, layer, source) {
- const { opacity, coverage } = layer.get('styleOptions');
+import { getBuffer } from '../../../geom/buffer/';
+import { generateLightingUniforms } from '../../../util/shaderModule';
+export default function DrawGrid(layerData, layer, source) {
+ const { opacity, coverage, lights } = layer.get('styleOptions');
const activeOption = layer.get('activedOptions');
const { xOffset, yOffset } = source.data;
- const attributes = new gridBuffer(layerdata);
+
+ // const attributes = new gridBuffer(layerdata);
+ const geometryBuffer = getBuffer(layer.type, layer.shapeType);
+ const buffer = new geometryBuffer({
+ layerData,
+ shapeType: layer.shapeType
+ });
+ const { attributes, indexArray } = buffer;
const geometry = new THREE.BufferGeometry();
- geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
- geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
+ geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));
+ geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
+ geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miters, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
+ geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
+
const material = new GridMaterial({
u_opacity: opacity,
u_xOffset: xOffset,
u_yOffset: yOffset,
u_coverage: coverage,
- u_activeColor: activeOption.fill
+ u_activeColor: activeOption.fill,
+ ...generateLightingUniforms(lights)
}, {
- SHAPE: false
+ SHAPE: false,
+ LIGHTING: layer.shapeType !== 'square'
});
const gridMesh = new THREE.Mesh(geometry, material);
return gridMesh;
diff --git a/src/layer/render/index.js b/src/layer/render/index.js
index 79158b56d9..53297cb3a8 100644
--- a/src/layer/render/index.js
+++ b/src/layer/render/index.js
@@ -38,7 +38,8 @@ import DrawGrid from './heatmap/gird';
import DrawHeatmap from './heatmap/heatmap';
import DrawHexagon from './heatmap/hexagon';
-registerRender('heatmap', 'grid', DrawGrid);
+registerRender('heatmap', 'square', DrawGrid);
+registerRender('heatmap', 'squareColumn', DrawGrid);
registerRender('heatmap', 'heatmap', DrawHeatmap);
registerRender('heatmap', 'hexagon', DrawHexagon);
diff --git a/src/layer/render/polygon/drawLine.js b/src/layer/render/polygon/drawLine.js
index 7763282689..908ec65e0d 100644
--- a/src/layer/render/polygon/drawLine.js
+++ b/src/layer/render/polygon/drawLine.js
@@ -1,5 +1,5 @@
import * as THREE from '../../../core/three';
-import PolygonBuffer from '../../../geom/buffer/polygon';
+import { getBuffer } from '../../../geom/buffer/';
import { LineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawPolygonLine(layerData, layer, buffer) {
const style = layer.get('styleOptions');
@@ -9,13 +9,14 @@ export default function DrawPolygonLine(layerData, layer, buffer) {
activeColor: activeOption.fill
};
const { opacity } = config;
- let { attributes, indexArray } = buffer;
- if (!attributes) {
- attributes = new PolygonBuffer({
- shape: layer.shape,
+ if (!buffer) {
+ const geometryBuffer = getBuffer(layer.type, layer.shape);
+ buffer = new geometryBuffer({
layerData
- }).attributes;
+ });
+
}
+ const { attributes, indexArray } = buffer;
const geometry = new THREE.BufferGeometry();
if (indexArray) {
geometry.setIndex(new THREE.Uint32BufferAttribute(indexArray, 1));