WebGL / Add new module with default shaders for VectorLayer

This commit is contained in:
Olivier Guyot
2022-06-09 13:04:37 +02:00
parent 6848df97f8
commit 79c974d63d
2 changed files with 214 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ import {buffer, createEmpty, equals, getWidth} from '../../extent.js';
import {create as createTransform} from '../../transform.js'; import {create as createTransform} from '../../transform.js';
import {create as createWebGLWorker} from '../../worker/webgl.js'; import {create as createWebGLWorker} from '../../worker/webgl.js';
import {listen, unlistenByKey} from '../../events.js'; import {listen, unlistenByKey} from '../../events.js';
import './shaders.js'; // this is to make sure that default shaders are part of the bundle
/** /**
* @typedef {Object} CustomAttribute A description of a custom attribute to be passed on to the GPU, with a value different * @typedef {Object} CustomAttribute A description of a custom attribute to be passed on to the GPU, with a value different

View File

@@ -0,0 +1,213 @@
/**
* @module ol/renderer/webgl/shaders
*/
import {asArray} from '../../color.js';
/**
* Attribute names used in the default shaders.
* @enum {string}
*/
export const DefaultAttributes = {
COLOR: 'color',
OPACITY: 'opacity',
WIDTH: 'width',
};
/**
* Packs red/green/blue channels of a color into a single float value; alpha is ignored.
* This is how DefaultAttributes.COLOR is expected to be computed.
* @param {import("../../color.js").Color|string} color Color as array of numbers or string
* @return {number} Float value containing the color
* @api
*/
export function packColor(color) {
const array = asArray(color);
const r = array[0] * 256 * 256;
const g = array[1] * 256;
const b = array[2];
return r + g + b;
}
const DECODE_COLOR_EXPRESSION = `vec3(
fract(floor(a_color / 256.0 / 256.0) / 256.0),
fract(floor(a_color / 256.0) / 256.0),
fract(a_color / 256.0)
);`;
/**
* Default polygon vertex shader.
* Relies on DefaultAttributes.COLOR and DefaultAttributes.OPACITY.
* @type {string}
* @api
*/
export const DEFAULT_POLYGON_VERTEX = `
precision mediump float;
uniform mat4 u_projectionMatrix;
attribute vec2 a_position;
attribute float a_color;
attribute float a_opacity;
varying vec3 v_color;
varying float v_opacity;
void main(void) {
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0);
v_color = ${DECODE_COLOR_EXPRESSION}
v_opacity = a_opacity;
}`;
/**
* Default polygon fragment shader.
* @type {string}
* @api
*/
export const DEFAULT_POLYGON_FRAGMENT = `
precision mediump float;
varying vec3 v_color;
varying float v_opacity;
void main(void) {
gl_FragColor = vec4(v_color, 1.0) * v_opacity;
}`;
/**
* Default linestring vertex shader.
* Relies on DefaultAttributes.COLOR, DefaultAttributes.OPACITY and DefaultAttributes.WIDTH.
* @type {string}
* @api
*/
export const DEFAULT_LINESTRING_VERTEX = `
precision mediump float;
uniform mat4 u_projectionMatrix;
uniform vec2 u_sizePx;
attribute vec2 a_segmentStart;
attribute vec2 a_segmentEnd;
attribute float a_parameters;
attribute float a_color;
attribute float a_opacity;
attribute float a_width;
varying vec2 v_segmentStart;
varying vec2 v_segmentEnd;
varying float v_angleStart;
varying float v_angleEnd;
varying vec3 v_color;
varying float v_opacity;
varying float v_width;
vec2 worldToPx(vec2 worldPos) {
vec4 screenPos = u_projectionMatrix * vec4(worldPos, 0.0, 1.0);
return (0.5 * screenPos.xy + 0.5) * u_sizePx;
}
vec4 pxToScreen(vec2 pxPos) {
vec2 screenPos = pxPos * 4.0 / u_sizePx;
return vec4(screenPos.xy, 0.0, 0.0);
}
vec2 getOffsetDirection(vec2 normalPx, vec2 tangentPx, float joinAngle) {
if (cos(joinAngle) > 0.93) return normalPx - tangentPx;
float halfAngle = joinAngle / 2.0;
vec2 angleBisectorNormal = vec2(
sin(halfAngle) * normalPx.x + cos(halfAngle) * normalPx.y,
-cos(halfAngle) * normalPx.x + sin(halfAngle) * normalPx.y
);
float length = 1.0 / sin(halfAngle);
return angleBisectorNormal * length;
}
void main(void) {
float anglePrecision = 1500.0;
float paramShift = 10000.0;
v_angleStart = fract(a_parameters / paramShift) * paramShift / anglePrecision;
v_angleEnd = fract(floor(a_parameters / paramShift + 0.5) / paramShift) * paramShift / anglePrecision;
float vertexNumber = floor(a_parameters / paramShift / paramShift + 0.0001);
vec2 tangentPx = worldToPx(a_segmentEnd) - worldToPx(a_segmentStart);
tangentPx = normalize(tangentPx);
vec2 normalPx = vec2(-tangentPx.y, tangentPx.x);
float normalDir = vertexNumber < 0.5 || (vertexNumber > 1.5 && vertexNumber < 2.5) ? 1.0 : -1.0;
float tangentDir = vertexNumber < 1.5 ? 1.0 : -1.0;
float angle = vertexNumber < 1.5 ? v_angleStart : v_angleEnd;
vec2 offsetPx = getOffsetDirection(normalPx * normalDir, tangentDir * tangentPx, angle) * a_width * 0.5;
vec2 position = vertexNumber < 1.5 ? a_segmentStart : a_segmentEnd;
gl_Position = u_projectionMatrix * vec4(position, 0.0, 1.0) + pxToScreen(offsetPx);
v_segmentStart = worldToPx(a_segmentStart);
v_segmentEnd = worldToPx(a_segmentEnd);
v_color = ${DECODE_COLOR_EXPRESSION}
v_opacity = a_opacity;
v_width = a_width;
}`;
/**
* Default linestring fragment shader.
* @type {string}
* @api
*/
export const DEFAULT_LINESTRING_FRAGMENT = `
precision mediump float;
uniform float u_pixelRatio;
varying vec2 v_segmentStart;
varying vec2 v_segmentEnd;
varying float v_angleStart;
varying float v_angleEnd;
varying vec3 v_color;
varying float v_opacity;
varying float v_width;
float segmentDistanceField(vec2 point, vec2 start, vec2 end, float radius) {
vec2 startToPoint = point - start;
vec2 startToEnd = end - start;
float ratio = clamp(dot(startToPoint, startToEnd) / dot(startToEnd, startToEnd), 0.0, 1.0);
float dist = length(startToPoint - ratio * startToEnd);
return 1.0 - smoothstep(radius - 1.0, radius, dist);
}
void main(void) {
vec2 v_currentPoint = gl_FragCoord.xy / u_pixelRatio;
gl_FragColor = vec4(v_color, 1.0) * v_opacity;
gl_FragColor *= segmentDistanceField(v_currentPoint, v_segmentStart, v_segmentEnd, v_width);
}`;
/**
* Default point vertex shader.
* Relies on DefaultAttributes.COLOR and DefaultAttributes.OPACITY.
* @type {string}
* @api
*/
export const DEFAULT_POINT_VERTEX = `
precision mediump float;
uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix;
attribute vec2 a_position;
attribute float a_index;
attribute float a_color;
attribute float a_opacity;
varying vec2 v_texCoord;
varying vec3 v_color;
varying float v_opacity;
void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix;
float size = 6.0;
float offsetX = a_index == 0.0 || a_index == 3.0 ? -size / 2.0 : size / 2.0;
float offsetY = a_index == 0.0 || a_index == 1.0 ? -size / 2.0 : size / 2.0;
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;
v_texCoord = vec2(u, v);
v_color = ${DECODE_COLOR_EXPRESSION}
v_opacity = a_opacity;
}`;
/**
* Default point fragment shader.
* @type {string}
* @api
*/
export const DEFAULT_POINT_FRAGMENT = `
precision mediump float;
varying vec3 v_color;
varying float v_opacity;
void main(void) {
gl_FragColor = vec4(v_color, 1.0) * v_opacity;
}`;