webgpu-app/index.js

234 lines
5.7 KiB
JavaScript

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);