even more webgpu stuff

This commit is contained in:
41666 2023-10-07 23:19:49 -04:00
parent 7da1fa8366
commit 96e992467f
14 changed files with 8421 additions and 30 deletions

View file

@ -1,9 +1,14 @@
import { WebGPUApp } from "../renderer/webgpu";
import Torus from "../meshes/torus";
import { MeshRenderer } from "../renderer/mesh-renderer";
const app = new WebGPUApp({ fov: 20 });
app.start();
// TODO:
// - plane
// - torus!
// - white shader
// - real shader with UVs and uniforms
const torusRenderer = new MeshRenderer(app, Torus);
app.start();

View file

@ -11,7 +11,7 @@ struct v2f {
}
@vertex
fn vertex_main(
fn main(
@builtin(position) position : vec4f,
@location(0) uv : vec2f,
) -> v2f {
@ -19,7 +19,7 @@ fn vertex_main(
}
@fragment
fn fragment_main(
fn main(
@location(0) uv : vec2f,
) -> @location(0) vec4f {
f32 zComponent = sin(uniforms.time) * 0.001 * 0.5 + 0.5;

1805
src/meshes/torus.ply Normal file

File diff suppressed because it is too large Load diff

6383
src/meshes/torus.ts Normal file

File diff suppressed because it is too large Load diff

15
src/renderer/behavior.ts Normal file
View file

@ -0,0 +1,15 @@
import { WebGPUApp } from "./webgpu";
export abstract class Behavior {
constructor(public app: WebGPUApp) {
this.onBeforeUpdate && app.onBeforeUpdate(this.onBeforeUpdate.bind(this));
this.onUpdate && app.onUpdate(this.onUpdate.bind(this));
this.onAfterUpdate && app.onAfterUpdate(this.onAfterUpdate.bind(this));
this.onStart && app.onStart(this.onStart.bind(this));
}
onStart(time: number) {}
onBeforeUpdate(time: number) {}
onUpdate(time: number) {}
onAfterUpdate(time: number) {}
}

View file

@ -0,0 +1,24 @@
import { Behavior } from "./behavior";
import { Mesh } from "./mesh";
import { WebGPUApp } from "./webgpu";
export class MeshRenderer extends Behavior {
private depthTexture?: GPUTexture;
private uniformBuffer?: GPUBuffer;
private texture?: GPUTexture;
private sampler?: GPUSampler;
private uniformBindGroup?: GPUBindGroup;
private renderPassDescriptor?: GPURenderBundleDescriptor;
constructor(
public app: WebGPUApp,
public mesh: Mesh
) {
super(app);
}
onStart() {
console.log("hello from meshrenderer!");
console.log(`i've got a ${this.mesh.constructor.name}`);
}
onUpdate(time: number) {}
}

View file

@ -1,16 +1,86 @@
import { Oops, Shader } from "./shader";
import { WebGPUApp } from "./webgpu";
export type MeshConfig = {
vertexData: Float32Array;
vertexSize: number;
positionOffset: number;
colorOffset: number;
uvOffset: number;
mesh: Float32Array;
positionSize: number;
colorSize: number;
uvSize: number;
};
export class Mesh {
private shader: Shader = Oops;
private _shader: Shader = Oops;
constructor(public config: MeshConfig) {}
shader(shader: Shader) {}
shader(shader: Shader) {
this._shader = shader;
return this;
}
buffer(app: WebGPUApp) {
const buffer = app.device.createBuffer({
size: this.config.mesh.byteLength,
usage: GPUBufferUsage.VERTEX,
mappedAtCreation: true,
});
new Float32Array(buffer.getMappedRange()).set(this.config.mesh);
buffer.unmap();
return buffer;
}
pipeline(app: WebGPUApp, config: Record<string, any>) {
const module = this._shader.module(app);
return app.device.createRenderPipeline({
layout: "auto",
vertex: {
module,
entryPoint: "main",
buffers: [
{
arrayStride: 4,
attributes: [
{
// position
shaderLocation: 0,
offset: 0,
format: "float32x4",
},
{
// color
shaderLocation: 2,
offset: this.config.positionSize,
format: "float32x4",
},
{
// uv
shaderLocation: 1,
offset: this.config.positionSize + this.config.colorSize,
format: "float32x4",
},
],
},
],
},
fragment: {
module,
entryPoint: "main",
targets: [
{
format: "rgba8unorm",
},
],
},
primitive: {
topology: "triangle-list",
cullMode: config.cullMode ?? "back",
},
depthStencil: config.stencil && {
depthWriteEnabled: true,
depthCompare: "less",
format: "depth24plus",
},
});
}
}

View file

@ -1,6 +1,7 @@
import { Behavior } from "./behavior";
import { WebGPUApp } from "./webgpu";
export class Telemetry {
export class Telemetry extends Behavior {
public el: HTMLElement;
public frameTimes: number[] = [];
public maxFrameTimes: number = 100;
@ -9,11 +10,10 @@ export class Telemetry {
public app: WebGPUApp,
selector = "#telemetry"
) {
super(app);
this.el = document.querySelector(selector) as HTMLElement;
if (this.el && location.search.includes("telemetry")) {
this.el.style.display = "block";
this.app.onAfterUpdate((time) => this.onAfterUpdate(time));
this.app.onStart(() => this.onStart());
}
}
@ -28,18 +28,14 @@ export class Telemetry {
onStart() {
this.lastFrameTime = 0;
this.frameTimes = [];
}
onAfterUpdate(time: number) {
const frameTime = time - this.lastFrameTime;
this.insertTime(frameTime);
setInterval(() => {
const averageFrameTime =
this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
const averageFrameTime =
this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
const framesPerSecond = 1000 / averageFrameTime;
const framesPerSecond = 1000 / averageFrameTime;
this.el.innerHTML = `
this.el.innerHTML = `
${framesPerSecond.toFixed(1)} FPS (${averageFrameTime.toFixed(
3
)} ms)<br />
@ -47,7 +43,12 @@ export class Telemetry {
this.app.registry.onUpdate.length
} | aU: ${this.app.registry.onAfterUpdate.length}
`;
}, 1000);
}
onAfterUpdate(time: number) {
const frameTime = time - this.lastFrameTime;
this.insertTime(frameTime);
this.lastFrameTime = time;
}
}