201 lines
4.3 KiB
JavaScript
201 lines
4.3 KiB
JavaScript
|
|
|
||
|
|
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();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|