diff --git a/src/layers/hexbin.js b/src/layers/hexbin.js index 2b207a5..2bfa280 100755 --- a/src/layers/hexbin.js +++ b/src/layers/hexbin.js @@ -4,8 +4,7 @@ import { DoubleSide, Mesh, MeshLambertMaterial, - Object3D, - ShaderMaterial + Object3D } from 'three'; const THREE = window.THREE @@ -16,8 +15,7 @@ const THREE = window.THREE DoubleSide, Mesh, MeshLambertMaterial, - Object3D, - ShaderMaterial + Object3D }; import * as _bfg from 'three/addons/utils/BufferGeometryUtils.js'; @@ -34,10 +32,10 @@ import { Tween, Easing } from '@tweenjs/tween.js'; import { colorStr2Hex, colorAlpha, color2ShaderArr } from '../utils/color-utils'; import { array2BufferAttr } from '../utils/three-utils'; +import { applyShaderExtensionToMaterial, invisibleUndergroundShaderExtend } from '../utils/shaders'; import { emptyObject } from '../utils/gc'; import threeDigest from '../utils/digest'; import { GLOBE_RADIUS } from '../constants'; -import { invisibleUndergroundShader } from '../utils/shaders'; // @@ -87,8 +85,7 @@ export default Kapsule({ sumWeight: points.reduce((agg, d) => agg + +weightAccessor(d), 0) })); - const topHexMaterials = {}; // indexed by color - const sideHexMaterials = {}; // indexed by color + const hexMaterials = {}; // indexed by color const scene = state.hexBinMerge ? new THREE.Object3D() : state.scene; // use fake scene if merging hex points @@ -113,8 +110,8 @@ export default Kapsule({ geom.applyMatrix4(obj.matrix); // color vertices - const topColor = color2ShaderArr(topColorAccessor(d), true, true); - const sideColor = color2ShaderArr(sideColorAccessor(d), true, true); + const topColor = color2ShaderArr(topColorAccessor(d)); + const sideColor = color2ShaderArr(sideColorAccessor(d)); const nVertices = geom.getAttribute('position').count; const topFaceIdx = geom.groups[0].count; // starting vertex index of top group @@ -126,11 +123,18 @@ export default Kapsule({ return geom; })); - const hexPoints = new THREE.Mesh(hexPointsGeometry, new THREE.ShaderMaterial({ - ...(invisibleUndergroundShader({ vertexColors: true })), - transparent: true, - side: THREE.DoubleSide - })); + const hexPoints = new THREE.Mesh( + hexPointsGeometry, + applyShaderExtensionToMaterial( + new THREE.MeshLambertMaterial({ + color: 0xffffff, + transparent: true, + vertexColors: true, + side: THREE.DoubleSide + }), + invisibleUndergroundShaderExtend + ) + ); hexPoints.__globeObjType = 'hexBinPoints'; // Add object type hexPoints.__data = hexBins; // Attach obj data @@ -217,26 +221,21 @@ export default Kapsule({ const sideColor = sideColorAccessor(d); const topColor = topColorAccessor(d); - if (!sideHexMaterials.hasOwnProperty(sideColor)) { - const opacity = colorAlpha(sideColor); - sideHexMaterials[sideColor] = new THREE.ShaderMaterial({ - ...(invisibleUndergroundShader()), - transparent: opacity < 1, - side: THREE.DoubleSide - }); - sideHexMaterials[sideColor].uniforms.color.value = color2ShaderArr(sideColor, true, true); - } - if (!topHexMaterials.hasOwnProperty(topColor)) { - const opacity = colorAlpha(topColor); - topHexMaterials[topColor] = new THREE.MeshLambertMaterial({ - color: colorStr2Hex(topColor), - opacity: opacity, - transparent: opacity < 1, - side: THREE.DoubleSide - }); - } - - obj.material = [sideHexMaterials[sideColor], topHexMaterials[topColor]]; + [sideColor, topColor].forEach(color => { + if (!hexMaterials.hasOwnProperty(color)) { + const opacity = colorAlpha(color); + hexMaterials[color] = applyShaderExtensionToMaterial( + new THREE.MeshLambertMaterial({ + color: colorStr2Hex(color), + transparent: opacity < 1, + opacity: opacity, + side: THREE.DoubleSide + }), + invisibleUndergroundShaderExtend + ); + } + }); + obj.material = [sideColor, topColor].map(color => hexMaterials[color]); } } } diff --git a/src/layers/polygons.js b/src/layers/polygons.js index 0bbd0d7..9eb720e 100644 --- a/src/layers/polygons.js +++ b/src/layers/polygons.js @@ -4,8 +4,7 @@ import { LineBasicMaterial, LineSegments, Mesh, - MeshBasicMaterial, - ShaderMaterial + MeshBasicMaterial } from 'three'; const THREE = window.THREE @@ -16,8 +15,7 @@ const THREE = window.THREE LineBasicMaterial, LineSegments, Mesh, - MeshBasicMaterial, - ShaderMaterial + MeshBasicMaterial }; import { ConicPolygonGeometry } from 'three-conic-polygon-geometry'; @@ -27,11 +25,11 @@ import Kapsule from 'kapsule'; import accessorFn from 'accessor-fn'; import { Tween, Easing } from '@tweenjs/tween.js'; -import { colorStr2Hex, colorAlpha, color2ShaderArr } from '../utils/color-utils'; +import { colorStr2Hex, colorAlpha } from '../utils/color-utils'; +import { applyShaderExtensionToMaterial, invisibleUndergroundShaderExtend } from '../utils/shaders'; import { emptyObject } from '../utils/gc'; import threeDigest from '../utils/digest'; import { GLOBE_RADIUS } from '../constants'; -import { invisibleUndergroundShader } from '../utils/shaders'; // @@ -109,11 +107,11 @@ export default Kapsule({ createObj: () => { const obj = new THREE.Group(); - obj.__defaultSideMaterial = new THREE.ShaderMaterial({ - ...(invisibleUndergroundShader()), - side: THREE.DoubleSide, - depthWrite: true - }); + obj.__defaultSideMaterial = applyShaderExtensionToMaterial( + new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, depthWrite: true }), + invisibleUndergroundShaderExtend + ); + obj.__defaultCapMaterial = new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, depthWrite: true }); // conic geometry @@ -176,13 +174,9 @@ export default Kapsule({ // conic object const material = conicObj.material[materialIdx]; const opacity = colorAlpha(color); + material.color.set(colorStr2Hex(color)); material.transparent = opacity < 1; - if (material.type !== 'ShaderMaterial') { - material.color.set(colorStr2Hex(color)); - material.opacity = opacity; - } else { - material.uniforms.color.value = color2ShaderArr(color, true, true); - } + material.opacity = opacity; }); if (addStroke) { @@ -200,7 +194,7 @@ export default Kapsule({ const { alt } = obj.__currentTargetD = td; conicObj.scale.x = conicObj.scale.y = conicObj.scale.z = 1 + alt; addStroke && (strokeObj.scale.x = strokeObj.scale.y = strokeObj.scale.z = 1 + alt + 1e-4); // stroke slightly above the conic mesh - obj.__defaultSideMaterial.uniforms.surfaceRadius.value = GLOBE_RADIUS / (alt + 1); // update side material scale uniform + obj.__defaultSideMaterial.userData.shader && (obj.__defaultSideMaterial.userData.shader.uniforms.surfaceRadius.value = GLOBE_RADIUS / (alt + 1)); // update side material scale uniform }; const currentTargetD = obj.__currentTargetD || Object.assign({}, targetD, { alt: -1e-3 }); diff --git a/src/utils/shaders.js b/src/utils/shaders.js index 515c4de..a968aeb 100644 --- a/src/utils/shaders.js +++ b/src/utils/shaders.js @@ -77,4 +77,29 @@ export const invisibleUndergroundShader = ({ vertexColors = false } = {}) => ({ gl_FragColor = ${vertexColors ? 'vColor' : 'color'}; } ` -}); \ No newline at end of file +}); + +export const invisibleUndergroundShaderExtend = shader => { + shader.uniforms.surfaceRadius = { type: 'float', value: 0 }; + shader.vertexShader = ('attribute float surfaceRadius;\nvarying float vSurfaceRadius;\nvarying vec3 vPos;\n' + shader.vertexShader) + .replace('void main() {', [ + 'void main() {', + 'vSurfaceRadius = surfaceRadius;', + 'vPos = position;' + ].join('\n')); + + shader.fragmentShader = ('uniform float surfaceRadius;\nvarying float vSurfaceRadius;\nvarying vec3 vPos;\n' + shader.fragmentShader) + .replace('void main() {', [ + 'void main() {', + 'if (length(vPos) < max(surfaceRadius, vSurfaceRadius)) discard;' + ].join('\n')); + + return shader; +}; + +export const applyShaderExtensionToMaterial = (material, extensionFn) => { + material.onBeforeCompile = shader => { + material.userData.shader = extensionFn(shader); + }; + return material; +}; \ No newline at end of file