Shader Builder / add option to generate hit detection shaders
This commit is contained in:
@@ -84,6 +84,8 @@ class WebGLPointsLayer extends Layer {
|
|||||||
return new WebGLPointsLayerRenderer(this, {
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
vertexShader: this.parseResult_.builder.getSymbolVertexShader(),
|
vertexShader: this.parseResult_.builder.getSymbolVertexShader(),
|
||||||
fragmentShader: this.parseResult_.builder.getSymbolFragmentShader(),
|
fragmentShader: this.parseResult_.builder.getSymbolFragmentShader(),
|
||||||
|
hitVertexShader: this.parseResult_.builder.getSymbolVertexShader(true),
|
||||||
|
hitFragmentShader: this.parseResult_.builder.getSymbolFragmentShader(true),
|
||||||
uniforms: this.parseResult_.uniforms,
|
uniforms: this.parseResult_.uniforms,
|
||||||
attributes: this.parseResult_.attributes
|
attributes: this.parseResult_.attributes
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
|||||||
options.hitVertexShader
|
options.hitVertexShader
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (this.getShaderCompileErrors()) {
|
||||||
|
throw new Error(this.getShaderCompileErrors());
|
||||||
|
}
|
||||||
|
|
||||||
const customAttributes = options.attributes ?
|
const customAttributes = options.attributes ?
|
||||||
options.attributes.map(function(attribute) {
|
options.attributes.map(function(attribute) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -248,13 +248,27 @@ export class ShaderBuilder {
|
|||||||
* The following varyings are hardcoded and gives the coordinate of the pixel both in the quad and on the texture:
|
* The following varyings are hardcoded and gives the coordinate of the pixel both in the quad and on the texture:
|
||||||
* `vec2 v_quadCoord`, `vec2 v_texCoord`
|
* `vec2 v_quadCoord`, `vec2 v_texCoord`
|
||||||
*
|
*
|
||||||
|
* @param {boolean} [forHitDetection] If true, the shader will be modified to include hit detection variables
|
||||||
|
* (namely, hit color with encoded feature id).
|
||||||
* @returns {string} The full shader as a string.
|
* @returns {string} The full shader as a string.
|
||||||
*/
|
*/
|
||||||
getSymbolVertexShader() {
|
getSymbolVertexShader(forHitDetection) {
|
||||||
const offsetMatrix = this.rotateWithView ?
|
const offsetMatrix = this.rotateWithView ?
|
||||||
'u_offsetScaleMatrix * u_offsetRotateMatrix' :
|
'u_offsetScaleMatrix * u_offsetRotateMatrix' :
|
||||||
'u_offsetScaleMatrix';
|
'u_offsetScaleMatrix';
|
||||||
|
|
||||||
|
let attributes = this.attributes;
|
||||||
|
let varyings = this.varyings;
|
||||||
|
|
||||||
|
if (forHitDetection) {
|
||||||
|
attributes = attributes.concat('vec4 a_hitColor');
|
||||||
|
varyings = varyings.concat({
|
||||||
|
name: 'v_hitColor',
|
||||||
|
type: 'vec4',
|
||||||
|
expression: 'a_hitColor'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return `precision mediump float;
|
return `precision mediump float;
|
||||||
uniform mat4 u_projectionMatrix;
|
uniform mat4 u_projectionMatrix;
|
||||||
uniform mat4 u_offsetScaleMatrix;
|
uniform mat4 u_offsetScaleMatrix;
|
||||||
@@ -265,12 +279,12 @@ ${this.uniforms.map(function(uniform) {
|
|||||||
}).join('\n')}
|
}).join('\n')}
|
||||||
attribute vec2 a_position;
|
attribute vec2 a_position;
|
||||||
attribute float a_index;
|
attribute float a_index;
|
||||||
${this.attributes.map(function(attribute) {
|
${attributes.map(function(attribute) {
|
||||||
return 'attribute ' + attribute + ';';
|
return 'attribute ' + attribute + ';';
|
||||||
}).join('\n')}
|
}).join('\n')}
|
||||||
varying vec2 v_texCoord;
|
varying vec2 v_texCoord;
|
||||||
varying vec2 v_quadCoord;
|
varying vec2 v_quadCoord;
|
||||||
${this.varyings.map(function(varying) {
|
${varyings.map(function(varying) {
|
||||||
return 'varying ' + varying.type + ' ' + varying.name + ';';
|
return 'varying ' + varying.type + ' ' + varying.name + ';';
|
||||||
}).join('\n')}
|
}).join('\n')}
|
||||||
void main(void) {
|
void main(void) {
|
||||||
@@ -288,7 +302,7 @@ void main(void) {
|
|||||||
u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
|
u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||||
v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;
|
v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||||
v_quadCoord = vec2(u, v);
|
v_quadCoord = vec2(u, v);
|
||||||
${this.varyings.map(function(varying) {
|
${varyings.map(function(varying) {
|
||||||
return ' ' + varying.name + ' = ' + varying.expression + ';';
|
return ' ' + varying.name + ' = ' + varying.expression + ';';
|
||||||
}).join('\n')}
|
}).join('\n')}
|
||||||
}`;
|
}`;
|
||||||
@@ -301,9 +315,24 @@ ${this.varyings.map(function(varying) {
|
|||||||
* Expects the following varyings to be transmitted by the vertex shader:
|
* Expects the following varyings to be transmitted by the vertex shader:
|
||||||
* `vec2 v_quadCoord`, `vec2 v_texCoord`
|
* `vec2 v_quadCoord`, `vec2 v_texCoord`
|
||||||
*
|
*
|
||||||
|
* @param {boolean} [forHitDetection] If true, the shader will be modified to include hit detection variables
|
||||||
|
* (namely, hit color with encoded feature id).
|
||||||
* @returns {string} The full shader as a string.
|
* @returns {string} The full shader as a string.
|
||||||
*/
|
*/
|
||||||
getSymbolFragmentShader() {
|
getSymbolFragmentShader(forHitDetection) {
|
||||||
|
const hitDetectionBypass = forHitDetection ?
|
||||||
|
' if (gl_FragColor.a < 0.1) { discard; } gl_FragColor = v_hitColor;' : '';
|
||||||
|
|
||||||
|
let varyings = this.varyings;
|
||||||
|
|
||||||
|
if (forHitDetection) {
|
||||||
|
varyings = varyings.concat({
|
||||||
|
name: 'v_hitColor',
|
||||||
|
type: 'vec4',
|
||||||
|
expression: 'a_hitColor'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return `precision mediump float;
|
return `precision mediump float;
|
||||||
uniform float u_time;
|
uniform float u_time;
|
||||||
${this.uniforms.map(function(uniform) {
|
${this.uniforms.map(function(uniform) {
|
||||||
@@ -311,13 +340,14 @@ ${this.uniforms.map(function(uniform) {
|
|||||||
}).join('\n')}
|
}).join('\n')}
|
||||||
varying vec2 v_texCoord;
|
varying vec2 v_texCoord;
|
||||||
varying vec2 v_quadCoord;
|
varying vec2 v_quadCoord;
|
||||||
${this.varyings.map(function(varying) {
|
${varyings.map(function(varying) {
|
||||||
return 'varying ' + varying.type + ' ' + varying.name + ';';
|
return 'varying ' + varying.type + ' ' + varying.name + ';';
|
||||||
}).join('\n')}
|
}).join('\n')}
|
||||||
void main(void) {
|
void main(void) {
|
||||||
if (${this.discardExpression}) { discard; }
|
if (${this.discardExpression}) { discard; }
|
||||||
gl_FragColor = ${this.colorExpression};
|
gl_FragColor = ${this.colorExpression};
|
||||||
gl_FragColor.rgb *= gl_FragColor.a;
|
gl_FragColor.rgb *= gl_FragColor.a;
|
||||||
|
${hitDetectionBypass}
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,39 @@ void main(void) {
|
|||||||
v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;
|
v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||||
v_quadCoord = vec2(u, v);
|
v_quadCoord = vec2(u, v);
|
||||||
|
|
||||||
|
}`);
|
||||||
|
});
|
||||||
|
it('generates a symbol vertex shader for hitDetection', function() {
|
||||||
|
const builder = new ShaderBuilder();
|
||||||
|
|
||||||
|
expect(builder.getSymbolVertexShader(true)).to.eql(`precision mediump float;
|
||||||
|
uniform mat4 u_projectionMatrix;
|
||||||
|
uniform mat4 u_offsetScaleMatrix;
|
||||||
|
uniform mat4 u_offsetRotateMatrix;
|
||||||
|
uniform float u_time;
|
||||||
|
|
||||||
|
attribute vec2 a_position;
|
||||||
|
attribute float a_index;
|
||||||
|
attribute vec4 a_hitColor;
|
||||||
|
varying vec2 v_texCoord;
|
||||||
|
varying vec2 v_quadCoord;
|
||||||
|
varying vec4 v_hitColor;
|
||||||
|
void main(void) {
|
||||||
|
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||||
|
vec2 size = vec2(1.0);
|
||||||
|
vec2 offset = vec2(0.0);
|
||||||
|
float offsetX = a_index == 0.0 || a_index == 3.0 ? offset.x - size.x / 2.0 : offset.x + size.x / 2.0;
|
||||||
|
float offsetY = a_index == 0.0 || a_index == 1.0 ? offset.y - size.y / 2.0 : offset.y + size.y / 2.0;
|
||||||
|
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
|
||||||
|
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
|
||||||
|
vec4 texCoord = vec4(0.0, 0.0, 1.0, 1.0);
|
||||||
|
float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p;
|
||||||
|
float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q;
|
||||||
|
v_texCoord = vec2(u, v);
|
||||||
|
u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||||
|
v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||||
|
v_quadCoord = vec2(u, v);
|
||||||
|
v_hitColor = a_hitColor;
|
||||||
}`);
|
}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -145,6 +178,7 @@ void main(void) {
|
|||||||
if (false) { discard; }
|
if (false) { discard; }
|
||||||
gl_FragColor = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
|
gl_FragColor = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
|
||||||
gl_FragColor.rgb *= gl_FragColor.a;
|
gl_FragColor.rgb *= gl_FragColor.a;
|
||||||
|
|
||||||
}`);
|
}`);
|
||||||
});
|
});
|
||||||
it('generates a symbol fragment shader (with uniforms)', function() {
|
it('generates a symbol fragment shader (with uniforms)', function() {
|
||||||
@@ -168,6 +202,23 @@ void main(void) {
|
|||||||
if (u_myUniform > 0.5) { discard; }
|
if (u_myUniform > 0.5) { discard; }
|
||||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
gl_FragColor.rgb *= gl_FragColor.a;
|
gl_FragColor.rgb *= gl_FragColor.a;
|
||||||
|
|
||||||
|
}`);
|
||||||
|
});
|
||||||
|
it('generates a symbol fragment shader for hit detection', function() {
|
||||||
|
const builder = new ShaderBuilder();
|
||||||
|
|
||||||
|
expect(builder.getSymbolFragmentShader(true)).to.eql(`precision mediump float;
|
||||||
|
uniform float u_time;
|
||||||
|
|
||||||
|
varying vec2 v_texCoord;
|
||||||
|
varying vec2 v_quadCoord;
|
||||||
|
varying vec4 v_hitColor;
|
||||||
|
void main(void) {
|
||||||
|
if (false) { discard; }
|
||||||
|
gl_FragColor = vec4(1.0);
|
||||||
|
gl_FragColor.rgb *= gl_FragColor.a;
|
||||||
|
if (gl_FragColor.a < 0.1) { discard; } gl_FragColor = v_hitColor;
|
||||||
}`);
|
}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user