diff --git a/demos/hexgon.html b/demos/hexgon.html
index 3cc2da6a73..bbfd0379d6 100644
--- a/demos/hexgon.html
+++ b/demos/hexgon.html
@@ -25,7 +25,7 @@ const scene = new L7.Scene({
mapStyle: 'dark', // 样式URL
center: [120.132624,30.281774],
pitch: 0,
- zoom: 10
+ zoom: 7
});
scene.on('loaded', () => {
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
@@ -53,16 +53,19 @@ scene.on('loaded', () => {
},
{
type: 'hexagon',
- size: 6000,
+ size: 10000,
field:'v',
method:'sum'
}
]
})
.active(true)
- .shape('hexagon')
+ .size('count',(value)=>{
+ return value * 1000;
+ })
+ .shape('square')
.style({
- coverage: 0.9,
+ coverage: 0.8,
angle: 0,
})
.color('count', ["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"])
diff --git a/src/geom/buffer/heatmap/hexagon.js b/src/geom/buffer/heatmap/hexagon.js
index 68cb3555ff..2c30133ec1 100644
--- a/src/geom/buffer/heatmap/hexagon.js
+++ b/src/geom/buffer/heatmap/hexagon.js
@@ -1,31 +1,61 @@
-import { fill, extrude } from '../../shape/polygon';
-export default function hexagonBuffer(layerData) {
- const attribute = {
- vertices: [],
- miter: [],
- colors: [],
- pickingIds: []
- };
- const a = Math.cos(Math.PI / 6);
- const points = [
- [ 0, -1, 0 ],
- [ -a, -0.5, 0 ],
- [ -a, 0.5, 0 ],
- [ 0, 1, 0 ],
- [ a, 0.5, 0 ],
- [ a, -0.5, 0 ],
- [ 0, -1, 0 ]
- ];
- // const hexgonPoints = polygonPath(6);
- const hexgonFill = fill([ points ]);
- const { positionsIndex, positions } = hexgonFill;
- layerData.forEach(element => {
- positionsIndex.forEach(pointIndex => {
- attribute.vertices.push(...element.coordinates);
- attribute.miter.push(positions[pointIndex][0], positions[pointIndex][1]);
- attribute.pickingIds.push(element.id);
- attribute.colors.push(...element.color);
+import BufferBase from '../buffer';
+import Global from '../../../global';
+import { fillPolygon, extrude_Polygon } from '../../extrude';
+import { polygonPath } from '../../shape/path';
+
+export default class Shape_3D extends BufferBase {
+ _buildFeatures() {
+ const layerData = this.get('layerData');
+ this._offset = 0;
+
+ layerData.forEach(feature => {
+ this._calculateFill(feature);
});
- });
- return attribute;
+ }
+ _initAttributes() {
+ super._initAttributes();
+ this.attributes.miters = new Float32Array(this.verticesCount * 3);
+ this.attributes.normals = new Float32Array(this.verticesCount * 3);
+ }
+ _calculateFeatures() {
+ this._calcultateGeometry();
+ const layerData = this.get('layerData');
+ const { positions, indexArray } = this.instanceGeometry;
+ const numFeature = layerData.length;
+ this.verticesCount = positions.length * numFeature / 3;
+ this.indexCount = indexArray.length * numFeature;
+ }
+ _calcultateGeometry() {
+ const shape = this.get('shapeType');
+ const hexgonFill = this.getShapeFunction(shape)([ this._getPoints(6) ]);
+ this.instanceGeometry = hexgonFill;
+ }
+ _calculateFill(feature) {
+
+ feature.bufferInfo = { verticesOffset: this._offset };
+ const { coordinates } = feature;
+ const numPoint = this.instanceGeometry.positions.length / 3;
+ this._encodeArray(feature, numPoint);
+ this.attributes.miters.set(this.instanceGeometry.positions, this._offset * 3);
+ const indexArray = this.instanceGeometry.indexArray.map(v => { return v + this._offset; });
+ this.indexArray.set(indexArray, this._offset);
+ if (this.instanceGeometry.normals) {
+ this.attributes.normals.set(this.instanceGeometry.normals, this._offset * 3);
+ }
+ const position = [];
+ for (let i = 0; i < numPoint; i++) {
+ position.push(...coordinates);
+ }
+ this.attributes.positions.set(position, this._offset * 3);
+ this._offset += numPoint;
+ }
+ _getPoints(num) {
+ return polygonPath(num, 1);
+ }
+ getShapeFunction(shape) {
+ const { pointShape } = Global;
+ if (pointShape['3d'].indexOf(shape) !== -1) return extrude_Polygon;
+ return fillPolygon;
+
+ }
}
diff --git a/src/geom/buffer/heatmap/hexagon_3d.js b/src/geom/buffer/heatmap/hexagon_3d.js
index ccbf30cbc0..aec1e3936e 100644
--- a/src/geom/buffer/heatmap/hexagon_3d.js
+++ b/src/geom/buffer/heatmap/hexagon_3d.js
@@ -1,33 +1,40 @@
+/**
+ * instantcebufferGeometry的组装方式
+ */
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 {
+import Global from '../../../global';
+import * as shapePath from '../../shape/path';
+
+export default class Hexagon3D extends BufferBase {
_buildFeatures() {
const layerData = this.get('layerData');
this._offset = 0;
layerData.forEach(feature => {
-
+ this._calculateFill(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 shape = this.get('shapeType');
+ const hexgonFill = this.getShape(shape);
const layerData = this.get('layerData');
- this.verticesCount = hexgonFill.positions.length / 3 * layerData.length;
- this.indexCount = hexgonFill.indexArray * layerData.length;
- this.featureBuffer = hexgonFill;
+ this.verticesCount = layerData.length;
+ this.indexCount = 0;
+ this.instanceGeometry = hexgonFill;
}
- _calculatefill(feature) {
- // this.
+ _calculateFill(feature) {
+
+ feature.bufferInfo = { verticesOffset: this._offset };
+ const { coordinates } = feature;
+ this._encodeArray(feature, 1);
+ this.attributes.positions.set(coordinates, this._offset * 3);
+ this._offset++;
}
- _getPoints(num) {
- return polygonPath(num);
+ getShape(shape) {
+ const { pointShape } = Global;
+ if (pointShape['3d'].indexOf(shape) !== -1) return extrude_Polygon([ shapePath[shape]() ]);
+ if (pointShape['2d'].indexOf(shape) !== -1) return fillPolygon([ shapePath[shape]() ]);
+ return fillPolygon([ shapePath[shape]() ]);
}
}
diff --git a/src/geom/buffer/index.js b/src/geom/buffer/index.js
index 55c3ff3090..fc4e009e51 100644
--- a/src/geom/buffer/index.js
+++ b/src/geom/buffer/index.js
@@ -12,6 +12,10 @@ import ArcLineBuffer from './line/arcline';
// heatmap
import Grid3D from './heatmap/grid_3d';
+import Hexagon3D from './heatmap/hexagon_3d';
+
+// 3D Shape
+import Shape_3D from './heatmap/hexagon';
import { registerBuffer, getBuffer } from './factory';
@@ -26,7 +30,11 @@ registerBuffer('line', 'greatCircle', ArcLineBuffer);
// heatmap
-registerBuffer('heatmap', 'square', Grid3D);
-registerBuffer('heatmap', 'squareColumn', Grid3D);
+// registerBuffer('heatmap', 'square', Grid3D);
+// registerBuffer('heatmap', 'squareColumn', Grid3D);
+registerBuffer('heatmap', 'shape', Hexagon3D);
+// 3D Shape
+
+registerBuffer('shape', 'extrude', Shape_3D);
export { getBuffer };
diff --git a/src/geom/extrude.js b/src/geom/extrude.js
index 452c82f0ee..09698185dc 100644
--- a/src/geom/extrude.js
+++ b/src/geom/extrude.js
@@ -1,5 +1,5 @@
import earcut from 'earcut';
-
+import * as THREE from '../core/three';
/**
* 计算是否拉伸
* @param {Array} points 点坐标数组
@@ -125,18 +125,45 @@ export function extrude_Polygon(points) {
const flattengeo = earcut.flatten(points);
const positions = [];
const indexArray = [];
+ const normals = [];
+ // 设置顶部z值
+ for (let j = 0; j < flattengeo.vertices.length / 3; j++) {
+ flattengeo.vertices[j * 3 + 2] = 1;
+ normals.push(0, 0, 1);
+ }
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;
+ let nextPoint = flattengeo.vertices.slice(i * 3 + 3, i * 3 + 6);
+ nextPoint.length === 0 && (nextPoint = flattengeo.vertices.slice(0, 3));
+ const indexOffset = positions.length / 3;
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; }));
+ const normal = computeNormal([ nextPoint[0], nextPoint[1], 1 ], [ prePoint[0], prePoint[1], 0 ], [ prePoint[0], prePoint[1], 1 ]);
+ normals.push(...normal, ...normal, ...normal, ...normal);
+ indexArray.push(...[ 1, 2, 0, 3, 2, 1 ].map(v => { return v + indexOffset; }));
}
return {
- positions: flattengeo.vertices,
- indexArray: triangles
+ positions,
+ indexArray,
+ normals
};
}
+
+function computeNormal(v1, v2, v3) {
+ const pA = new THREE.Vector3();
+ const pB = new THREE.Vector3();
+ const pC = new THREE.Vector3();
+ const cb = new THREE.Vector3();
+ const ab = new THREE.Vector3();
+ pA.set(...v1);
+ pB.set(...v2);
+ pC.set(...v3);
+ cb.subVectors(pC, pB);
+ ab.subVectors(pA, pB);
+ cb.cross(ab);
+ cb.normalize();
+ const { x, y, z } = cb;
+ return [ x, y, z ];
+};
diff --git a/src/geom/material/hexagon.js b/src/geom/material/hexagon.js
index ffb1739d1f..fc2bc30071 100644
--- a/src/geom/material/hexagon.js
+++ b/src/geom/material/hexagon.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 hexagonMaterial extends Material {
getDefaultParameters() {
return {
@@ -19,9 +20,9 @@ export default class hexagonMaterial extends Material {
}
constructor(_uniforms, _defines, parameters) {
super(parameters);
- const { uniforms, defines } = this.getDefaultParameters();
- const { vs, fs } = getModule('hexagon');
- this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
+ const { defines } = this.getDefaultParameters();
+ const { vs, fs, uniforms } = getModule('hexagon');
+ this.uniforms = wrapUniforms(merge(uniforms, _uniforms));
this.type = 'hexagonMaterial';
this.defines = Object.assign(defines, _defines);
this.vertexShader = vs;
diff --git a/src/geom/shader/hexagon_frag.glsl b/src/geom/shader/hexagon_frag.glsl
index 77c7d120d0..6fd41421b4 100644
--- a/src/geom/shader/hexagon_frag.glsl
+++ b/src/geom/shader/hexagon_frag.glsl
@@ -1,7 +1,5 @@
precision highp float;
- uniform float u_opacity;
varying vec4 v_color;
void main() {
- vec4 color = v_color;
- gl_FragColor = color;
+ gl_FragColor = v_color;
}
\ No newline at end of file
diff --git a/src/geom/shader/hexagon_vert.glsl b/src/geom/shader/hexagon_vert.glsl
index 1bd95bbbdf..3940da986e 100644
--- a/src/geom/shader/hexagon_vert.glsl
+++ b/src/geom/shader/hexagon_vert.glsl
@@ -1,26 +1,41 @@
precision highp float;
-attribute vec2 miter;
+// attribute vec2 miter;
+attribute vec3 miter;
+attribute vec3 a_shape;
+attribute float a_size;
attribute vec4 a_color;
uniform float u_radius;
uniform float u_coverage;
uniform float u_opacity;
uniform float u_angle;
+
uniform float u_activeId;
uniform vec4 u_activeColor;
varying vec4 v_color;
+#pragma include "lighting"
+
void main() {
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle));
v_color = a_color;
- v_color.a *= u_opacity;
+ v_color.a *= u_opacity;
if(pickingId == u_activeId) {
v_color = u_activeColor;
}
- vec2 offset =vec2(rotationMatrix * miter * u_radius * u_coverage );
+ vec2 offset =vec2(rotationMatrix * miter.xy * u_radius * u_coverage );
+ // vec2 offset =vec2(rotationMatrix * a_shape.xy * u_radius * u_coverage );
float x = position.x + offset.x;
float y = position.y + offset.y;
- gl_Position = matModelViewProjection * vec4(x, y, position.z, 1.0);
+ // float z = a_shape.z * a_size;
+ float z = miter.z * a_size;
+
+ #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/geom/shape/path.js b/src/geom/shape/path.js
index 82bd51d68e..4eaf321e18 100644
--- a/src/geom/shape/path.js
+++ b/src/geom/shape/path.js
@@ -33,7 +33,7 @@ export function polygonPath(pointCount, start = 0) {
const step = Math.PI * 2 / pointCount;
const line = [];
for (let i = 0; i < pointCount; i++) {
- line.push(step * i - start * Math.PI / 12);
+ line.push(step * i + start * Math.PI / 12);
}
const path = line.map(t => {
const x = Math.sin(t + Math.PI / 4),
diff --git a/src/layer/heatmap_layer.js b/src/layer/heatmap_layer.js
index b75c270c1f..5468e542b8 100644
--- a/src/layer/heatmap_layer.js
+++ b/src/layer/heatmap_layer.js
@@ -8,6 +8,8 @@ export default class HeatMapLayer extends Layer {
}
draw() {
this.type = 'heatmap';
- this.add(getRender('heatmap', this.shapeType || 'heatmap')(this.layerData, this, this.layerSource));
+ if (!this.shapeType) this.shapeType = 'heatmap';
+ const renderType = this.shapeType === 'heatmap' ? 'heatmap' : 'shape';
+ this.add(getRender('heatmap', renderType)(this.layerData, this, this.layerSource));
}
}
diff --git a/src/layer/render/heatmap/hexagon.js b/src/layer/render/heatmap/hexagon.js
index 8c2c42ee14..3fa4c03285 100644
--- a/src/layer/render/heatmap/hexagon.js
+++ b/src/layer/render/heatmap/hexagon.js
@@ -1,27 +1,41 @@
import * as THREE from '../../../core/three';
-import hexagonBuffer from '../../../geom/buffer/heatmap/hexagon';
import GridMaterial from '../../../geom/material/hexagon';
-export default function DrawHexagon(layerdata, layer, source) {
+import { getBuffer } from '../../../geom/buffer/';
+import { generateLightingUniforms } from '../../../util/shaderModule';
+export default function DrawHexagon(layerData, layer, source) {
const style = layer.get('styleOptions');
const { fill } = layer.get('activedOptions');
const { radius } = source.data;
- const attributes = new hexagonBuffer(layerdata);
- const { opacity, angle, coverage } = style;
- const geometry = new THREE.BufferGeometry();
- geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
- geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
- geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
- geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
+ const { opacity, angle = 0, coverage, lights } = style;
+ const geometryBuffer = getBuffer(layer.type, 'shape');
+ const buffer = new geometryBuffer({
+ layerData,
+ shapeType: layer.shapeType
+ });
+ const { attributes, instanceGeometry } = buffer;
+ const instancedGeometry = new THREE.InstancedBufferGeometry();
+ instancedGeometry.setIndex(instanceGeometry.indexArray);
+ instancedGeometry.addAttribute('miter', new THREE.Float32BufferAttribute(instanceGeometry.positions, 3));
+ if (instanceGeometry.normals) {
+ instancedGeometry.addAttribute('normal', new THREE.Float32BufferAttribute(instanceGeometry.normals, 3));
+ }
+ instancedGeometry.addAttribute('position', new THREE.InstancedBufferAttribute(new Float32Array(attributes.positions), 3));
+ instancedGeometry.addAttribute('a_color', new THREE.InstancedBufferAttribute(new Float32Array(attributes.colors), 4));
+ instancedGeometry.addAttribute('pickingId', new THREE.InstancedBufferAttribute(new Float32Array(attributes.pickingIds), 1));
+ instancedGeometry.addAttribute('a_size', new THREE.InstancedBufferAttribute(new Float32Array(attributes.sizes), 1));
+
const material = new GridMaterial({
u_opacity: opacity,
u_radius: radius,
u_angle: angle / 180 * Math.PI,
u_coverage: coverage,
- u_activeColor: fill
+ u_activeColor: fill,
+ ...generateLightingUniforms(lights)
}, {
- SHAPE: false
+ SHAPE: false,
+ LIGHTING: !!instanceGeometry.normals
});
- const hexgonMesh = new THREE.Mesh(geometry, material);
+ const hexgonMesh = new THREE.Mesh(instancedGeometry, material);
return hexgonMesh;
}
diff --git a/src/layer/render/index.js b/src/layer/render/index.js
index 53297cb3a8..4272da7ab9 100644
--- a/src/layer/render/index.js
+++ b/src/layer/render/index.js
@@ -3,6 +3,7 @@ import { registerRender, getRender } from './factory';
import DrawFill from './polygon/drawFill';
import DrawLine from './polygon/drawLine';
import DrawAnimate from './polygon/drawAnimate';
+import Draw3DShape from './point/draw_3d_shape';
registerRender('polygon', 'fill', DrawFill);
registerRender('polygon', 'extrude', DrawFill);
@@ -31,6 +32,7 @@ registerRender('point', 'normal', DrawPointNormal);
registerRender('point', 'stroke', DrawPointStroke);
registerRender('point', 'text', DrawPointText);
registerRender('point', 'circle', DrawPointCircle);
+registerRender('point', 'shape', Draw3DShape);
// heatmap
@@ -41,7 +43,7 @@ import DrawHexagon from './heatmap/hexagon';
registerRender('heatmap', 'square', DrawGrid);
registerRender('heatmap', 'squareColumn', DrawGrid);
registerRender('heatmap', 'heatmap', DrawHeatmap);
-registerRender('heatmap', 'hexagon', DrawHexagon);
+registerRender('heatmap', 'shape', DrawHexagon);
// image
diff --git a/src/layer/render/point/draw_3d_shape.js b/src/layer/render/point/draw_3d_shape.js
new file mode 100644
index 0000000000..422e6e520d
--- /dev/null
+++ b/src/layer/render/point/draw_3d_shape.js
@@ -0,0 +1,41 @@
+import * as THREE from '../../../core/three';
+import GridMaterial from '../../../geom/material/hexagon';
+import { getBuffer } from '../../../geom/buffer/';
+import { generateLightingUniforms } from '../../../util/shaderModule';
+export default function Draw3DShape(layerData, layer, source) {
+ const style = layer.get('styleOptions');
+ const { fill } = layer.get('activedOptions');
+ const { radius } = source.data;
+ // const attributes = new hexagonBuffer(layerdata);
+ const { opacity, angle, coverage, lights } = style;
+ const geometryBuffer = getBuffer('shape', 'extrude');
+ const buffer = new geometryBuffer({
+ layerData,
+ shapeType: layer.shapeType
+ });
+ const { attributes, indexArray } = buffer;
+ const geometry = new THREE.BufferGeometry();
+ 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));
+ geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
+
+
+ const material = new GridMaterial({
+ u_opacity: opacity,
+ u_radius: radius,
+ u_angle: angle / 180 * Math.PI,
+ u_coverage: coverage,
+ u_activeColor: fill,
+ ...generateLightingUniforms(lights)
+ }, {
+ SHAPE: false,
+ LIGHTING: true
+ });
+ const hexgonMesh = new THREE.Mesh(geometry, material);
+ return hexgonMesh;
+}
+
diff --git a/src/source/transform/grid.js b/src/source/transform/grid.js
index 4098f15e15..9b1067566a 100644
--- a/src/source/transform/grid.js
+++ b/src/source/transform/grid.js
@@ -13,6 +13,7 @@ export function aggregatorToGrid(data, option) {
return {
yOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
xOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
+ radius: gridOffset.xOffset / 360 * (256 << 20) / 2,
dataArray: layerData
};
}