157 lines
4.4 KiB
WebGPU Shading Language
157 lines
4.4 KiB
WebGPU Shading Language
struct View {
|
|
viewProj: mat4x4f,
|
|
lightViewProj: mat4x4f,
|
|
lightPosition: vec4f,
|
|
eyePosition: vec4f,
|
|
aspect: f32,
|
|
};
|
|
|
|
struct Config {
|
|
scale: f32,
|
|
translateX: f32,
|
|
translateY: f32,
|
|
padding0: f32,
|
|
distanceThreshold: f32,
|
|
distanceScale: f32,
|
|
distanceOffset: f32,
|
|
padding1: f32,
|
|
outlineThreshold: f32,
|
|
outlineScale: f32,
|
|
outlineOffset: f32,
|
|
padding2: f32,
|
|
colorMix: f32,
|
|
colorScale: f32,
|
|
colorOffset: f32,
|
|
padding3: f32,
|
|
};
|
|
|
|
struct GlyphBuffer {
|
|
texPosition: vec2f,
|
|
texSize: vec2f,
|
|
size: vec2f,
|
|
unused: vec2f,
|
|
};
|
|
|
|
struct LayoutBuffer {
|
|
position: vec4f, // glyph_index w
|
|
};
|
|
|
|
@group(0) @binding(0) var<uniform> view: View;
|
|
|
|
@group(1) @binding(0) var linearSampler: sampler;
|
|
@group(1) @binding(1) var fontTexture: texture_2d<f32>;
|
|
@group(1) @binding(2) var<storage> glyphBuffer: array<GlyphBuffer>;
|
|
|
|
@group(2) @binding(0) var<storage> layoutBuffer: array<LayoutBuffer>;
|
|
@group(2) @binding(1) var<uniform> config: Config;
|
|
|
|
struct VertexInput {
|
|
@builtin(vertex_index) vertex_index: u32,
|
|
@builtin(instance_index) instance_index: u32,
|
|
};
|
|
|
|
struct VertexOutput {
|
|
@builtin(position) position: vec4f,
|
|
@location(0) @interpolate(linear, sample) texture: vec2f,
|
|
//@location(0) texture: vec2f,
|
|
@location(1) @interpolate(flat) glyphIndex: u32,
|
|
@location(2) foo: vec4f,
|
|
};
|
|
|
|
const vertices = array(
|
|
vec2f(1.0, 0.0),
|
|
vec2f(0.0, 1.0),
|
|
vec2f(0.0, 0.0),
|
|
vec2f(1.0, 1.0),
|
|
);
|
|
|
|
@vertex
|
|
fn vertexMain(input: VertexInput) -> VertexOutput
|
|
{
|
|
let texture = vertices[input.vertex_index];
|
|
|
|
let position = vec2f(texture.x, 1.0 - texture.y);
|
|
|
|
let glyphIndex = u32(layoutBuffer[input.instance_index].position.w);
|
|
let viewPosition = position * glyphBuffer[glyphIndex].size + layoutBuffer[input.instance_index].position.xy;
|
|
let screenPosition = viewPosition * vec2f(1 / view.aspect, 1) * config.scale + vec2f(config.translateX, config.translateY);
|
|
|
|
var output: VertexOutput;
|
|
output.position = vec4f(screenPosition, 0.0, 1.0);
|
|
output.texture = texture;
|
|
output.glyphIndex = glyphIndex;
|
|
output.foo = vec4f(layoutBuffer[glyphIndex].position.xy, 0, 0);
|
|
return output;
|
|
}
|
|
|
|
fn blend(dst: vec4f, src: vec4f, distance: f32, threshold: f32, scale: f32, offset: f32) -> vec4f
|
|
{
|
|
let scaledDistance = (distance - threshold) * scale + offset;
|
|
let alpha = clamp(scaledDistance, 0.0, 1.0);
|
|
let opacity = clamp(src.a * alpha - dst.a, 0.0, 1.0);
|
|
return opacity * src + (1.0 - opacity) * dst;
|
|
}
|
|
|
|
fn palette(t: f32) -> vec4f
|
|
{
|
|
let a = vec3f(0.5, 0.5, 0.5);
|
|
let b = vec3f(0.5, 0.5, 0.5);
|
|
let c = vec3f(1.0, 1.0, 1.0);
|
|
let d = vec3f(0.00, 0.33, 0.67);
|
|
//0.263,0.416,0.557
|
|
let color = a + b * cos(6.28318 * (c * t + d));
|
|
return vec4f(color, 1);
|
|
}
|
|
|
|
fn aliasedLinearSaturation(distance: f32, threshold: f32, scale: f32) -> f32
|
|
{
|
|
let distanceFromEdge = threshold - distance;
|
|
let dx = dpdx(distanceFromEdge);
|
|
let dy = dpdy(distanceFromEdge);
|
|
let gradientLength = length(vec2f(dx, dy));
|
|
let thresholdWidth = scale * gradientLength;
|
|
let aliased = saturate((distanceFromEdge / thresholdWidth) + 0.5);
|
|
return aliased;
|
|
}
|
|
|
|
@fragment
|
|
fn fragmentMain(input: VertexOutput) -> @location(0) vec4f
|
|
{
|
|
let p = glyphBuffer[input.glyphIndex].texPosition;
|
|
let s = glyphBuffer[input.glyphIndex].texSize;
|
|
|
|
let base = textureSample(fontTexture, linearSampler, input.texture * s + p);
|
|
let distance = base.x;
|
|
|
|
let insideT = aliasedLinearSaturation(distance,
|
|
config.distanceThreshold,
|
|
config.distanceScale);
|
|
|
|
let outlineT = aliasedLinearSaturation(distance,
|
|
config.outlineThreshold,
|
|
config.outlineScale);
|
|
|
|
let insideColor = vec4f(1, 1, 1, 1);
|
|
let outlineColor = vec4f(0, 0, 0, 1);
|
|
let outsideColor = vec4f(0, 0, 0, 0);
|
|
|
|
let outline = mix(outlineColor, outsideColor, outlineT);
|
|
return mix(insideColor, outline, insideT);
|
|
|
|
/*
|
|
let insideColorW = vec4f(1, 1, 1, 1);
|
|
let insideColorP = palette(distance * config.colorScale + config.colorOffset);
|
|
let insideColor = mix(insideColorW, insideColorP, config.colorMix);
|
|
let outlineColor = vec4f(0, 0, 0, 1);
|
|
|
|
var color = vec4f(0, 0, 0, 0);
|
|
color = blend(color, insideColor, distance,
|
|
config.distanceThreshold, config.distanceScale, config.distanceOffset);
|
|
|
|
color = blend(color, outlineColor, distance,
|
|
config.distanceThreshold - config.outlineThreshold,
|
|
config.outlineScale, config.outlineOffset);
|
|
return color;
|
|
*/
|
|
}
|