import { getPath } from "./common.js"; import { loadGltf } from "./index2.js"; import { loadLight } from "./light.js"; if (!navigator.gpu) { throw new Error("WebGPU not supported on this browser."); } const adapter = await navigator.gpu.requestAdapter(); if (!adapter) { throw new Error("No WebGPU adapter"); } const device = await adapter.requestDevice(); const canvas = document.querySelector("canvas"); canvas.width = canvas.clientWidth canvas.height = canvas.clientHeight const context = canvas.getContext("webgpu"); const canvasFormat = navigator.gpu.getPreferredCanvasFormat(); context.configure({ device: device, format: canvasFormat, }); const encoder = device.createCommandEncoder(); const renderPass = encoder.beginRenderPass({ colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: "clear", clearValue: { r: 0.9, g: 0.5, b: 0.2, a: 1 }, storeOp: "store", }] }); renderPass.end(); const commandBuffer = encoder.finish(); device.queue.submit([commandBuffer]); const memory = new WebAssembly.Memory({ initial: 258 * 2 }); const module = await WebAssembly.instantiateStreaming(fetch("src/module.wasm"), { env: { memory: memory, log: console.log, } }); function createDepthTexture() { return device.createTexture({ size: [canvas.width, canvas.height], format: 'depth24plus', usage: GPUTextureUsage.RENDER_ATTACHMENT, }); } var depthTexture = undefined; const eyeValueX = document.getElementById("eye-value-x"); const eyeValueY = document.getElementById("eye-value-y"); const eyeValueZ = document.getElementById("eye-value-z"); const yawValue = document.getElementById("yaw"); const pitchValue = document.getElementById("pitch"); function recreateDepth() { if (canvas.clientWidth !== canvas.width || canvas.clientWidth !== canvas.height) { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; if (depthTexture !== undefined) { depthTexture.destroy(); } depthTexture = createDepthTexture(); } } const matrixSize = 4 * 4 * 4; const float4Size = 4 * 4; const float3Size = 4 * 3; const viewUniformBufferSize = (matrixSize * 2) + (float4Size * 2); const viewUniformBuffer = device.createBuffer({ label: "view uniform buffer", size: viewUniformBufferSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, }); const cameraStateSize = (float3Size * 3) + (4 * 3) + (float3Size * 1); const viewStateAddress = module.instance.exports.mem_alloc(viewUniformBufferSize); const cameraStateAddress = module.instance.exports.mem_alloc(cameraStateSize); module.instance.exports.camera_init(cameraStateAddress); const gltfRenderer = await loadGltf(device, canvasFormat, viewUniformBuffer, memory, module); const lightRenderer = await loadLight(device, canvasFormat, viewUniformBuffer); const KEY = { A: 65, B: 66, C: 67, D: 68, E: 69, F: 70, G: 71, H: 72, I: 73, J: 74, K: 75, L: 76, M: 77, N: 78, O: 79, P: 80, Q: 81, R: 82, S: 83, T: 84, U: 85, V: 86, W: 87, X: 88, Y: 89, Z: 90, Left: 37, Up: 38, Right: 39, Down: 40, }; const keyCodes = new Set(Object.values(KEY)); const keyState = {}; for (const code of Object.values(KEY)) { keyState[code] = false; } function handleKeydown(e) { //console.log(e.keyCode); if (keyCodes.has(e.keyCode)) { keyState[e.keyCode] = true; } } function handleKeyup(e) { if (keyCodes.has(e.keyCode)) { keyState[e.keyCode] = false; } } window.addEventListener('keydown', handleKeydown, false); window.addEventListener('keyup', handleKeyup, false); function updateView() { const lu = keyState[KEY.W] === true; const ll = keyState[KEY.A] === true; const ld = keyState[KEY.S] === true; const lr = keyState[KEY.D] === true; const lal = keyState[KEY.Q] === true; const lar = keyState[KEY.E] === true; const ru = keyState[KEY.Up] === true; const rl = keyState[KEY.Left] === true; const rd = keyState[KEY.Down] === true; const rr = keyState[KEY.Right] === true; module.instance.exports.camera_move(cameraStateAddress, lu, ll, ld, lr, lal, lar, ru, rl, rd, rr); const aspect = canvas.width / canvas.height; module.instance.exports.camera_view_projection(cameraStateAddress, viewStateAddress, aspect); device.queue.writeBuffer(viewUniformBuffer, 0, memory.buffer, viewStateAddress, viewUniformBufferSize); const cameraStateF32 = new Float32Array(memory.buffer, cameraStateAddress, cameraStateSize); eyeValueX.innerHTML = cameraStateF32[0].toFixed(1); eyeValueY.innerHTML = cameraStateF32[1].toFixed(1); eyeValueZ.innerHTML = cameraStateF32[2].toFixed(1); yawValue.innerHTML = cameraStateF32[9].toFixed(2); pitchValue.innerHTML = cameraStateF32[10].toFixed(2); } function render2() { recreateDepth(); const colorView = context.getCurrentTexture().createView(); updateView(); { const encoder = device.createCommandEncoder(); const renderPass = encoder.beginRenderPass({ colorAttachments: [{ view: colorView, loadOp: "clear", clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 }, storeOp: "store", }], depthStencilAttachment: { view: depthTexture.createView(), depthClearValue: 1.0, depthLoadOp: 'clear', depthStoreOp: 'store', }, }); gltfRenderer.render(renderPass); lightRenderer.render(renderPass); renderPass.end(); const commandBuffer = encoder.finish(); device.queue.submit([commandBuffer]); } requestAnimationFrame(render2); } requestAnimationFrame(render2);