diff --git a/src/core/scene.js b/src/core/scene.js index d9229a2512..121ede7bc8 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -6,6 +6,7 @@ import WorkerPool from './worker'; import { MapProvider } from '../map/provider'; import GaodeMap from '../map/gaodeMap'; import Global from '../global'; +import { compileBuiltinModules } from '../geom/shader'; export default class Scene extends Base { getDefaultCfg() { return Global.scene; @@ -22,6 +23,7 @@ export default class Scene extends Base { this._engine = new Engine(mapContainer, this); this._engine.run(); this.workerPool = new WorkerPool(); + compileBuiltinModules(); } // 为pickup场景添加 object 对象 addPickMesh(object) { diff --git a/src/geom/material/polygonMaterial.js b/src/geom/material/polygonMaterial.js index d47eb72065..da8a598122 100644 --- a/src/geom/material/polygonMaterial.js +++ b/src/geom/material/polygonMaterial.js @@ -1,6 +1,5 @@ -import polygon_frag from '../shader/polygon_frag.glsl'; -import polygon_vert from '../shader/polygon_vert.glsl'; import Material from './material'; +import { getModule } from '../../util/shaderModule'; // export default function PolygonMaterial(options) { // const material = new Material({ // uniforms: { @@ -48,8 +47,10 @@ export default class PolygonMaterial extends Material { this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms)); this.type = 'PolygonMaterial'; this.defines = Object.assign(defines, _defines); - this.vertexShader = polygon_vert; - this.fragmentShader = polygon_frag; + + const { vs, fs } = getModule('polygon'); + this.vertexShader = vs; + this.fragmentShader = fs; this.transparent = true; } } diff --git a/src/geom/shader/common.glsl b/src/geom/shader/common.glsl new file mode 100644 index 0000000000..09462af13e --- /dev/null +++ b/src/geom/shader/common.glsl @@ -0,0 +1,2 @@ +#define PI 3.14159265359 +#define TWO_PI 6.28318530718 \ No newline at end of file diff --git a/src/geom/shader/index.js b/src/geom/shader/index.js index 525a698d2d..fffbfda42a 100644 --- a/src/geom/shader/index.js +++ b/src/geom/shader/index.js @@ -1,14 +1,12 @@ import point_frag from '../shader/point_frag.glsl'; import point_vert from '../shader/point_vert.glsl'; -const shaderslib = { - pointShader: { - fragment: point_frag, - vertex: point_vert - } -}; -// for (const programName in shaderslib) { -// const program = shaderslib[programName]; -// program.fragment = ShaderFactory.parseIncludes(program.fragment); -// program.vertex = ShaderFactory.parseIncludes(program.vertex); -// } -export default shaderslib; +import polygon_frag from '../shader/polygon_frag.glsl'; +import polygon_vert from '../shader/polygon_vert.glsl'; +import common from './common.glsl'; +import { registerModule } from '../../util/shaderModule'; + +export function compileBuiltinModules() { + registerModule('point', { vs: point_vert, fs: point_frag }); + registerModule('common', { vs: common, fs: common }); + registerModule('polygon', { vs: polygon_vert, fs: polygon_frag }); +} diff --git a/src/geom/shader/point_frag.glsl b/src/geom/shader/point_frag.glsl index 238c972638..eecea0605c 100644 --- a/src/geom/shader/point_frag.glsl +++ b/src/geom/shader/point_frag.glsl @@ -1,7 +1,8 @@ precision highp float; -#define PI 3.14159265359 -#define TWO_PI 6.28318530718 + +#pragma import "common" + uniform float u_strokeWidth; uniform vec4 u_stroke; uniform float u_opacity; diff --git a/src/geom/shader/project_vert.glsl b/src/geom/shader/project_vert.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/util/shaderModule.js b/src/util/shaderModule.js new file mode 100644 index 0000000000..b0a354194f --- /dev/null +++ b/src/util/shaderModule.js @@ -0,0 +1,59 @@ +const SHADER_TYPE = { + VS: 'vs', + FS: 'fs' +}; +const moduleCache = {}; +const rawContentCache = {}; +const precisionRegExp = /precision\s+(high|low|medium)p\s+float/; +const globalDefaultprecision = '#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n #else\n precision mediump float;\n#endif\n'; +const includeRegExp = /#pragma include (["^+"]?["\ "[a-zA-Z_0-9](.*)"]*?)/g; + +function processModule(rawContent, includeList, type) { + return rawContent.replace(includeRegExp, (_, strMatch) => { + const includeOpt = strMatch.split(' '); + const includeName = includeOpt[0].replace(/"/g, ''); + + if (includeList.indexOf(includeName) > -1) { + return ''; + } + + let txt = rawContentCache[includeName][type]; + includeList.push(includeName); + + txt = processModule(txt, includeList, type); + return txt; + }); +} + +export function registerModule(moduleName, { vs, fs }) { + rawContentCache[moduleName] = { + [SHADER_TYPE.VS]: vs, + [SHADER_TYPE.FS]: fs + }; +} + +export function getModule(moduleName) { + if (moduleCache[moduleName]) { + return moduleCache[moduleName]; + } + + let vs = rawContentCache[moduleName][SHADER_TYPE.VS]; + let fs = rawContentCache[moduleName][SHADER_TYPE.FS]; + + vs = processModule(vs, [], SHADER_TYPE.VS); + fs = processModule(fs, [], SHADER_TYPE.FS); + + /** + * set default precision for fragment shader + * https://stackoverflow.com/questions/28540290/why-it-is-necessary-to-set-precision-for-the-fragment-shader + */ + if (!precisionRegExp.test(fs)) { + fs = globalDefaultprecision + fs; + } + + moduleCache[moduleName] = { + [SHADER_TYPE.VS]: vs.trim(), + [SHADER_TYPE.FS]: fs.trim() + }; + return moduleCache[moduleName]; +} diff --git a/test/unit/shader-module/base-spec.js b/test/unit/shader-module/base-spec.js new file mode 100644 index 0000000000..8f2b35c079 --- /dev/null +++ b/test/unit/shader-module/base-spec.js @@ -0,0 +1,32 @@ +import { expect } from 'chai'; +import { registerModule, getModule } from '../../../src/util/shaderModule'; + +describe('test shader module', function() { + + const vs = ` + #define PI 3.14 + `; + + const commonModule = { + vs, + fs: vs + }; + + const module1 = { + vs: ` + #pragma include "common" + `, + fs: '' + }; + + registerModule('common', commonModule); + registerModule('module1', module1); + + it('should import a module correctly.', function() { + const { vs, fs } = getModule('module1'); + + expect(vs).eq('#define PI 3.14'); + expect(fs).eq(''); + }); + +});