Skip to content

Commit

Permalink
interpret vertex formats from attributes to make shaders for other gl…
Browse files Browse the repository at this point in the history
…bs easier to write
  • Loading branch information
cmhhelgeson committed Jan 31, 2024
1 parent 66c39ac commit 5f9d6d5
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 26 deletions.
Binary file added public/assets/gltf/RiggedSimple.glb
Binary file not shown.
71 changes: 60 additions & 11 deletions src/sample/skinnedMesh/glbUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Mat4, Vec3, mat4 } from 'wgpu-matrix';

//NOTE: GLTF code is not generally extensible to all gltf models
// Modified from Will Usher code found at this link https://www.willusher.io/graphics/2023/05/16/0-to-gltf-first-mesh

// Determines the topology of our pipeline
enum GLTFRenderMode {
POINTS = 0,
Expand Down Expand Up @@ -169,6 +168,45 @@ const gltfElementSize = (
return gltfDataStructureTypeNumComponents(type) * componentSize;
};

// Convert differently depending on if the shader is a vertex or compute shader
const convertGPUVertexFormatToWGSLFormat = (vertexFormat: GPUVertexFormat) => {
switch (vertexFormat) {
case 'float32': {
return 'f32';
}
case 'float32x2': {
return 'vec2<f32>';
}
case 'float32x3': {
return 'vec3<f32>';
}
case 'float32x4': {
return 'vec4<f32>';
}
case 'uint32': {
return 'u32';
}
case 'uint32x2': {
return 'vec2<u32>';
}
case 'uint32x3': {
return 'vec3<u32>';
}
case 'uint32x4': {
return 'vec4<u32>';
}
case 'uint8x2': {
return 'vec2<u32>';
}
case 'uint8x4': {
return 'vec4<u32>';
}
default: {
return 'f32';
}
}
};

export class GLTFBuffer {
buffer: Uint8Array;
constructor(buffer: ArrayBuffer, offset: number, size: number) {
Expand Down Expand Up @@ -292,8 +330,8 @@ export class GLTFPrimitive {

buildRenderPipeline(
device: GPUDevice,
vertexShaderModule: GPUShaderModule,
fragmentShaderModule: GPUShaderModule,
vertexShader: string,
fragmentShader: string,
colorFormat: GPUTextureFormat,
depthFormat: GPUTextureFormat,
bgLayouts: GPUBindGroupLayout[],
Expand All @@ -302,8 +340,14 @@ export class GLTFPrimitive {
// For now, just check if the attributeMap contains a given attribute using map.has(), and add it if it does
// POSITION, NORMAL, TEXCOORD_0, JOINTS_0, WEIGHTS_0 for order
// Vertex attribute state and shader stage
let VertexInputShaderString = `struct VertexInput {\n`;
const vertexBuffers: GPUVertexBufferLayout[] = this.attributes.map(
(attr, idx) => {
const vertexFormat: GPUVertexFormat = this.attributeMap[attr].vertexType;

Check failure on line 346 in src/sample/skinnedMesh/glbUtils.ts

View workflow job for this annotation

GitHub Actions / build

Insert `⏎·········`
const attrString = attr.toLowerCase().replace(/_0$/, '');
VertexInputShaderString += `\t@location(${idx}) ${attrString}: ${convertGPUVertexFormatToWGSLFormat(
vertexFormat
)},\n`;
return {
arrayStride: this.attributeMap[attr].byteStride,
attributes: [
Expand All @@ -313,20 +357,26 @@ export class GLTFPrimitive {
shaderLocation: idx,
},
],
};
} as GPUVertexBufferLayout;
}
);
VertexInputShaderString += '}';
console.log(VertexInputShaderString);

const vertexState: GPUVertexState = {
// Shader stage info
module: vertexShaderModule,
module: device.createShaderModule({
code: VertexInputShaderString + vertexShader,
}),
entryPoint: 'vertexMain',
buffers: vertexBuffers,
};

const fragmentState: GPUFragmentState = {
// Shader info
module: fragmentShaderModule,
module: device.createShaderModule({
code: VertexInputShaderString + fragmentShader,
}),
entryPoint: 'fragmentMain',
// Output render target info
targets: [{ format: colorFormat }],
Expand Down Expand Up @@ -401,8 +451,8 @@ export class GLTFMesh {

buildRenderPipeline(
device: GPUDevice,
vertexShaderModule: GPUShaderModule,
fragmentShaderModule: GPUShaderModule,
vertexShader: string,
fragmentShader: string,
colorFormat: GPUTextureFormat,
depthFormat: GPUTextureFormat,
bgLayouts: GPUBindGroupLayout[]
Expand All @@ -412,8 +462,8 @@ export class GLTFMesh {
for (let i = 0; i < this.primitives.length; ++i) {
this.primitives[i].buildRenderPipeline(
device,
vertexShaderModule,
fragmentShaderModule,
vertexShader,
fragmentShader,
colorFormat,
depthFormat,
bgLayouts,
Expand Down Expand Up @@ -768,7 +818,6 @@ export const convertGLBToJSONAndBinary = async (
);

console.log(jsonChunk);

// Binary data located after jsonChunk
const binaryHeader = new Uint32Array(buffer, 20 + jsonChunkLength, 2);
validateBinaryHeader(binaryHeader);
Expand Down
10 changes: 1 addition & 9 deletions src/sample/skinnedMesh/gltf.wgsl
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
// Whale.glb Vertex attributes
// POSTION, NORMAL, TEXCOORD_0, JOINTS_0, WEIGHTS_0
// Read in VertexInput from attributes
// f32x3 f32x3 f32x2 u8x4 f32x4
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) normal: vec3<f32>,
@location(2) texcoord: vec2<f32>,
@location(3) joints: vec4<u32>,
@location(4) weights: vec4<f32>,
}

struct VertexOutput {
@builtin(position) Position: vec4<f32>,
@location(0) normal: vec3<f32>,
Expand Down
8 changes: 2 additions & 6 deletions src/sample/skinnedMesh/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,8 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {

whaleScene.meshes[0].buildRenderPipeline(
device,
device.createShaderModule({
code: gltfWGSL,
}),
device.createShaderModule({
code: gltfWGSL,
}),
gltfWGSL,
gltfWGSL,
presentationFormat,
depthTexture.format,
[
Expand Down

0 comments on commit 5f9d6d5

Please sign in to comment.