diff --git a/demos/07_city.html b/demos/07_city.html
index 032dfe9bcc..0b5acd860f 100644
--- a/demos/07_city.html
+++ b/demos/07_city.html
@@ -32,35 +32,35 @@ const scene = new L7.Scene({
});
window.scene = scene;
scene.on('loaded', () => {
- $.get('https://gw.alipayobjects.com/os/rmsportal/XHMbjQwrSrajvLLvMPbK.json', data => {
- scene.PolygonLayer({
- zIndex: 0
- })
- .source(data)
- .shape('fill')
- .active({fill:'blue'})
- .color('rgb(79,174,234)')
- .render();
- });
- $.get('https://gw.alipayobjects.com/os/rmsportal/VifgwJEyBIXnDrjCwWdK.json', data => {
- scene.PolygonLayer({
- zIndex: 0
- })
- .source(data)
- .shape('fill')
- .color('rgb(156,194,116)')
- .render();
- });
- $.get('https://gw.alipayobjects.com/os/rmsportal/ZseLNWMOPGrgqQYfvtli.json', data => {
- scene.LineLayer({
- zIndex: 2
- })
- .source(data)
- .shape('line')
- .size([3,0])
- .color('rgb(79,174,234)')
- .render();
- });
+ // $.get('https://gw.alipayobjects.com/os/rmsportal/XHMbjQwrSrajvLLvMPbK.json', data => {
+ // scene.PolygonLayer({
+ // zIndex: 0
+ // })
+ // .source(data)
+ // .shape('fill')
+ // .active({fill:'blue'})
+ // .color('rgb(79,174,234)')
+ // .render();
+ // });
+ // $.get('https://gw.alipayobjects.com/os/rmsportal/VifgwJEyBIXnDrjCwWdK.json', data => {
+ // scene.PolygonLayer({
+ // zIndex: 0
+ // })
+ // .source(data)
+ // .shape('fill')
+ // .color('rgb(156,194,116)')
+ // .render();
+ // });
+ // $.get('https://gw.alipayobjects.com/os/rmsportal/ZseLNWMOPGrgqQYfvtli.json', data => {
+ // scene.LineLayer({
+ // zIndex: 2
+ // })
+ // .source(data)
+ // .shape('line')
+ // .size([3,0])
+ // .color('rgb(79,174,234)')
+ // .render();
+ // });
$.get('https://gw.alipayobjects.com/os/rmsportal/ggFwDClGjjvpSMBIrcEx.json', data => {
citylayer = scene.PolygonLayer({
@@ -69,6 +69,24 @@ scene.on('loaded', () => {
.source(data)
.shape('extrude')
.active({fill:'red'})
+ .style({
+ lights: [
+ {
+ type: 'directional',
+ direction: [ 1, 10.5, 12 ],
+ ambient: [ 0.2, 0.2, 0.2 ],
+ diffuse: 'red',
+ specular: [ 0.1, 0.1, 0.1 ]
+ },
+ {
+ type: 'directional',
+ direction: [ 1, -10.5, 12 ],
+ ambient: [ 0.2, 0.2, 0.2 ],
+ diffuse: 'green',
+ specular: [ 0.1, 0.1, 0.1 ]
+ },
+ ]
+ })
.size('floor',[10,2000])
.color('rgba(242,246,250,0.96)')
.render();
diff --git a/demos/taxi.html b/demos/taxi.html
index dc2edc621e..8b89708488 100644
--- a/demos/taxi.html
+++ b/demos/taxi.html
@@ -55,7 +55,23 @@ scene.on('loaded', () => {
baseColor:'rgb(16,16,16)',
windowColor:'rgb(30,60,89)',
//brightColor:'rgb(155,217,255)'
- brightColor:'rgb(255,176,38)'
+ brightColor:'rgb(255,176,38)',
+ lights: [
+ {
+ type: 'directional',
+ direction: [ 1, 10.5, 12 ],
+ ambient: [ 0.2, 0.2, 0.2 ],
+ diffuse: 'red',
+ specular: [ 0.1, 0.1, 0.1 ]
+ },
+ {
+ type: 'directional',
+ direction: [ 1, -10.5, 12 ],
+ ambient: [ 0.2, 0.2, 0.2 ],
+ diffuse: 'green',
+ specular: [ 0.1, 0.1, 0.1 ]
+ },
+ ]
})
.render();
diff --git a/src/geom/material/polygonMaterial.js b/src/geom/material/polygonMaterial.js
index 5de4c72acc..d77069e5fa 100644
--- a/src/geom/material/polygonMaterial.js
+++ b/src/geom/material/polygonMaterial.js
@@ -1,33 +1,15 @@
import Material from './material';
-import { getModule } from '../../util/shaderModule';
-export default class PolygonMaterial extends Material {
- getDefaultParameters() {
- return {
- uniforms: {
- u_opacity: { value: 1.0 },
- u_time: { value: 0 },
- u_zoom: { value: 0 },
- u_baseColor: { value: [ 1.0, 0, 0, 1.0 ] },
- u_brightColor: { value: [ 1.0, 0, 0, 1.0 ] },
- u_windowColor: { value: [ 1.0, 0, 0, 1.0 ] },
- u_near: { value: 0.0 },
- u_far: { value: 1.0 },
- u_activeId: { value: 0 },
- u_activeColor: { value: [ 1.0, 0, 0, 1.0 ] }
- },
- defines: {
+import { getModule, wrapUniforms } from '../../util/shaderModule';
+import merge from '@antv/util/lib/deep-mix';
- }
- };
- }
+export default class PolygonMaterial extends Material {
constructor(_uniforms, _defines, parameters) {
super(parameters);
- const { uniforms, defines } = this.getDefaultParameters();
- this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
+ const { vs, fs, uniforms } = getModule('polygon');
+ this.uniforms = wrapUniforms(merge(uniforms, _uniforms));
this.type = 'PolygonMaterial';
- this.defines = Object.assign(defines, _defines);
+ this.defines = _defines;
- const { vs, fs } = getModule('polygon');
this.vertexShader = vs;
this.fragmentShader = fs;
this.transparent = true;
diff --git a/src/geom/shader/index.js b/src/geom/shader/index.js
index 2b17a38656..2943ef4c5b 100644
--- a/src/geom/shader/index.js
+++ b/src/geom/shader/index.js
@@ -52,12 +52,14 @@ import common from './common.glsl';
import { registerModule } from '../../util/shaderModule';
import pick_color from './shaderChunks/pick_color.glsl';
import decode from './shaderChunks/decode.glsl';
+import lighting from './shaderChunks/lighting.glsl';
import sdf_2d from './shaderChunks/sdf_2d.glsl';
export function compileBuiltinModules() {
registerModule('point', { vs: point_vert, fs: point_frag });
registerModule('common', { vs: common, fs: common });
registerModule('decode', { vs: decode, fs: '' });
+ registerModule('lighting', { vs: lighting, fs: '' });
registerModule('sdf_2d', { vs: '', fs: sdf_2d });
registerModule('pick_color', { vs: pick_color, fs: pick_color });
registerModule('circle', { vs: circle_vert, fs: circle_frag });
diff --git a/src/geom/shader/polygon_frag.glsl b/src/geom/shader/polygon_frag.glsl
index 545721cd04..8f1780ce9a 100644
--- a/src/geom/shader/polygon_frag.glsl
+++ b/src/geom/shader/polygon_frag.glsl
@@ -1,16 +1,18 @@
precision highp float;
-uniform sampler2D u_texture;
-uniform vec4 u_baseColor;
-uniform vec4 u_brightColor;
-uniform vec4 u_windowColor;
-uniform float u_zoom;
-uniform float u_time;
-uniform float u_near;
-uniform float u_far;
+
+uniform vec4 u_baseColor : [ 1.0, 0, 0, 1.0 ];
+uniform vec4 u_brightColor : [ 1.0, 0, 0, 1.0 ];
+uniform vec4 u_windowColor : [ 1.0, 0, 0, 1.0 ];
+uniform float u_zoom : 0;
+uniform float u_time : 0;
+uniform float u_near : 0;
+uniform float u_far : 1;
+
+#ifdef ANIMATE
varying vec2 v_texCoord;
-varying vec4 v_color;
-varying float v_lightWeight;
-varying float v_size;
+#endif
+
+varying vec4 v_color;
varying vec4 worldId;
vec3 getWindowColor(float n, float hot, vec3 brightColor, vec3 darkColor) {
@@ -41,12 +43,6 @@ float sdRect(vec2 p, vec2 sz) {
float inside = min(max(d.x, d.y), 0.);
return outside + inside;
}
-float circle(in vec2 _st, in float _radius){
- vec2 dist = _st-vec2(0.5);
- return 1.-smoothstep(_radius-(_radius*0.01),
- _radius+(_radius*0.01),
- dot(dist,dist)*4.0);
-}
void main() {
if(v_color.w == 0.0) {
@@ -104,19 +100,13 @@ void main() {
// if(head ==1.0) { // 顶部亮线
// color = brightColor;
// }
- color = color * v_lightWeight;
+ color = color * v_color.rgb;
vec3 foggedColor = fog(color,fogColor,depth);
gl_FragColor = vec4(foggedColor,1.0);
}
#else
- // #ifdef SHAPE
- // vec2 st = gl_FragCoord.xy / v_size ;
- // vec3 color = vec3(circle(st,0.5));
- // gl_FragColor = vec4(color, 1.0 );
- // return;
- // #endif
gl_FragColor = vec4(v_color.xyz , v_color.w);
#endif
diff --git a/src/geom/shader/polygon_vert.glsl b/src/geom/shader/polygon_vert.glsl
index 815244fb97..ad811a1c7b 100644
--- a/src/geom/shader/polygon_vert.glsl
+++ b/src/geom/shader/polygon_vert.glsl
@@ -1,61 +1,50 @@
precision highp float;
-#define ambientRatio 0.5
-#define diffuseRatio 0.4
-#define specularRatio 0.1
-attribute vec4 a_color;
-attribute vec2 faceUv;
-attribute vec3 a_shape;
-attribute vec3 a_size;
-uniform float u_zoom;
-uniform float u_opacity;
-varying vec2 v_texCoord;
-varying vec4 v_color;
-varying float v_lightWeight;
-varying float v_size;
-uniform float u_activeId;
-uniform vec4 u_activeColor;
-void main() {
- float scale = pow(2.0,(20.0 - u_zoom));
- mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
- worldId = id_toPickColor(pickingId);
- vec3 newposition = position;
- // newposition.x -= 128.0;
- #ifdef SHAPE
- newposition =position + a_size * scale* a_shape + vec3(0., a_size.y * scale / 4., 0.);
- #endif
- v_texCoord = faceUv;
- if(normal == vec3(0.,0.,1.)){
- v_color = a_color;
- v_color.a *= u_opacity;
- if(pickingId == u_activeId) {
- v_color = u_activeColor;
- }
- v_size = a_size.x * scale;
- gl_Position = matModelViewProjection * vec4(newposition, 1.0);
- return;
- }
-
- vec3 worldPos = vec3(vec4(newposition,1.0) * modelMatrix);
- vec3 worldNormal = vec3(vec4(normal,1.0) * modelMatrix);
- // //cal light weight
- vec3 viewDir = normalize(cameraPosition - worldPos);
- //vec3 lightDir = normalize(vec3(1, -10.5, 12));
- vec3 lightDir = normalize(vec3(0.,-10.,1.));
- vec3 halfDir = normalize(viewDir+lightDir);
- // //lambert
- float lambert = dot(worldNormal, lightDir);
- //specular
- float specular = pow( max(0.0, dot(worldNormal, halfDir)), 32.0);
- //sum to light weight
- float lightWeight = ambientRatio + diffuseRatio * lambert + specularRatio * specular;
- v_texCoord = faceUv;
- v_lightWeight = lightWeight;
-
- v_color =vec4(a_color.rgb*lightWeight, a_color.w);
- if(pickingId == u_activeId) {
- v_color = u_activeColor;
- }
- gl_Position = matModelViewProjection * vec4(newposition, 1.0);
-
+attribute vec4 a_color;
+
+#ifdef SHAPE
+attribute vec3 a_size;
+attribute vec3 a_shape;
+#endif
+
+#ifdef ANIMATE
+attribute vec2 faceUv;
+varying vec2 v_texCoord;
+#endif
+
+varying vec4 v_color;
+
+uniform float u_zoom : 0;
+uniform float u_opacity : 1.0;
+uniform float u_activeId : 0;
+uniform vec4 u_activeColor : [1.0, 0.0, 0.0, 1.0];
+
+#pragma include "lighting"
+
+void main() {
+ #ifdef ANIMATE
+ v_texCoord = faceUv;
+ #endif
+ v_color = a_color;
+ v_color.a *= u_opacity;
+
+ // put offset in world space & shrink with current zoom level
+ float scale = pow(2.0,(20.0 - u_zoom));
+ vec3 offset = vec3(0.);
+ #ifdef SHAPE
+ offset = vec3(a_size * scale * a_shape);
+ #endif
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position + offset, 1.);
+
+ #ifdef LIGHTING
+ if (normal != vec3(0., 0., 1.)) {
+ vec3 viewDir = normalize(cameraPosition - position);
+ v_color.rgb *= calc_lighting(position, normal, viewDir);
+ }
+ #endif
+
+ if(pickingId == u_activeId) {
+ v_color = u_activeColor;
+ }
+ worldId = id_toPickColor(pickingId);
}
\ No newline at end of file
diff --git a/src/geom/shader/shaderChunks/lighting.glsl b/src/geom/shader/shaderChunks/lighting.glsl
new file mode 100644
index 0000000000..330e8b5525
--- /dev/null
+++ b/src/geom/shader/shaderChunks/lighting.glsl
@@ -0,0 +1,100 @@
+// Blinn-Phong model
+// apply lighting in vertex shader instead of fragment shader
+// @see https://learnopengl.com/Advanced-Lighting/Advanced-Lighting
+// TODO: support point light、spot light & sun light
+uniform float u_ambient : 1.0;
+uniform float u_diffuse : 1.0;
+uniform float u_specular : 1.0;
+uniform int u_num_of_directional_lights : 1;
+uniform int u_num_of_spot_lights : 0;
+
+#define SHININESS 32.0
+#define MAX_NUM_OF_DIRECTIONAL_LIGHTS 3
+#define MAX_NUM_OF_SPOT_LIGHTS 3
+
+#pragma include "common"
+
+struct DirectionalLight {
+ vec3 direction;
+ vec3 ambient;
+ vec3 diffuse;
+ vec3 specular;
+};
+
+struct SpotLight {
+ vec3 position;
+ vec3 direction;
+ vec3 ambient;
+ vec3 diffuse;
+ vec3 specular;
+ float constant;
+ float linear;
+ float quadratic;
+ float angle;
+ float blur;
+ float exponent;
+};
+
+uniform DirectionalLight u_directional_lights[MAX_NUM_OF_DIRECTIONAL_LIGHTS];
+uniform SpotLight u_spot_lights[MAX_NUM_OF_SPOT_LIGHTS];
+
+vec3 calc_directional_light(DirectionalLight light, vec3 normal, vec3 viewDir) {
+ vec3 lightDir = normalize(light.direction);
+ // diffuse shading
+ float diff = max(dot(normal, lightDir), 0.0);
+ // Blinn-Phong specular shading
+ vec3 halfwayDir = normalize(lightDir + viewDir);
+ float spec = pow(max(dot(normal, halfwayDir), 0.0), SHININESS);
+
+ vec3 ambient = light.ambient * u_ambient;
+ vec3 diffuse = light.diffuse * diff * u_diffuse;
+ vec3 specular = light.specular * spec * u_specular;
+
+ return ambient + diffuse + specular;
+}
+
+// vec3 calc_spot_light(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) {
+// vec3 lightDir = normalize(light.position - fragPos);
+// // diffuse shading
+// float diff = max(dot(normal, lightDir), 0.0);
+// // specular shading
+// vec3 reflectDir = reflect(-lightDir, normal);
+// float spec = pow(max(dot(viewDir, reflectDir), 0.0), SHININESS);
+// // attenuation
+// float distance = length(light.position - fragPos);
+// float attenuation = 1.0 / (light.constant + light.linear * distance +
+// light.quadratic * (distance * distance));
+
+// vec3 ambient = light.ambient * u_ambient;
+// vec3 diffuse = light.diffuse * diff * u_diffuse;
+// vec3 specular = light.specular * spec * u_specular;
+
+// float spotEffect = dot(normalize(light.direction), -lightDir);
+// float spotCosCutoff = cos(light.angle / 180.0 * PI);
+// float spotCosOuterCutoff = cos((light.angle + light.blur) / 180.0 * PI);
+// float spotCosInnerCutoff = cos((light.angle - light.blur) / 180.0 * PI);
+// if (spotEffect > spotCosCutoff) {
+// spotEffect = pow(smoothstep(spotCosOuterCutoff, spotCosInnerCutoff, spotEffect), light.exponent);
+// } else {
+// spotEffect = 0.0;
+// }
+
+// return ambient + attenuation * (spotEffect * diffuse + specular);
+// }
+
+vec3 calc_lighting(vec3 position, vec3 normal, vec3 viewDir) {
+ vec3 weight = vec3(0.0);
+ for (int i = 0; i < MAX_NUM_OF_DIRECTIONAL_LIGHTS; i++) {
+ if (i >= u_num_of_directional_lights) {
+ break;
+ }
+ weight += calc_directional_light(u_directional_lights[i], normal, viewDir);
+ }
+ // for (int i = 0; i < MAX_NUM_OF_SPOT_LIGHTS; i++) {
+ // if (i >= u_num_of_spot_lights) {
+ // break;
+ // }
+ // weight += calc_spot_light(u_spot_lights[i], normal, position, viewDir);
+ // }
+ return weight;
+}
\ No newline at end of file
diff --git a/src/layer/render/point/drawFill.js b/src/layer/render/point/drawFill.js
index a6ec26dc49..cc2fcf741e 100644
--- a/src/layer/render/point/drawFill.js
+++ b/src/layer/render/point/drawFill.js
@@ -9,6 +9,7 @@ import * as THREE from '../../../core/three';
import * as PointBuffer from '../../../geom/buffer/point/index';
import DrawStroke from './drawStroke';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
+import { generateLightingUniforms } from '../../../util/shaderModule';
export default function DrawFill(layerData, layer) {
const style = layer.get('styleOptions');
const activeOption = layer.get('activedOptions');
@@ -34,9 +35,11 @@ export default function DrawFill(layerData, layer) {
const material = new PolygonMaterial({
u_opacity: style.opacity,
u_activeColor: activeOption.fill,
- u_zoom: layer.scene.getZoom()
+ u_zoom: layer.scene.getZoom(),
+ ...generateLightingUniforms(style.lights)
}, {
- SHAPE: true
+ SHAPE: true,
+ LIGHTING: true
});
material.setDefinesvalue('SHAPE', true);
material.depthTest = false;
diff --git a/src/layer/render/polygon/drawAnimate.js b/src/layer/render/polygon/drawAnimate.js
index b8eed2ab34..beae138076 100644
--- a/src/layer/render/polygon/drawAnimate.js
+++ b/src/layer/render/polygon/drawAnimate.js
@@ -1,6 +1,8 @@
import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
+import { generateLightingUniforms } from '../../../util/shaderModule';
+
export default function DrawAnimate(layerData, layer) {
const style = layer.get('styleOptions');
const { near, far } = layer.map.getCameraState();
@@ -9,7 +11,7 @@ export default function DrawAnimate(layerData, layer) {
shape: 'extrude',
layerData
});
- const { opacity, baseColor, brightColor, windowColor } = style;
+ const { opacity, baseColor, brightColor, windowColor, lights } = style;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
@@ -23,9 +25,11 @@ export default function DrawAnimate(layerData, layer) {
u_brightColor: brightColor,
u_windowColor: windowColor,
u_near: near,
- u_far: far
+ u_far: far,
+ ...generateLightingUniforms(lights)
}, {
SHAPE: false,
+ LIGHTING: true,
ANIMATE: true
});
const fillPolygonMesh = new THREE.Mesh(geometry, material);
diff --git a/src/layer/render/polygon/drawFill.js b/src/layer/render/polygon/drawFill.js
index 11ae385a2e..6c32906c44 100644
--- a/src/layer/render/polygon/drawFill.js
+++ b/src/layer/render/polygon/drawFill.js
@@ -1,6 +1,7 @@
import * as THREE from '../../../core/three';
import PolygonBuffer from '../../../geom/buffer/polygon';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
+import { generateLightingUniforms } from '../../../util/shaderModule';
export default function DrawPolygonFill(layerData, layer) {
const style = layer.get('styleOptions');
@@ -9,7 +10,7 @@ export default function DrawPolygonFill(layerData, layer) {
...style,
activeColor: activeOption.fill
};
- const { opacity, activeColor } = config;
+ const { opacity, activeColor, lights } = config;
const { attributes } = new PolygonBuffer({
shape: layer.shape,
layerData
@@ -21,9 +22,11 @@ export default function DrawPolygonFill(layerData, layer) {
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
const material = new PolygonMaterial({
u_opacity: opacity,
- u_activeColor: activeColor
+ u_activeColor: activeColor,
+ ...generateLightingUniforms(lights)
}, {
- SHAPE: false
+ SHAPE: false,
+ LIGHTING: true
});
const fillPolygonMesh = new THREE.Mesh(geometry, material);
return fillPolygonMesh;
diff --git a/src/util/shaderModule.js b/src/util/shaderModule.js
index 2c6c775d85..a4078be0bd 100644
--- a/src/util/shaderModule.js
+++ b/src/util/shaderModule.js
@@ -178,7 +178,8 @@ export function wrapUniforms(uniforms) {
const DEFAULT_LIGHT = {
type: 'directional',
- direction: [ 1, 10.5, 12 ],
+ // direction: [ 1, 10.5, 12 ],
+ direction: [ 0, -10.5, 1 ],
ambient: [ 0.2, 0.2, 0.2 ],
diffuse: [ 0.6, 0.6, 0.6 ],
specular: [ 0.1, 0.1, 0.1 ]