even more webgpu stuff
This commit is contained in:
parent
7da1fa8366
commit
96e992467f
14 changed files with 8421 additions and 30 deletions
4
build.ts
4
build.ts
|
@ -2,6 +2,7 @@ import chalk from "chalk";
|
||||||
import { generate } from "./generate";
|
import { generate } from "./generate";
|
||||||
import { globSync } from "glob";
|
import { globSync } from "glob";
|
||||||
import { rmSync, mkdirSync, cpSync } from "node:fs";
|
import { rmSync, mkdirSync, cpSync } from "node:fs";
|
||||||
|
import { convertMeshes } from "./convert-meshes";
|
||||||
|
|
||||||
console.log(chalk.green`>> Cleaing up ./html ...`);
|
console.log(chalk.green`>> Cleaing up ./html ...`);
|
||||||
rmSync("html", { recursive: true, force: true });
|
rmSync("html", { recursive: true, force: true });
|
||||||
|
@ -33,3 +34,6 @@ for (const file of publics) {
|
||||||
cpSync(file, dest);
|
cpSync(file, dest);
|
||||||
console.log(chalk.yellow(` -> ${dest}...`));
|
console.log(chalk.yellow(` -> ${dest}...`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(chalk.green`>> Convert meshes ...`);
|
||||||
|
await convertMeshes();
|
||||||
|
|
59
convert-meshes.ts
Normal file
59
convert-meshes.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import chalk from "chalk";
|
||||||
|
import { globSync } from "glob";
|
||||||
|
|
||||||
|
export const convertMeshes = async () => {
|
||||||
|
const meshes = globSync("src/meshes/*.ply");
|
||||||
|
|
||||||
|
for (const file of meshes) {
|
||||||
|
const ply = await Bun.file(file).text();
|
||||||
|
|
||||||
|
const [header, body] = ply.split("end_header");
|
||||||
|
const colorSize = header.includes("red") ? 4 : 0;
|
||||||
|
|
||||||
|
const values: number[] = [];
|
||||||
|
|
||||||
|
for (const line of body.split("\n")) {
|
||||||
|
// line looks like
|
||||||
|
// x y z r g b a u v
|
||||||
|
// We need to convert it to
|
||||||
|
// x y z 1 r g b a u v
|
||||||
|
|
||||||
|
const [x, y, z, r, g, b, a, u, v] = line.split(" ");
|
||||||
|
|
||||||
|
if (!g) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
values.push(
|
||||||
|
parseFloat(x),
|
||||||
|
parseFloat(y),
|
||||||
|
parseFloat(z),
|
||||||
|
1,
|
||||||
|
parseFloat(r),
|
||||||
|
parseFloat(g)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (colorSize > 0) {
|
||||||
|
values.push(parseFloat(b), parseFloat(a), parseFloat(u), parseFloat(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const outFile = file.replace(".ply", ".ts");
|
||||||
|
const outString = `
|
||||||
|
import { Mesh } from "../renderer/mesh";
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const mesh = new Float32Array(${JSON.stringify(values, null, 2)});
|
||||||
|
|
||||||
|
export default new Mesh({
|
||||||
|
mesh,
|
||||||
|
positionSize: 4 * 4,
|
||||||
|
colorSize: ${colorSize} * 4,
|
||||||
|
uvSize: 2 * 4,
|
||||||
|
});
|
||||||
|
`;
|
||||||
|
|
||||||
|
await Bun.write(outFile, outString);
|
||||||
|
console.log(chalk.yellow(` -> ${file}...`));
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
import{a as Y} from"../chunk-0cd54990cab7d3a5.js";class E{constructor(C){this.gl=C.gl,this.app=C,this.program=this.gl.createProgram()}attach(C,D){console.log("attaching shader",{type:C,source:D});const R=this.gl.createShader(C);if(this.gl.shaderSource(R,D),this.gl.compileShader(R),!this.gl.getShaderParameter(R,this.gl.COMPILE_STATUS))throw new Error("An error occurred compiling the shaders: "+this.gl.getShaderInfoLog(R));return this.gl.attachShader(this.program,R),this}link(){if(this.gl.linkProgram(this.program),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw new Error("Unable to initialize the shader program: "+this.gl.getProgramInfoLog(this.program));return console.log("shader linked"),this}location(C){if(C[0]==="a")return this.gl.getAttribLocation(this.program,C);else if(C[0]==="u")return this.gl.getUniformLocation(this.program,C)}updateTime(){const C=this.app.now(),D=Math.sin(C),R=Math.cos(C);this.gl.uniform1f(this.location("uTime"),C),this.gl.uniform1f(this.location("uSinTime"),D),this.gl.uniform1f(this.location("uCosTime"),R)}activate(C,D){this.gl.useProgram(this.program),this.gl.uniformMatrix4fv(this.location("uProjectionMatrix"),!1,C),this.gl.uniformMatrix4fv(this.location("uModelViewMatrix"),!1,D),this.updateTime()}}class I{constructor(C){this.gl=C.gl,this.app=C,this.vertexPositions=new Float32Array([]),this.positionBuffer=null,this.textureBuffer=null}initBuffer(C,D=this.gl.STATIC_DRAW){const R=this.gl.createBuffer();return this.gl.bindBuffer(this.gl.ARRAY_BUFFER,R),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array(C),D),R}attachShader(C){return this.shader=C,this.vertexPosition=C.location("aVertexPosition"),this.textureCoord=C.location("aTextureCoord"),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.gl.vertexAttribPointer(this.vertexPosition,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.vertexPosition),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.textureBuffer),this.gl.vertexAttribPointer(this.textureCoord,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.textureCoord),this}draw2D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/2)}draw3D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/3)}}class K extends I{constructor(C){super(C);this.vertexPositions=new Float32Array([-1,-1,1,-1,-1,1,1,1]),this.positionBuffer=this.initBuffer(this.vertexPositions),this.textureBuffer=this.initBuffer(new Float32Array([0,0,1,0,0,1,1,1])),this.app.onUpdate(()=>this.draw2D())}}class L{constructor(C={fov:45}){if(this._now=0,this.registry={onStart:[],onUpdate:[],onBeforeUpdate:[],onAfterUpdate:[]},this.config=C,this.canvas=document.querySelector("canvas"),this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.gl=this.canvas.getContext("webgl2"),this.gl===null)throw document.querySelector("main").innerHTML="<div><i>your browser didn't let me set up webgl</i></div>",new Error("Unable to initialize WebGL. Your browser or machine may not support it.");const D=this.gl,R=this.config.fov*Math.PI/180,G=D.canvas.clientWidth/D.canvas.clientHeight,H=0.1,J=100,P=glMatrix.mat4.create();glMatrix.mat4.perspective(P,R,G,H,J);const q=glMatrix.mat4.create();glMatrix.mat4.translate(q,q,[-0,0,-6]),this.projectionMatrix=P,this.modelViewMatrix=q,this.clear(),this.onBeforeUpdate(()=>this.clear()),this.telemetry=new Y(this)}clear(){const C=this.gl;C.clearColor(0,0,0,1),C.clearDepth(1),C.enable(C.DEPTH_TEST),C.depthFunc(C.LEQUAL),C.clear(C.COLOR_BUFFER_BIT|C.DEPTH_BUFFER_BIT)}onStart(C){this.registry.onStart.push(C)}onUpdate(C){this.registry.onUpdate.push(C)}onBeforeUpdate(C){this.registry.onBeforeUpdate.push(C)}onAfterUpdate(C){this.registry.onAfterUpdate.push(C)}start(){this.registry.onStart.forEach((C)=>C(this))}update(){this.registry.onBeforeUpdate.forEach((C)=>C(this)),this.registry.onUpdate.forEach((C)=>C(this)),this.registry.onAfterUpdate.forEach((C)=>C(this))}oneShot(){requestAnimationFrame((C)=>{this._now=C,this.start(),this.update()})}loop(){const C=(D)=>{this._now=D,this.update(),requestAnimationFrame(C)};requestAnimationFrame(C)}now(){return this._now}}var k=`precision highp float;
|
import{b as Y} from"../chunk-c8239659df5e5cce.js";class E{constructor(C){this.gl=C.gl,this.app=C,this.program=this.gl.createProgram()}attach(C,D){console.log("attaching shader",{type:C,source:D});const R=this.gl.createShader(C);if(this.gl.shaderSource(R,D),this.gl.compileShader(R),!this.gl.getShaderParameter(R,this.gl.COMPILE_STATUS))throw new Error("An error occurred compiling the shaders: "+this.gl.getShaderInfoLog(R));return this.gl.attachShader(this.program,R),this}link(){if(this.gl.linkProgram(this.program),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw new Error("Unable to initialize the shader program: "+this.gl.getProgramInfoLog(this.program));return console.log("shader linked"),this}location(C){if(C[0]==="a")return this.gl.getAttribLocation(this.program,C);else if(C[0]==="u")return this.gl.getUniformLocation(this.program,C)}updateTime(){const C=this.app.now(),D=Math.sin(C),R=Math.cos(C);this.gl.uniform1f(this.location("uTime"),C),this.gl.uniform1f(this.location("uSinTime"),D),this.gl.uniform1f(this.location("uCosTime"),R)}activate(C,D){this.gl.useProgram(this.program),this.gl.uniformMatrix4fv(this.location("uProjectionMatrix"),!1,C),this.gl.uniformMatrix4fv(this.location("uModelViewMatrix"),!1,D),this.updateTime()}}class I{constructor(C){this.gl=C.gl,this.app=C,this.vertexPositions=new Float32Array([]),this.positionBuffer=null,this.textureBuffer=null}initBuffer(C,D=this.gl.STATIC_DRAW){const R=this.gl.createBuffer();return this.gl.bindBuffer(this.gl.ARRAY_BUFFER,R),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array(C),D),R}attachShader(C){return this.shader=C,this.vertexPosition=C.location("aVertexPosition"),this.textureCoord=C.location("aTextureCoord"),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.gl.vertexAttribPointer(this.vertexPosition,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.vertexPosition),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.textureBuffer),this.gl.vertexAttribPointer(this.textureCoord,2,this.gl.FLOAT,!1,0,0),this.gl.enableVertexAttribArray(this.textureCoord),this}draw2D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/2)}draw3D(){this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.shader.activate(this.app.projectionMatrix,this.app.modelViewMatrix),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,this.vertexPositions.length/3)}}class K extends I{constructor(C){super(C);this.vertexPositions=new Float32Array([-1,-1,1,-1,-1,1,1,1]),this.positionBuffer=this.initBuffer(this.vertexPositions),this.textureBuffer=this.initBuffer(new Float32Array([0,0,1,0,0,1,1,1])),this.app.onUpdate(()=>this.draw2D())}}class L{constructor(C={fov:45}){if(this._now=0,this.registry={onStart:[],onUpdate:[],onBeforeUpdate:[],onAfterUpdate:[]},this.config=C,this.canvas=document.querySelector("canvas"),this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.gl=this.canvas.getContext("webgl2"),this.gl===null)throw document.querySelector("main").innerHTML="<div><i>your browser didn't let me set up webgl</i></div>",new Error("Unable to initialize WebGL. Your browser or machine may not support it.");const D=this.gl,R=this.config.fov*Math.PI/180,G=D.canvas.clientWidth/D.canvas.clientHeight,H=0.1,J=100,P=glMatrix.mat4.create();glMatrix.mat4.perspective(P,R,G,H,J);const q=glMatrix.mat4.create();glMatrix.mat4.translate(q,q,[-0,0,-6]),this.projectionMatrix=P,this.modelViewMatrix=q,this.clear(),this.onBeforeUpdate(()=>this.clear()),this.telemetry=new Y(this)}clear(){const C=this.gl;C.clearColor(0,0,0,1),C.clearDepth(1),C.enable(C.DEPTH_TEST),C.depthFunc(C.LEQUAL),C.clear(C.COLOR_BUFFER_BIT|C.DEPTH_BUFFER_BIT)}onStart(C){this.registry.onStart.push(C)}onUpdate(C){this.registry.onUpdate.push(C)}onBeforeUpdate(C){this.registry.onBeforeUpdate.push(C)}onAfterUpdate(C){this.registry.onAfterUpdate.push(C)}start(){this.registry.onStart.forEach((C)=>C(this))}update(){this.registry.onBeforeUpdate.forEach((C)=>C(this)),this.registry.onUpdate.forEach((C)=>C(this)),this.registry.onAfterUpdate.forEach((C)=>C(this))}oneShot(){requestAnimationFrame((C)=>{this._now=C,this.start(),this.update()})}loop(){const C=(D)=>{this._now=D,this.update(),requestAnimationFrame(C)};requestAnimationFrame(C)}now(){return this._now}}var k=`precision highp float;
|
||||||
|
|
||||||
uniform float uTime;
|
uniform float uTime;
|
||||||
uniform float uSinTime;
|
uniform float uSinTime;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,5 +0,0 @@
|
||||||
class j{p;el;frameTimes=[];maxFrameTimes=100;lastFrameTime=0;constructor(p,x="#telemetry"){this.app=p;if(this.el=document.querySelector(x),this.el&&location.search.includes("telemetry"))this.el.style.display="block",this.app.onAfterUpdate((s)=>this.onAfterUpdate(s)),this.app.onStart(()=>this.onStart())}insertTime(p){if(this.frameTimes.push(p),this.frameTimes.length>this.maxFrameTimes)this.frameTimes.shift()}onStart(){this.lastFrameTime=0,this.frameTimes=[]}onAfterUpdate(p){const x=p-this.lastFrameTime;this.insertTime(x);const s=this.frameTimes.reduce((d,h)=>d+h,0)/this.frameTimes.length,$=1000/s;this.el.innerHTML=`
|
|
||||||
${$.toFixed(1)} FPS (${s.toFixed(3)} ms)<br />
|
|
||||||
bU: ${this.app.registry.onBeforeUpdate.length} | U: ${this.app.registry.onUpdate.length} | aU: ${this.app.registry.onAfterUpdate.length}
|
|
||||||
`,this.lastFrameTime=p}}
|
|
||||||
export{j as a};
|
|
5
html/chunk-c8239659df5e5cce.js
Normal file
5
html/chunk-c8239659df5e5cce.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class n{U;constructor(U){this.app=U;this.onBeforeUpdate&&U.onBeforeUpdate(this.onBeforeUpdate.bind(this)),this.onUpdate&&U.onUpdate(this.onUpdate.bind(this)),this.onAfterUpdate&&U.onAfterUpdate(this.onAfterUpdate.bind(this)),this.onStart&&U.onStart(this.onStart.bind(this))}onStart(U){}onBeforeUpdate(U){}onUpdate(U){}onAfterUpdate(U){}}class k extends n{U;el;frameTimes=[];maxFrameTimes=100;lastFrameTime=0;constructor(U,h="#telemetry"){super(U);this.app=U;if(this.el=document.querySelector(h),this.el&&location.search.includes("telemetry"))this.el.style.display="block"}insertTime(U){if(this.frameTimes.push(U),this.frameTimes.length>this.maxFrameTimes)this.frameTimes.shift()}onStart(){this.lastFrameTime=0,this.frameTimes=[],setInterval(()=>{const U=this.frameTimes.reduce((L,j)=>L+j,0)/this.frameTimes.length,h=1000/U;this.el.innerHTML=`
|
||||||
|
${h.toFixed(1)} FPS (${U.toFixed(3)} ms)<br />
|
||||||
|
bU: ${this.app.registry.onBeforeUpdate.length} | U: ${this.app.registry.onUpdate.length} | aU: ${this.app.registry.onAfterUpdate.length}
|
||||||
|
`},1000)}onAfterUpdate(U){const h=U-this.lastFrameTime;this.insertTime(h),this.lastFrameTime=U}}
|
||||||
|
export{n as a,k as b};
|
|
@ -1,9 +1,14 @@
|
||||||
import { WebGPUApp } from "../renderer/webgpu";
|
import { WebGPUApp } from "../renderer/webgpu";
|
||||||
|
import Torus from "../meshes/torus";
|
||||||
|
import { MeshRenderer } from "../renderer/mesh-renderer";
|
||||||
|
|
||||||
const app = new WebGPUApp({ fov: 20 });
|
const app = new WebGPUApp({ fov: 20 });
|
||||||
|
|
||||||
app.start();
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - plane
|
// - torus!
|
||||||
// - white shader
|
// - white shader
|
||||||
// - real shader with UVs and uniforms
|
// - real shader with UVs and uniforms
|
||||||
|
|
||||||
|
const torusRenderer = new MeshRenderer(app, Torus);
|
||||||
|
|
||||||
|
app.start();
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct v2f {
|
||||||
}
|
}
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vertex_main(
|
fn main(
|
||||||
@builtin(position) position : vec4f,
|
@builtin(position) position : vec4f,
|
||||||
@location(0) uv : vec2f,
|
@location(0) uv : vec2f,
|
||||||
) -> v2f {
|
) -> v2f {
|
||||||
|
@ -19,7 +19,7 @@ fn vertex_main(
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fragment_main(
|
fn main(
|
||||||
@location(0) uv : vec2f,
|
@location(0) uv : vec2f,
|
||||||
) -> @location(0) vec4f {
|
) -> @location(0) vec4f {
|
||||||
f32 zComponent = sin(uniforms.time) * 0.001 * 0.5 + 0.5;
|
f32 zComponent = sin(uniforms.time) * 0.001 * 0.5 + 0.5;
|
||||||
|
|
1805
src/meshes/torus.ply
Normal file
1805
src/meshes/torus.ply
Normal file
File diff suppressed because it is too large
Load diff
6383
src/meshes/torus.ts
Normal file
6383
src/meshes/torus.ts
Normal file
File diff suppressed because it is too large
Load diff
15
src/renderer/behavior.ts
Normal file
15
src/renderer/behavior.ts
Normal 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) {}
|
||||||
|
}
|
24
src/renderer/mesh-renderer.ts
Normal file
24
src/renderer/mesh-renderer.ts
Normal 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) {}
|
||||||
|
}
|
|
@ -1,16 +1,86 @@
|
||||||
import { Oops, Shader } from "./shader";
|
import { Oops, Shader } from "./shader";
|
||||||
|
import { WebGPUApp } from "./webgpu";
|
||||||
|
|
||||||
export type MeshConfig = {
|
export type MeshConfig = {
|
||||||
vertexData: Float32Array;
|
mesh: Float32Array;
|
||||||
vertexSize: number;
|
positionSize: number;
|
||||||
positionOffset: number;
|
colorSize: number;
|
||||||
colorOffset: number;
|
uvSize: number;
|
||||||
uvOffset: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Mesh {
|
export class Mesh {
|
||||||
private shader: Shader = Oops;
|
private _shader: Shader = Oops;
|
||||||
|
|
||||||
constructor(public config: MeshConfig) {}
|
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",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import { Behavior } from "./behavior";
|
||||||
import { WebGPUApp } from "./webgpu";
|
import { WebGPUApp } from "./webgpu";
|
||||||
|
|
||||||
export class Telemetry {
|
export class Telemetry extends Behavior {
|
||||||
public el: HTMLElement;
|
public el: HTMLElement;
|
||||||
public frameTimes: number[] = [];
|
public frameTimes: number[] = [];
|
||||||
public maxFrameTimes: number = 100;
|
public maxFrameTimes: number = 100;
|
||||||
|
@ -9,11 +10,10 @@ export class Telemetry {
|
||||||
public app: WebGPUApp,
|
public app: WebGPUApp,
|
||||||
selector = "#telemetry"
|
selector = "#telemetry"
|
||||||
) {
|
) {
|
||||||
|
super(app);
|
||||||
this.el = document.querySelector(selector) as HTMLElement;
|
this.el = document.querySelector(selector) as HTMLElement;
|
||||||
if (this.el && location.search.includes("telemetry")) {
|
if (this.el && location.search.includes("telemetry")) {
|
||||||
this.el.style.display = "block";
|
this.el.style.display = "block";
|
||||||
this.app.onAfterUpdate((time) => this.onAfterUpdate(time));
|
|
||||||
this.app.onStart(() => this.onStart());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +28,8 @@ export class Telemetry {
|
||||||
onStart() {
|
onStart() {
|
||||||
this.lastFrameTime = 0;
|
this.lastFrameTime = 0;
|
||||||
this.frameTimes = [];
|
this.frameTimes = [];
|
||||||
}
|
|
||||||
|
|
||||||
onAfterUpdate(time: number) {
|
|
||||||
const frameTime = time - this.lastFrameTime;
|
|
||||||
this.insertTime(frameTime);
|
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
const averageFrameTime =
|
const averageFrameTime =
|
||||||
this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
|
this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
|
||||||
|
|
||||||
|
@ -47,7 +43,12 @@ export class Telemetry {
|
||||||
this.app.registry.onUpdate.length
|
this.app.registry.onUpdate.length
|
||||||
} | aU: ${this.app.registry.onAfterUpdate.length}
|
} | aU: ${this.app.registry.onAfterUpdate.length}
|
||||||
`;
|
`;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAfterUpdate(time: number) {
|
||||||
|
const frameTime = time - this.lastFrameTime;
|
||||||
|
this.insertTime(frameTime);
|
||||||
this.lastFrameTime = time;
|
this.lastFrameTime = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue