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"; export class ParticleSimulation { canvas; device; camera; useLocalSort = true; eventManager = new EventManager(); frameCount = 0; setCanvas( canvas ) { this.canvas = canvas; this.eventManager.setCanvas( canvas ); } async setup( offscreenCanvas, width, height ) { offscreenCanvas.width = width; offscreenCanvas.height = height; this.canvas = offscreenCanvas; const context = offscreenCanvas.getContext("webgpu"); this.camera = new Camera( [0, 0, 1115], [0, -.3, 0], [0, 1, 0] ); this.eventManager.setup( offscreenCanvas, this.camera ); const adapter = await self.navigator.gpu.requestAdapter(); if ( !adapter ) { throw new Error("Failed to get GPU adapter"); } const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); this.device = await adapter.requestDevice(); this.renderShader = new Shader( this.device ); context.configure({ device: this.device, format: presentationFormat, alphaMode: "opaque" }); var model = await this.loadJSON("demo.json"); var mesh = model.meshes[0]; console.log( mesh ); const vertices = new Float32Array([ 0.0, 0.5, // 0 - top outer point 0.1123, 0.1545, // 1 - inner point between top and right 0.4755, 0.1545, // 2 - right outer point 0.1816, -0.0590, // 3 - inner point between right and bottom right 0.2939, -0.4045, // 4 - bottom right outer point 0.0, -0.1909, // 5 - inner bottom point -0.2939,-0.4045, // 6 - bottom left outer point -0.1816, -0.0590,// 7 - inner point between bottom left and left -0.4755, 0.1545, // 8 - left outer point -0.1123, 0.1545, // 9 - inner point between left and top ]); const indices = new Uint16Array([ 0, 1, 9, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 1, 3, 5, 1, 5, 7, 1, 7, 9, ]); const instanceCount = 100; const instancePositions = new Float32Array(instanceCount * 4); // vec4 per instance for (let i = 0; i < instanceCount; i++) { const x = (i % 10) * 300.0; const y = Math.floor(i / 10) * 350.0; instancePositions[i * 4 + 0] = x - 500; instancePositions[i * 4 + 1] = 0; instancePositions[i * 4 + 2] = y - 500; instancePositions[i * 4 + 3] = 0; } this.renderShader.setCanvas( this.canvas ); this.renderShader.topology = "triangle-list"; await this.renderShader.setup( "../../shaders/triangle-list.wgsl"); this.renderShader.setAttribute( "position", mesh.vertices ); this.renderShader.setAttribute( "normal", mesh.normals ); this.renderShader.setVariable( "instancePositions", instancePositions ); var faces = mesh.faces; const indexArray = new Uint32Array(faces.length * 3); for (let i = 0; i < faces.length; i++) { indexArray[i * 3 + 0] = faces[i][0]; indexArray[i * 3 + 1] = faces[i][1]; indexArray[i * 3 + 2] = faces[i][2]; } this.renderShader.setIndices( indexArray ); this.render(); } updateTimeDelta() { const now = performance.now(); this.deltaTimeValue = ( now - this.lastFrameTime ) / 1000; this.lastFrameTime = now; } async render() { this.updateTimeDelta(); const viewMatrixData = this.camera.getViewMatrix(); const projectionMatrixData = Matrix4.createProjectionMatrix( this.camera, this.canvas ) const viewProjectionMatrix = Matrix4.multiply( projectionMatrixData, viewMatrixData ); const cameraWorldMatrix = Matrix4.invert( viewMatrixData ); const cameraPosition = Matrix4.getColumn( cameraWorldMatrix, 3 ); this.renderShader.setVariable( "viewProjectionMatrix", viewProjectionMatrix ); this.renderShader.setVariable( "cameraPosition", cameraPosition ); this.renderShader.renderToCanvas( this.vertexCount, 60, 0 ); this.frameCount++; requestAnimationFrame( this.render.bind( this ) ); } async loadJSON( pathName ) { const response = await fetch( pathName ); if ( !response.ok ){ throw new Error( `Failed to load shader: ${ pathName }` ); } return await response.json(); } }