145 lines
4.3 KiB
JavaScript
145 lines
4.3 KiB
JavaScript
import { getPathText } from "./common.js"
|
|
|
|
// Triangle vertices, one vertex per line. Hand-transcribed from a
|
|
// .obj file exported from Blender to this form.
|
|
//
|
|
// I've also written myriad scripts to do this automatically for
|
|
// larger models.
|
|
//
|
|
// Float32Array is a fairly convenient way to convert floating point
|
|
// literals to bytes.
|
|
const triangleVertices = new Float32Array([
|
|
// [position ] [texture ] [normal ]
|
|
0.0, 1.0, 0.0, 0.5, 1.0, 0.0, 1.0, 0.0,
|
|
1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
|
|
-1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
|
]);
|
|
|
|
class TriangleRenderer {
|
|
constructor(device, canvasFormat, wgsl)
|
|
{
|
|
const label = "TriangleRenderer";
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// shader module
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const shaderModule = device.createShaderModule({
|
|
label: `${label} shader`,
|
|
code: wgsl,
|
|
});
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// pipeline
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// "bind group layouts" are a declaration of which `var` bindings
|
|
// exist in the shader programs loaded by this pipeline
|
|
//
|
|
// None are used in triangle.wgsl, so this list is empty.
|
|
const bindGroupLayouts = [
|
|
];
|
|
|
|
const pipelineLayout = device.createPipelineLayout({
|
|
label: `${label} pipeline layout`,
|
|
bindGroupLayouts: bindGroupLayouts,
|
|
});
|
|
|
|
// vertexBufferLayouts describes the position of each element for
|
|
// each buffer. There is only one vertex buffer used in this demo,
|
|
// so there is only one vertex buffer layout in this list.
|
|
//
|
|
// shaderLocation matches the location numbers defined in
|
|
// triangle.wgsl.
|
|
//
|
|
// "offset" is the starting offset in bytes, 4 bytes per floating
|
|
// point number. This matches the arrangement in bytes of the
|
|
// triangleVertices Float32Array.
|
|
const arrayStride = (4 * 3) + (4 * 2) + (4 * 3);
|
|
const vertexBufferLayouts = [
|
|
{
|
|
arrayStride: arrayStride,
|
|
attributes: [{
|
|
format: "float32x3",
|
|
offset: 0,
|
|
shaderLocation: 0,
|
|
}, {
|
|
format: "float32x2",
|
|
offset: 12,
|
|
shaderLocation: 1,
|
|
}, {
|
|
format: "float32x3",
|
|
offset: 20,
|
|
shaderLocation: 2,
|
|
}],
|
|
},
|
|
];
|
|
|
|
this.renderPipeline = device.createRenderPipeline({
|
|
label: `${label} render pipeline`,
|
|
layout: pipelineLayout,
|
|
vertex: {
|
|
module: shaderModule,
|
|
entryPoint: "vertexMain",
|
|
buffers: vertexBufferLayouts,
|
|
},
|
|
fragment: {
|
|
module: shaderModule,
|
|
entryPoint: "fragmentMain",
|
|
targets: [{
|
|
format: canvasFormat,
|
|
}]
|
|
},
|
|
primitive: {
|
|
topology: "triangle-list",
|
|
},
|
|
depthStencil: {
|
|
depthWriteEnabled: true,
|
|
depthCompare: "less",
|
|
format: "depth24plus",
|
|
},
|
|
});
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// bind group
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// there are no bind groups, because triangle.wgsl doesn't use any.
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// buffer
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
this.vertexBuffer = device.createBuffer({
|
|
label: `${label} vertex buffer`,
|
|
size: triangleVertices.byteLength,
|
|
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
|
});
|
|
|
|
// copy the (system RAM) triangleVertices to the (gpu RAM) vertexBuffer.
|
|
device.queue.writeBuffer(this.vertexBuffer, 0, triangleVertices);
|
|
}
|
|
|
|
render(renderPass)
|
|
{
|
|
renderPass.setPipeline(this.renderPipeline);
|
|
renderPass.setVertexBuffer(0, this.vertexBuffer);
|
|
const vertexCount = 3;
|
|
renderPass.draw(vertexCount);
|
|
}
|
|
}
|
|
|
|
// This "loadTriangleRenderer" function is separate from the
|
|
// constructor because Javascript class constructors can't be async
|
|
// functions.
|
|
async function loadTriangleRenderer(device, canvasFormat)
|
|
{
|
|
const triangleWgsl = await getPathText("triangle.wgsl");
|
|
|
|
const renderer = new TriangleRenderer(device, canvasFormat, triangleWgsl);
|
|
|
|
return renderer;
|
|
}
|
|
|
|
export { loadTriangleRenderer };
|