From 5f9d6d597abeb2076908a736cb5b3e79fc1b9a0e Mon Sep 17 00:00:00 2001 From: cmhhelgeson <62450112+cmhhelgeson@users.noreply.github.com> Date: Wed, 31 Jan 2024 12:34:27 -0800 Subject: [PATCH] interpret vertex formats from attributes to make shaders for other glbs easier to write --- public/assets/gltf/RiggedSimple.glb | Bin 0 -> 15104 bytes src/sample/skinnedMesh/glbUtils.ts | 71 +++++++++++++++++++++++----- src/sample/skinnedMesh/gltf.wgsl | 10 +--- src/sample/skinnedMesh/main.ts | 8 +--- 4 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 public/assets/gltf/RiggedSimple.glb diff --git a/public/assets/gltf/RiggedSimple.glb b/public/assets/gltf/RiggedSimple.glb new file mode 100644 index 0000000000000000000000000000000000000000..d56b94eef74fb085d7e7856a29cbafd0428fbfdc GIT binary patch literal 15104 zcmeHO33wD$w!X57Yyu*pC}6WFu@kGhs+WrC>V!Zb5Qvh1AZsTyB#@0P5C~aN5dqnf zkO%_uR9qs8JcKkVDKIK7qYo8P)Nw`>T*h5c#BKg_yQ)$N0S5i%8|Qs?eK-BrsdN8( zwtMO(=!}fyxE2hb>lmAMA!Ean5=Rx;{CRnSd|PCZZAKs~kn7LS&b39_ViOY*Vg|=J zh9)G(+3dDCf!w_G>?}NRL}ebclZq$l4{VWw-IN#EQq$5i zrsW1OeS!#;On-iEdLi9J2zH^F5pI28#a3m=!IkCD48W?Jri{5BW;I$$vOBDch076= zTNEY5qsX$y?NMBwK)A<#%37z6q5@-3vvV8tjs`O8V^d|taOBdq7yPa zc3wt$*0exwQ{!c;>8Dxil-ODI;Fsi7+zv%?$)elic6r=^aJL=ai5@|6C~iD(Iz;lL zA&i5vvqJXf=lZkqGW_{G=g5;obPAyIxFp%>RAeO(E{e3g!>zd8vRjY@k5hIyoOYsj z3vRa{J7rmLxyg^*?0kbMTo0olI6R7i2@X*aoeqx+iJ(XLp@crNASq7C>7*R$u_Egt z1VOY>ol!*f0?f%x&rHuxpQGRU^HE+Y1^IMaWE-9sKPowCieQTr?Y2>gqesRh*diTv z+x3Y_@yYRtqim6q-FD-U_@To>T5_@7hK!`A(sbl06V+{tlzG(#a?|}8kkb06e-wI>rX$; zjBw*QaP#zY@>2a7NH*WIA=^TRrf208pdC0V4EcfFoNS{EYzgtBhQy3UH^?r?=Q=L3 z@Er8r=cw-~4z(2Q8N)VeM1es_&`4?`JV^?g&a6O2AfNgZk~uRQhLgTzr|Q!a)vz5Y zQK^`jmz^78O(~c@J&-##JusJNCuLrKAaVM1-V~9n)a=Y06kb+-^1K}6$|*XqMrw9J z76r-03xoGErvlb%F-MR^7d|4Sc#FXB1|v>W@MtH$$&7F*LUu}mthi+qASDQIZBZu2 z`Mbx7w~{E)JICQ^_T{5jr4%8^cnb<5idzJqKs1s`BYQlcR}{%DH~$VhQ~ptazsWbG z9yw(<)_(!B&uHbOsqV3y^$aL}4lLFieogF+5QN(_6IVqq`MGd8j{c>v4ai3E%(O5%$ znGP?Z?Mz$Ra*%0c3x6gEPPgKbWrYInP(%my)H6M?@-}~}YyMEDzag4hW~I{?)(vPH zD#H_=1__pmKu*+$$BmaDdS_@4I?$J}10@^-L$!oP>T(Mnk4F>*1tqQ@GWE(C8Iz34 zp*;F=zQBnp^cK!Z$sHNU_h)3Jr;g4pn30BGFYo}bO@Ce>HajCbH_o5Re>a(ceS>P3 zQ2L6~1B*n|su1DAEj|dUg58Wop@!wLw*>SKMZzB7HAM^S>llo1q}Xl?WTxlk;S^~| zu}&zL_{Jpt9D#EOH+l-z4G-Ypkebh(X?VL^4;7~zC@6xSP>Cf3vS!esPZZI*%!3-b zkV|SfE}TN(!D+e4e8fK_Ny3qc&XY~(9A}`D@mg$5Cwb&1bm%pW%sUewwr*oO2iiqPWR<5)`Go{lnsnU!7`XtRi`Rm==>e!vizMOLVub8|1WPH?1KUXW?zn#6a z^^c`m@5C3Q-al5YTthDsy(r=RJ*_APVer@YQ=xaj@qunOSS6G|LdKRS*>i&f4%nA^Gmf| zn_u#N;;UBr9{jpie6mFQF!G4k+o4){pl92lFs(#u@$xU;%-5=v?BSOLUujXI&9`?@ z=ag3|!GZz7i>iyY{h#+xCni)Wv3EIxZLTcVzId>|8pf)W%3XtlJ2x%RMoo06Up}%% zdH0p1pwxYVHlvMC-7;p4^2A#y!SaPg+Rn`*)co%&m5UF~4t{!gzV?J?oI1IpQW>98 z791BjU;AvQQBO8Lt-E+0n?#tAf@#RXvHJgJaQ|4%$?5ov%^{bV{z?R_bk^=2% zSG9V~vs!6izCBn~nXe6;xmq1xw_5r3(JjH~f&y(;#WM9DYPr&C&*tF%k#n>j+ZU;8 zpD0&~pWPU|tk+y^Sw*QDBUUI`d#Z!q9+|6M{8*lP;GPO4b=#_-b913~!R{HVd|{>1 zY3-8WlN07?Tb`Vtj+j%abSu0$m~z2<&GSg2+WDcSIs+C*4Gis0SDAm@y-NoDO z<7%Z$4zJBVSgQ3DpN=|kyjm%~>*&rkpO{y+NjKYD!6b-(;xf10j$ zw)>{}J=^+cqe>_~t9Oo49oKUrhYO`$tSXJmyyu-#4s7jlr|?M30(Fbj}@{ z`kVOBIERVfVm=dZdTfM=w@n>q;`+{knk#gk4bRUu@qx4w6X)Ks$i!nmTxQ}aQRNMI z)tx4u{n z+w%n`-m)p(#P=6YGW~sX*bOGudJHk~uCF{M-u}GZ#ILXFW8#<7x|w)ibXzkQ3&j&= zju!3xn~CSm-e=+kS8g@&;=NTS{_gMs6L;vFVAhPamd?XI$M4(toxIFNJ%b_r@B;WvorljOT`&zDXAPTSW+4`3+1u z29MQG!&Za0IUbs4@Q}WtW3}N-n7EBKNv|n3d~GT>Y-%be4ui*vt@>x;Y--Qp*z=ut z%_`AW4E(_BS{kSJzI`6Y_ofe3-`q4`oATEJ@A6$wtMwgcarvW_^{UuCgUchvcl3R? zG>OX{Cp!ARE==a~^FES%>?29L3!GE8$-cC0vX%{=@0TX|29EE@<)0NM`yx+tiKSOWiYk8!GGTNFTQNu3j3)<%c%S_pL}D%H^=v*RMm^@`XjItMC^Zp{luS**pEjJXx$%?tNyyb zKO$Fsb$?$#ZnNP7=_CG{5g*vDy#*gAo^PWT=IimKdTF_1`3^n)+RGKwc2JxzhyFZ0 zUsOBfLpJ13fq##l-w5z)dVW8JJzl*YjvbY>3-y}00X7$4Q0-lY=Pj2d@tV05_0nQq zGOw8_;CorG$(zBa=r!4J7AVsmUfJFmx-Zl0qjMiO@Ow+*>c}^$`2z!bIuU=q)@a!K zu3qyN9{zVweXeipeeW2YzKZ&xb*Wv8v^{$|L>)?3oYg;Jyq;qxcouj%`A9wt+;U4N$7SGl97^_;LY@fj-U~B0{s#6>?OMb!abpdR4}#mT z%Vlu))Ai?oI}$v^uYfyN=O=Eg!R4eoNVkW$u?Dw|bFb{>B)^DzKh`E}gMPg3uN30p zF&PYQw;rDoaAOTF4+HmAdTdXC8*7C0ogc{L1A3y?I;Hha1An!Bpv%A)g+-e>L)>$X zJo302ItSxA?J#iXltr}$4t>+lvPSy1Wj}1L<%)mU}uL$m2X+{g*o?-f04@Yd)N}kF2 zLwS;45_Ihvlp5t}&yvLXI>W#N# zaJllFPyN35BQAeO>EyfSon$V5UtXq88oQs%kF|38K5ymZ^1k8Q)T_erPd4~S?a6m%^tmG_Tf3%P4XAu<1D?#KKY`) z∾GEAX9H5~@jStgLyr+At9|lC8u^ao-Lf=(~Dx{ccIG`3GL#?u}@9m|_yGwme)X z;GXax$WFYzeK+A@_#TUAglYbvoTD6nJ6Wh3ee?jwE83LRy}nN4I03dF*K5AdH}}+y z#-O`|frx51kY^WYX&^y2ngV@Ue3y1&G;U5^9t57y%Y`_yf$?@iR> zZ|zamK1O~S{mq(pYyDVj%vy)m`n1-zwf?Pp#JZ2Hd(FBZt$WtG->p5t+BdAd#oB+Y zJ<8h0tUb`$C#}8I+Hb8r+1j_Qz5R4`ZjHY+FV=in^JvYlHSbMp!>Ac+Em>>KT6@-- zwAQM%o~`u{o6VZH?gi_9!CK}%vhFYI9<=UF>z=jlW$PZd_5o{uAUhj>&TD+j{=9D- zkpFZ%3~SES4r5-^Z-XcF-T01~**}}y&^(*ofBW;M(fj{;|KFacf7SktHDTTdYHH}5 zuHIi0rY4OUgR^iMzSpQVH8tvaY!C1oz@O3?+4pcwJKvZw7vp!BKEPqXPT*+Z;lN|? z_syxmGl2^rFY}EXv&i>g%~If1z-xfl0dE4{3|s^K$AEVLKLPn3;AeqfgnU2n8^CWv z{&(Obz@I|?74UK3laRCMEj2BolgG4$lOu%(56PW`;Vlsvkmy5YEJWRoe#Q#7S#k@>q+zs6OSPUD)V%cCk ziD5%9qFEetuVX_oPhrDYJidp6EuM`4v&<5(ii3^BngSbz^&?m!Y_YTJVOJQt0XAOE zM#J6#ED5&vW6AKt#>T*>K5Q)f>&0$_ua~oN@cS}09x>>_ZbCe|vk8bzH#QM*>dGb| zW}Vq&#IF;Zf>?H7QxVs8%#RqiWhsbv8;=J z<+40n`N&)pD`0bQ&1HqS=CS#>ijYq)TfmBOl>n8pGPV%c&ET94=9#!MIA;#HW`l`% z=0LL$vuSP#=9FRv>Cfbvv$;kge_G1rDsT*{B^s3x33Lm)l`X<`8(WO)cD4l9QdH4k zwv63@YdO#gwi30qimk@aL9Coruu8TDKPy-jtHyOF>MoY8W$SR=1+<=RU>kAW4fb2W zJs8YOIOlTCwTiP;a)xR?_b$v?j~TJhUd%OD@U<%V(~X>GFz`@VJ%m?x94cDD{cz-A z7%Dm*C;{0Sfr@qjjY8H&qM{>!u17u-QPE*QqmkzuP|*W`l9B%;RJ09fEb3wmD!LcY zIMmCHsOZapZbBW6M@4rBnuz+EfQs%4G#Pa_2^HN5Xe#P)3M#rCPzvhQkBV*sG!6Be Oii&Ol6o-fh*gpZAu7BA8 literal 0 HcmV?d00001 diff --git a/src/sample/skinnedMesh/glbUtils.ts b/src/sample/skinnedMesh/glbUtils.ts index 267a5973..5feb5462 100644 --- a/src/sample/skinnedMesh/glbUtils.ts +++ b/src/sample/skinnedMesh/glbUtils.ts @@ -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, @@ -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'; + } + case 'float32x3': { + return 'vec3'; + } + case 'float32x4': { + return 'vec4'; + } + case 'uint32': { + return 'u32'; + } + case 'uint32x2': { + return 'vec2'; + } + case 'uint32x3': { + return 'vec3'; + } + case 'uint32x4': { + return 'vec4'; + } + case 'uint8x2': { + return 'vec2'; + } + case 'uint8x4': { + return 'vec4'; + } + default: { + return 'f32'; + } + } +}; + export class GLTFBuffer { buffer: Uint8Array; constructor(buffer: ArrayBuffer, offset: number, size: number) { @@ -292,8 +330,8 @@ export class GLTFPrimitive { buildRenderPipeline( device: GPUDevice, - vertexShaderModule: GPUShaderModule, - fragmentShaderModule: GPUShaderModule, + vertexShader: string, + fragmentShader: string, colorFormat: GPUTextureFormat, depthFormat: GPUTextureFormat, bgLayouts: GPUBindGroupLayout[], @@ -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; + const attrString = attr.toLowerCase().replace(/_0$/, ''); + VertexInputShaderString += `\t@location(${idx}) ${attrString}: ${convertGPUVertexFormatToWGSLFormat( + vertexFormat + )},\n`; return { arrayStride: this.attributeMap[attr].byteStride, attributes: [ @@ -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 }], @@ -401,8 +451,8 @@ export class GLTFMesh { buildRenderPipeline( device: GPUDevice, - vertexShaderModule: GPUShaderModule, - fragmentShaderModule: GPUShaderModule, + vertexShader: string, + fragmentShader: string, colorFormat: GPUTextureFormat, depthFormat: GPUTextureFormat, bgLayouts: GPUBindGroupLayout[] @@ -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, @@ -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); diff --git a/src/sample/skinnedMesh/gltf.wgsl b/src/sample/skinnedMesh/gltf.wgsl index c4b120a0..0310a2a3 100644 --- a/src/sample/skinnedMesh/gltf.wgsl +++ b/src/sample/skinnedMesh/gltf.wgsl @@ -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, - @location(1) normal: vec3, - @location(2) texcoord: vec2, - @location(3) joints: vec4, - @location(4) weights: vec4, -} - struct VertexOutput { @builtin(position) Position: vec4, @location(0) normal: vec3, diff --git a/src/sample/skinnedMesh/main.ts b/src/sample/skinnedMesh/main.ts index 3a2c845c..8b85ac1e 100644 --- a/src/sample/skinnedMesh/main.ts +++ b/src/sample/skinnedMesh/main.ts @@ -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, [