First Commit

This commit is contained in:
2025-12-25 10:57:33 +01:00
commit f6a2cac364
672 changed files with 75678 additions and 0 deletions

357
rayTracingWebGpuWasm.js Normal file
View File

@@ -0,0 +1,357 @@
import Shader from "../framework/WebGpu.js";
import Matrix4 from "../framework/Matrix4.js";
import Vector3 from "../framework/Vector3.js";
import Camera from "../framework/Camera.js";
import EventManager from "../framework/eventManager.js";
import ShaderInpector from "../framework/ShaderInpector.js";
import WasmModule from "./wasm_renderer.js";
export class ParticleSimulation {
canvas;
device;
camera;
eventManager = new EventManager();
frameCount = 0;
wasm;
framebufferPtr;
framebufferUint8;
frameBufferTexture;
fbSampler;
width;
height;
renderShader;
time = 0;
lastTime = 0;
lastFrameTime;
setCanvas ( canvas ) {
this.canvas = canvas;
this.eventManager.setCanvas( canvas );
}
createPlane ( width, height, repeatU, repeatV ) {
const vertices = new Float32Array( new Array(
-width / 2, -height / 2, 0,
width / 2, -height / 2, 0,
-width / 2, height / 2, 0,
width / 2, -height / 2, 0,
width / 2, height / 2, 0,
-width / 2, height / 2, 0
) );
const uvs = new Float32Array( new Array(
0, 0,
repeatU, 0,
0, repeatV,
repeatU, 0,
repeatU, repeatV,
0, repeatV
) );
const result = {
vertices: vertices,
normals: null,
uvs: uvs
};
return result;
}
async setup ( offscreenCanvas, width, height ) {
this.fpsElement = document.getElementById( "fps" );
this.width = width;
this.height = height;
offscreenCanvas.width = width;
offscreenCanvas.height = height;
this.canvas = offscreenCanvas;
const context = offscreenCanvas.getContext( "webgpu" );
this.camera = new Camera( new Array( 0, 0, 1115 ), new Array( 0, -0.3, 0 ), new Array( 0, 1, 0 ) );
this.eventManager.setup( offscreenCanvas, this.camera );
const adapter = await navigator.gpu.requestAdapter();
if ( adapter === null ) {
throw new Error( "Failed to get GPU adapter" );
}
this.device = await adapter.requestDevice();
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device: this.device,
format: presentationFormat,
alphaMode: "opaque"
});
this.renderShader = new Shader( this.device );
this.renderShader.setCanvas( this.canvas );
this.wasm = await WasmModule();
this.wasm._set_resolution( width, height );
this.framebufferPtr = this.wasm._get_framebuffer_ptr();
this.framebufferUint8 = new Uint8Array(
this.wasm.HEAPU8.buffer,
this.framebufferPtr,
width * height * 4
);
this.frameBufferTexture = this.device.createTexture({
size: [ width, height, 1 ],
format: "rgba8unorm",
usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING
});
this.fbSampler = this.device.createSampler({
magFilter: "nearest",
minFilter: "nearest",
addressModeU: "clamp-to-edge",
addressModeV: "clamp-to-edge"
});
const plane = this.createPlane( 1800, 1800, 1, 1 );
this.renderShader.setAttribute( "position", plane.vertices );
this.renderShader.setAttribute( "uv", plane.uvs );
this.vertexCount = plane.vertices.length / 3;
this.renderShader.topology = "triangle-list";
await this.renderShader.setup( "../shaders/triangle-list-texture-solid.wgsl" );
this.renderShader.setVariable( "mySampler", this.fbSampler );
this.renderShader.setVariable( "myTexture", this.frameBufferTexture );
await this.setupFxaa();
await this.setupTaa();
this.lastFrameTime = performance.now();
this.bindRenderLoop();
}
async setupFxaa() {
this.fxaaShader = new Shader(this.device);
this.fxaaShader.setCanvas(this.canvas);
const fullscreenQuad = this.createPlane(2, 2, 1, 1); // covers NDC [-1,1]
this.fxaaShader.setAttribute("position", fullscreenQuad.vertices);
this.fxaaShader.setAttribute("uv", fullscreenQuad.uvs);
this.fxaaShader.topology = "triangle-list";
await this.fxaaShader.setup("../shaders/fxaa.wgsl");
this.fxaaShader.setVariable("mySampler", this.fbSampler);
this.fxaaShader.setVariable("myTexture", this.frameBufferTexture);
this.fxaaShader.setVariable("resolution", new Float32Array([this.width, this.height]));
}
updateTimeDelta () {
const now = performance.now();
this.deltaTimeValue = ( now - this.lastFrameTime ) / 1000;
this.time += this.deltaTimeValue;
this.lastFrameTime = now;
this.frameCount++;
if ( now - this.lastTime >= 1000 ) {
const fps = this.frameCount / ( ( now - this.lastTime ) / 1000 );
const fpsText = "FPS: " + fps.toFixed( 1 );
this.fpsElement.textContent = fpsText;
this.frameCount = 0;
this.lastTime = now;
}
}
async render () {
this.updateTimeDelta();
this.wasm._update_framebuffer( this.time );
this.device.queue.writeTexture(
{ texture: this.frameBufferTexture },
this.framebufferUint8,
{
bytesPerRow: this.width * 4
},
{
width: this.width,
height: this.height,
depthOrArrayLayers: 1
}
);
/*
const viewMatrix = this.camera.getViewMatrix();
const projectionMatrix = Matrix4.createProjectionMatrix( this.camera, this.canvas );
const viewProjectionMatrix = Matrix4.multiply( projectionMatrix, viewMatrix );
const cameraWorldMatrix = Matrix4.invert( viewMatrix );
const cameraPosition = Matrix4.getColumn( cameraWorldMatrix, 3 );
this.renderShader.setVariable( "viewProjectionMatrix", viewProjectionMatrix );
this.renderShader.renderToCanvas( this.vertexCount, 1, 0 );
*/
this.fxaaShader.renderToCanvas(6, 1, 0);
}
renderTaa() {
const prevIndex = this.currentHistoryIndex;
const nextIndex = 1 - prevIndex;
// Set framebuffer into history
this.device.queue.writeTexture(
{ texture: this.historyTextures[nextIndex] },
this.framebufferUint8,
{ bytesPerRow: this.width * 4 },
{ width: this.width, height: this.height, depthOrArrayLayers: 1 }
);
// Apply TAA blend
this.taaShader.setVariable("currentFrame", this.historyTextures[nextIndex]);
this.taaShader.setVariable("historyFrame", this.historyTextures[prevIndex]);
this.taaShader.renderToCanvas(6, 1, 0);
// Swap history
this.currentHistoryIndex = nextIndex;
}
async setupTaa() {
this.taaShader = new Shader(this.device);
this.taaShader.setCanvas(this.canvas);
const quad = this.createPlane(2, 2, 1, 1);
this.taaShader.setAttribute("position", quad.vertices);
this.taaShader.setAttribute("uv", quad.uvs);
this.taaShader.topology = "triangle-list";
await this.taaShader.setup("../shaders/taa.wgsl");
this.taaShader.setVariable("mySampler", this.fbSampler);
this.taaShader.setVariable("blendAmount", new Float32Array([0.1])); // you can tweak this
this.historyTextures = [
this.frameBufferTexture,
this.device.createTexture({
size: [this.width, this.height, 1],
format: "rgba8unorm",
usage:
GPUTextureUsage.COPY_DST |
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.RENDER_ATTACHMENT
})
];
this.currentHistoryIndex = 0;
}
bindRenderLoop () {
requestAnimationFrame( this.loop.bind( this ) );
}
async loop () {
await this.render();
this.bindRenderLoop();
}
}