Fixing several embarrassing bugs.

WebGPU and REGL projects now flipY again, and they properly flip the symbolY glyph coordinate in the rain pass's fragment shader.
Switching on some older code that was disabled for FF Nightly support— it makes more sense to wait for that support as implementations finalize.
Added mipmap to images loaded into REGL project.
This commit is contained in:
Rezmason
2022-10-11 09:25:24 -07:00
parent 3843dd90d1
commit e8be232e9b
10 changed files with 46 additions and 65 deletions

View File

@@ -1,6 +1,17 @@
TODO:
Seems like bloom size and resolution impact the REGL and WebGPU bloom implementations differently
Ossify the REGL bloom
Load all the GLSL from files
Move high pass into WebGPU bloom
Live config update roadmap
Write an explanation of the rain pass (and include images)
Compute
Volumetric quads
Fullscreen quad and spacial mapping
MSDFs
Audio system
Toggle (or number representing frequency)
@@ -37,12 +48,6 @@ WebGPU
Improve loop support
Write an explanation of the rain pass (and include images)
Compute
Volumetric quads
Fullscreen quad and spacial mapping
MSDFs
Idea: Build a UI
Replace versions with presets
Simple changes update the values

View File

@@ -1,4 +1,4 @@
import { loadImage, loadText, makePassFBO, makePass } from "./utils.js";
import { loadText, makePassFBO, makePass } from "./utils.js";
let start;
const numClicks = 5;

View File

@@ -1,4 +1,4 @@
import { loadImage, loadText, makePassFBO, makePass } from "./utils.js";
import { loadText, makePassFBO, makePass } from "./utils.js";
// Multiplies the rendered rain and bloom by a loaded in image

View File

