mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-18 14:19:30 -07:00
Runtime target textures seem to need to be the same format as the canvas current texture. Requires additional investigation.
Created a computeToTexture shader to experiment with writing directly to textures as a means of performing post processing.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import std140 from "./std140.js";
|
import std140 from "./std140.js";
|
||||||
import { getCanvasSize, loadTexture, loadShaderModule, makeUniformBuffer } from "./utils.js";
|
import { getCanvasSize, createRTT, loadTexture, loadShaderModule, makeUniformBuffer } from "./utils.js";
|
||||||
const { mat4, vec3 } = glMatrix;
|
const { mat4, vec3 } = glMatrix;
|
||||||
|
|
||||||
const rippleTypes = {
|
const rippleTypes = {
|
||||||
@@ -25,11 +25,9 @@ export default async (canvas, config) => {
|
|||||||
const canvasConfig = {
|
const canvasConfig = {
|
||||||
device,
|
device,
|
||||||
format: presentationFormat,
|
format: presentationFormat,
|
||||||
size: getCanvasSize(canvas),
|
size: [NaN, NaN],
|
||||||
};
|
};
|
||||||
|
|
||||||
canvasContext.configure(canvasConfig);
|
|
||||||
|
|
||||||
const assets = [
|
const assets = [
|
||||||
loadTexture(device, config.glyphTexURL),
|
loadTexture(device, config.glyphTexURL),
|
||||||
loadShaderModule(device, "shaders/wgsl/rainPass.wgsl"),
|
loadShaderModule(device, "shaders/wgsl/rainPass.wgsl"),
|
||||||
@@ -124,7 +122,7 @@ export default async (canvas, config) => {
|
|||||||
};
|
};
|
||||||
updateCameraBuffer();
|
updateCameraBuffer();
|
||||||
|
|
||||||
const msdfSampler = device.createSampler({
|
const linearSampler = device.createSampler({
|
||||||
magFilter: "linear",
|
magFilter: "linear",
|
||||||
minFilter: "linear",
|
minFilter: "linear",
|
||||||
});
|
});
|
||||||
@@ -192,7 +190,7 @@ export default async (canvas, config) => {
|
|||||||
|
|
||||||
const rainRenderBindGroup = device.createBindGroup({
|
const rainRenderBindGroup = device.createBindGroup({
|
||||||
layout: rainRenderPipeline.getBindGroupLayout(0),
|
layout: rainRenderPipeline.getBindGroupLayout(0),
|
||||||
entries: [configBuffer, timeBuffer, sceneBuffer, msdfSampler, msdfTexture.createView(), cellsBuffer]
|
entries: [configBuffer, timeBuffer, sceneBuffer, linearSampler, msdfTexture.createView(), cellsBuffer]
|
||||||
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
|
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
|
||||||
.map((resource, binding) => ({
|
.map((resource, binding) => ({
|
||||||
binding,
|
binding,
|
||||||
@@ -200,20 +198,12 @@ export default async (canvas, config) => {
|
|||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderToCanvasBindGroup = device.createBindGroup({
|
let rtt, renderToCanvasBindGroup;
|
||||||
layout: renderToCanvasPipeline.getBindGroupLayout(0),
|
|
||||||
entries: [msdfSampler, msdfTexture.createView()]
|
|
||||||
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
|
|
||||||
.map((resource, binding) => ({
|
|
||||||
binding,
|
|
||||||
resource,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
const rainRenderPassConfig = {
|
const rainRenderPassConfig = {
|
||||||
colorAttachments: [
|
colorAttachments: [
|
||||||
{
|
{
|
||||||
view: canvasContext.getCurrentTexture().createView(),
|
view: null,
|
||||||
loadValue: { r: 0, g: 0, b: 0, a: 1 },
|
loadValue: { r: 0, g: 0, b: 0, a: 1 },
|
||||||
storeOp: "store",
|
storeOp: "store",
|
||||||
},
|
},
|
||||||
@@ -223,7 +213,7 @@ export default async (canvas, config) => {
|
|||||||
const renderToCanvasPassConfig = {
|
const renderToCanvasPassConfig = {
|
||||||
colorAttachments: [
|
colorAttachments: [
|
||||||
{
|
{
|
||||||
view: canvasContext.getCurrentTexture().createView(),
|
view: null,
|
||||||
loadValue: { r: 0, g: 0, b: 0, a: 1 },
|
loadValue: { r: 0, g: 0, b: 0, a: 1 },
|
||||||
storeOp: "store",
|
storeOp: "store",
|
||||||
},
|
},
|
||||||
@@ -238,7 +228,18 @@ export default async (canvas, config) => {
|
|||||||
canvasConfig.size = canvasSize;
|
canvasConfig.size = canvasSize;
|
||||||
canvasContext.configure(canvasConfig);
|
canvasContext.configure(canvasConfig);
|
||||||
|
|
||||||
// TODO: destroy and recreate all screen size textures
|
rtt = createRTT(adapter, device, canvasContext);
|
||||||
|
rainRenderPassConfig.colorAttachments[0].view = rtt.createView();
|
||||||
|
|
||||||
|
renderToCanvasBindGroup = device.createBindGroup({
|
||||||
|
layout: renderToCanvasPipeline.getBindGroupLayout(0),
|
||||||
|
entries: [linearSampler, rtt.createView()]
|
||||||
|
.map((resource) => (resource instanceof GPUBuffer ? { buffer: resource } : resource))
|
||||||
|
.map((resource, binding) => ({
|
||||||
|
binding,
|
||||||
|
resource,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
updateCameraBuffer();
|
updateCameraBuffer();
|
||||||
}
|
}
|
||||||
@@ -254,19 +255,18 @@ export default async (canvas, config) => {
|
|||||||
rainComputePass.dispatch(Math.ceil(gridSize[0] / 32), gridSize[1], 1);
|
rainComputePass.dispatch(Math.ceil(gridSize[0] / 32), gridSize[1], 1);
|
||||||
rainComputePass.endPass();
|
rainComputePass.endPass();
|
||||||
|
|
||||||
rainRenderPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
|
|
||||||
const rainRenderPass = encoder.beginRenderPass(rainRenderPassConfig);
|
const rainRenderPass = encoder.beginRenderPass(rainRenderPassConfig);
|
||||||
rainRenderPass.setPipeline(rainRenderPipeline);
|
rainRenderPass.setPipeline(rainRenderPipeline);
|
||||||
rainRenderPass.setBindGroup(0, rainRenderBindGroup);
|
rainRenderPass.setBindGroup(0, rainRenderBindGroup);
|
||||||
rainRenderPass.draw(numVerticesPerQuad * numQuads, 1, 0, 0);
|
rainRenderPass.draw(numVerticesPerQuad * numQuads, 1, 0, 0);
|
||||||
rainRenderPass.endPass();
|
rainRenderPass.endPass();
|
||||||
|
|
||||||
// renderToCanvasPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
|
renderToCanvasPassConfig.colorAttachments[0].view = canvasContext.getCurrentTexture().createView();
|
||||||
// const renderToCanvasPass = encoder.beginRenderPass(renderToCanvasPassConfig);
|
const renderToCanvasPass = encoder.beginRenderPass(renderToCanvasPassConfig);
|
||||||
// renderToCanvasPass.setPipeline(renderToCanvasPipeline);
|
renderToCanvasPass.setPipeline(renderToCanvasPipeline);
|
||||||
// renderToCanvasPass.setBindGroup(0, renderToCanvasBindGroup);
|
renderToCanvasPass.setBindGroup(0, renderToCanvasBindGroup);
|
||||||
// renderToCanvasPass.draw(numVerticesPerQuad, 1, 0, 0);
|
renderToCanvasPass.draw(numVerticesPerQuad, 1, 0, 0);
|
||||||
// renderToCanvasPass.endPass();
|
renderToCanvasPass.endPass();
|
||||||
|
|
||||||
const commandBuffer = encoder.finish();
|
const commandBuffer = encoder.finish();
|
||||||
device.queue.submit([commandBuffer]);
|
device.queue.submit([commandBuffer]);
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ const loadTexture = async (device, url) => {
|
|||||||
return texture;
|
return texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createRTT = (adapter, device, canvasContext) => {
|
||||||
|
return device.createTexture({
|
||||||
|
size: [...getCanvasSize(canvasContext.canvas), 1],
|
||||||
|
format: canvasContext.getPreferredFormat(adapter),
|
||||||
|
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT// TODO: reduce
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const loadShaderModule = async (device, url) => {
|
const loadShaderModule = async (device, url) => {
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
const code = await response.text();
|
const code = await response.text();
|
||||||
@@ -46,4 +54,4 @@ const makeUniformBuffer = (device, structLayout, values = null) => {
|
|||||||
return buffer;
|
return buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getCanvasSize, loadTexture, loadShaderModule, makeUniformBuffer };
|
export { getCanvasSize, loadTexture, createRTT, loadShaderModule, makeUniformBuffer };
|
||||||
|
|||||||
23
shaders/wgsl/computeToTexture.wgsl
Normal file
23
shaders/wgsl/computeToTexture.wgsl
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[[block]] struct Time {
|
||||||
|
seconds : f32;
|
||||||
|
frames : i32;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var textureSampler : sampler;
|
||||||
|
[[group(0), binding(1)]] var inputTex : texture_2d<f32>;
|
||||||
|
[[group(0), binding(2)]] var outputTex : texture_storage_2d<rgba8unorm, write>;
|
||||||
|
|
||||||
|
// Compute shader
|
||||||
|
|
||||||
|
[[stage(compute), workgroup_size(32, 1, 1)]] fn computeMain([[builtin(global_invocation_id)]] id : vec3<u32>) {
|
||||||
|
var row = i32(id.y);
|
||||||
|
var column = i32(id.x);
|
||||||
|
|
||||||
|
if (column >= i32(textureDimensions(inputTex).x)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var color = textureSampleLevel(inputTex, textureSampler, vec2<f32>(f32(column), f32(row)), 0.0);
|
||||||
|
color.g = color.r;
|
||||||
|
textureStore(outputTex, vec2<i32>(column, row), color);
|
||||||
|
}
|
||||||
@@ -13,5 +13,5 @@ struct VertOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[stage(fragment)]] fn fragMain(input : VertOutput) -> [[location(0)]] vec4<f32> {
|
[[stage(fragment)]] fn fragMain(input : VertOutput) -> [[location(0)]] vec4<f32> {
|
||||||
return textureSample(inputTexture, inputSampler, input.uv);
|
return textureSample(inputTexture, inputSampler, vec2<f32>(input.uv.x, 1.0 - input.uv.y));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user