234 lines
5.7 KiB
JavaScript
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);
|