@@ -134,8 +134,8 @@ export default ({ regl, config, lkg }) => {
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
const glyphMSDF = loadImage(regl, config.glyphMSDFURL);
const glintMSDF = loadImage(regl, config.glintMSDFURL);
const baseTexture = loadImage(regl, config.baseTextureURL);
const glintTexture = loadImage(regl, config.glintTextureURL);
const baseTexture = loadImage(regl, config.baseTextureURL, true);
const glintTexture = loadImage(regl, config.glintTextureURL, true);
const rainPassVert = loadText("shaders/glsl/rainPass.vert.glsl");
const rainPassFrag = loadText("shaders/glsl/rainPass.frag.glsl");
const output = makePassFBO(regl, config.useHalfFloat);

View File

@@ -1,11 +1,10 @@
const makePassTexture = (regl, halfFloat, mipmap) =>
const makePassTexture = (regl, halfFloat) =>
regl.texture({
width: 1,
height: 1,
type: halfFloat ? "half float" : "uint8",
wrap: "clamp",
minFilter: "mipmap",
min: mipmap ? "mipmap" : "linear",
min: "linear",
mag: "linear",
});
@@ -26,7 +25,9 @@ const makeDoubleBuffer = (regl, props) => {
};
};
const loadImage = (regl, url) => {
const isPowerOfTwo = (x) => Math.log2(x) % 1 == 0;
const loadImage = (regl, url, mipmap) => {
let texture = regl.texture([[0]]);
let loaded = false;
return {
@@ -55,10 +56,17 @@ const loadImage = (regl, url) => {
data.src = url;
await data.decode();
loaded = true;
if (mipmap) {
if (!isPowerOfTwo(data.width) || !isPowerOfTwo(data.height)) {
console.warn(`Can't mipmap a non-power-of-two image: ${url}`);
}
mipmap = false;
}
texture = regl.texture({
data,
mag: "linear",
min: "linear",
min: mipmap ? "mipmap" : "linear",
flipY: true,
});
}
})(),

View File

@@ -1,7 +1,12 @@
/*
// TODO: switch back to this impl once it doesn't break on FF Nightly
const loadTexture = async (device, url) => {
if (url == null) {
return device.createTexture({
size: [1, 1, 1],
format: "rgba8unorm",
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
}
const response = await fetch(url);
const data = await response.blob();
const source = await createImageBitmap(data);
@@ -13,42 +18,7 @@ const loadTexture = async (device, url) => {
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
device.queue.copyExternalImageToTexture({ source }, { texture }, size);
return texture;
};
*/
const loadTexture = async (device, url) => {
if (url == null) {
return device.createTexture({
size: [1, 1, 1],
format: "rgba8unorm",
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
}
const image = new Image();
image.crossOrigin = "Anonymous";
image.src = url;
await image.decode();
const { width, height } = image;
const size = [width, height, 1];
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
const source = ctx.getImageData(0, 0, width, height).data;
const texture = device.createTexture({
size,
format: "rgba8unorm",
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
device.queue.writeTexture({ texture }, source, { bytesPerRow: 4 * width }, size);
device.queue.copyExternalImageToTexture({ source, flipY: true }, { texture }, size);
return texture;
};

View File

@@ -102,13 +102,13 @@ vec3 getBrightness(vec4 raindrop, vec4 effect, float quadDepth, vec2 uv) {
vec2 getSymbolUV(float index) {
float symbolX = modI(index, glyphTextureGridSize.x);
float symbolY = (index - symbolX) / glyphTextureGridSize.x;
symbolY = glyphTextureGridSize.y - symbolY - 1.;
return vec2(symbolX, symbolY);
}
vec2 getSymbol(vec2 uv, float index) {
// resolve UV to cropped position of glyph in MSDF texture
uv = fract(uv * vec2(numColumns, numRows));
uv.y = 1.0 - uv.y; // y-flip
uv -= 0.5;
uv *= clamp(1. - glyphEdgeCrop, 0., 1.);
uv += 0.5;

View File

@@ -33,7 +33,7 @@ fn getBrightness(uv : vec2<f32>) -> vec4<f32> {
var uv = vec2<f32>(coord) / vec2<f32>(screenSize);
var bgColor = textureSampleLevel( backgroundTex, linearSampler, uv, 0.0 ).rgb;
var bgColor = textureSampleLevel( backgroundTex, linearSampler, vec2<f32>(uv.x, 1.0 - uv.y), 0.0 ).rgb;
// Combine the texture and bloom, then blow it out to reveal more of the image
var brightness = getBrightness(uv);

View File

@@ -352,11 +352,10 @@ fn computeEffect (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scre
// Vertex shader
// Firefox Nightly (that is to say, Naga) currently has a bug that mixes up these values from ones in the uniforms.
// var<private> quadCorners : array<vec2<f32>, NUM_VERTICES_PER_QUAD> = array<vec2<f32>, NUM_VERTICES_PER_QUAD>(
// vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 0.0), vec2<f32>(0.0, 1.0),
// vec2<f32>(1.0, 1.0), vec2<f32>(0.0, 1.0), vec2<f32>(1.0, 0.0)
// );
var<private> quadCorners : array<vec2<f32>, NUM_VERTICES_PER_QUAD> = array<vec2<f32>, NUM_VERTICES_PER_QUAD>(
vec2<f32>(0.0, 0.0), vec2<f32>(0.0, 1.0), vec2<f32>(1.0, 1.0),
vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 1.0), vec2<f32>(1.0, 0.0)
);
@vertex fn vertMain(input : VertInput) -> VertOutput {
@@ -368,8 +367,7 @@ fn computeEffect (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scre
var i = i32(input.index);
var quadIndex = i / NUM_VERTICES_PER_QUAD;
// var quadCorner = quadCorners[i % NUM_VERTICES_PER_QUAD];
var quadCorner = vec2<f32>(f32(i % 2), f32((i + 1) % 6 / 3));
var quadCorner = quadCorners[i % NUM_VERTICES_PER_QUAD];
var quadPosition = vec2<f32>(
f32(quadIndex % i32(quadGridSize.x)),
@@ -487,13 +485,13 @@ fn getBrightness(raindrop : vec4<f32>, effect : vec4<f32>, uv : vec2<f32>, quadD
fn getSymbolUV(symbol : i32) -> vec2<f32> {
var symbolX = symbol % config.glyphTextureGridSize.x;
var symbolY = symbol / config.glyphTextureGridSize.x;
symbolY = config.glyphTextureGridSize.y - symbolY - 1;
return vec2<f32>(f32(symbolX), f32(symbolY));
}
fn getSymbol(cellUV : vec2<f32>, index : i32) -> vec2<f32> {
// resolve UV to cropped position of glyph in MSDF texture
var uv = fract(cellUV * config.gridSize);
uv.y = 1.0 - uv.y; // y-flip
uv -= 0.5;
uv *= clamp(1.0 - config.glyphEdgeCrop, 0.0, 1.0);
uv += 0.5;

View File

@@ -51,7 +51,7 @@ fn getBrightness(uv : vec2<f32>) -> vec4<f32> {
var uv = vec2<f32>(coord) / vec2<f32>(screenSize);
var color = textureSampleLevel( stripeTex, linearSampler, uv, 0.0 ).rgb;
var color = textureSampleLevel( stripeTex, linearSampler, vec2<f32>(uv.x, 1.0 - uv.y), 0.0 ).rgb;
var brightness = getBrightness(uv);