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 { globSync } from "glob";
|
||||
import { rmSync, mkdirSync, cpSync } from "node:fs";
|
||||
import { convertMeshes } from "./convert-meshes";
|
||||
|
||||
console.log(chalk.green`>> Cleaing up ./html ...`);
|
||||
rmSync("html", { recursive: true, force: true });
|
||||
|
@ -33,3 +34,6 @@ for (const file of publics) {
|
|||
cpSync(file, 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 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 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();
|
||||
|
|
|
@ -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
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 { 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",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue