diff --git a/404.html b/404.html index 821970f0..8fe94b36 100644 --- a/404.html +++ b/404.html @@ -1,4 +1,4 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file + }

404

This page could not be found.

\ No newline at end of file diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/A-buffer.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/A-buffer.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/A-buffer.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/A-buffer.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/animometer.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/animometer.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/animometer.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/animometer.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/bitonicSort.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/bitonicSort.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/bitonicSort.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/bitonicSort.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/cameras.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/cameras.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/cameras.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/cameras.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/computeBoids.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/computeBoids.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/computeBoids.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/computeBoids.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/cornell.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/cornell.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/cornell.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/cornell.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/cubemap.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/cubemap.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/cubemap.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/cubemap.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/deferredRendering.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/deferredRendering.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/deferredRendering.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/deferredRendering.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/fractalCube.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/fractalCube.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/fractalCube.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/fractalCube.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/gameOfLife.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/gameOfLife.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/gameOfLife.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/gameOfLife.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/helloTriangle.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/helloTriangle.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/helloTriangle.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/helloTriangle.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/helloTriangleMSAA.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/helloTriangleMSAA.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/helloTriangleMSAA.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/helloTriangleMSAA.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/imageBlur.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/imageBlur.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/imageBlur.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/imageBlur.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/instancedCube.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/instancedCube.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/instancedCube.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/instancedCube.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/particles.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/particles.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/particles.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/particles.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/renderBundles.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/renderBundles.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/renderBundles.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/renderBundles.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/resizeCanvas.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/resizeCanvas.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/resizeCanvas.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/resizeCanvas.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/reversedZ.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/reversedZ.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/reversedZ.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/reversedZ.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/rotatingCube.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/rotatingCube.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/rotatingCube.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/rotatingCube.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/samplerParameters.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/samplerParameters.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/samplerParameters.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/samplerParameters.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/shadowMapping.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/shadowMapping.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/shadowMapping.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/shadowMapping.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/texturedCube.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/texturedCube.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/texturedCube.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/texturedCube.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/twoCubes.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/twoCubes.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/twoCubes.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/twoCubes.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/videoUploading.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/videoUploading.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/videoUploading.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/videoUploading.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/videoUploadingWebCodecs.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/videoUploadingWebCodecs.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/videoUploadingWebCodecs.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/videoUploadingWebCodecs.json diff --git a/_next/data/lvQoHI2oN8VKaFRrb5QRa/samples/worker.json b/_next/data/um7Vob07qBXC-7TtBPMuf/samples/worker.json similarity index 100% rename from _next/data/lvQoHI2oN8VKaFRrb5QRa/samples/worker.json rename to _next/data/um7Vob07qBXC-7TtBPMuf/samples/worker.json diff --git a/_next/static/chunks/103.7e49647d1fd74910.js b/_next/static/chunks/103.7e49647d1fd74910.js new file mode 100644 index 00000000..a9fcb0a5 --- /dev/null +++ b/_next/static/chunks/103.7e49647d1fd74910.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[103],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,o.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,g]=(0,s.useState)(null),[x,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();m&&f.current&&(m.dom.style.position="absolute",m.showPanel(1),f.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:l,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){v(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},5103:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@binding(1) @group(0) var mySampler: sampler;\n@binding(2) @group(0) var myTexture: texture_2d;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n let texColor = textureSample(myTexture, mySampler, fragUV * 0.8 + vec2(0.1));\n let f = select(1.0, 0.0, length(texColor.rgb - vec3(0.5)) < 0.01);\n return f * texColor + (1.0 - f) * fragPosition;\n}\n",c="src/sample/fractalCube/main.ts";let u=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),c=await a.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:f,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:"premultiplied"});let m=c.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(i.zS),m.unmap();let d=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:s}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=c.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),g=c.createTexture({size:[n.width,n.height],format:f,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST}),x=c.createSampler({magFilter:"linear",minFilter:"linear"}),v=c.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}},{binding:1,resource:x},{binding:2,resource:g.createView()}]}),b={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},w=n.width/n.height,P=r._E.perspective(2*Math.PI/5,w,1,100),T=r._E.create();requestAnimationFrame(function e(){if(!t.active)return;let a=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotate(e,r.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),r._E.multiply(P,e,T),T}();c.queue.writeBuffer(h,0,a.buffer,a.byteOffset,a.byteLength);let o=u.getCurrentTexture();b.colorAttachments[0].view=o.createView();let s=c.createCommandEncoder(),l=s.beginRenderPass(b);l.setPipeline(d),l.setBindGroup(0,v),l.setVertexBuffer(0,m),l.draw(i.MO),l.end(),s.copyTextureToTexture({texture:o},{texture:g},[n.width,n.height]),c.queue.submit([s.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Fractal Cube",description:"This example uses the previous frame's rendering result as the source texture for the next frame.",init:u,sources:[{name:c.substring(23),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleSelfWGSL from './sampleSelf.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n\n // Specify we want both RENDER_ATTACHMENT and COPY_SRC since we\n // will copy out of the swapchain texture.\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleSelfWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // We will copy the frame's rendering results into this texture and\n // sample it on the next frame.\n const cubeTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: presentationFormat,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\n });\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n\n const swapChainTexture = context.getCurrentTexture();\n // prettier-ignore\n renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n\n // Copy the rendering results from the swapchain into |cubeTexture|.\n commandEncoder.copyTextureToTexture(\n {\n texture: swapChainTexture,\n },\n {\n texture: cubeTexture,\n },\n [canvas.width, canvas.height]\n );\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst FractalCube: () => JSX.Element = () =>\n makeSample({\n name: 'Fractal Cube',\n description:\n \"This example uses the previous frame's rendering result \\\n as the source texture for the next frame.\",\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleSelf.frag.wgsl',\n contents: sampleSelfWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default FractalCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleSelf.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var f=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/103.a4534ca52e82f705.js b/_next/static/chunks/103.a4534ca52e82f705.js deleted file mode 100644 index 3092b293..00000000 --- a/_next/static/chunks/103.a4534ca52e82f705.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[103],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,o.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,g]=(0,s.useState)(null),[x,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();m&&f.current&&(m.dom.style.position="absolute",m.showPanel(1),f.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:l,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){v(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},5103:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@binding(1) @group(0) var mySampler: sampler;\n@binding(2) @group(0) var myTexture: texture_2d;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n let texColor = textureSample(myTexture, mySampler, fragUV * 0.8 + vec2(0.1));\n let f = select(1.0, 0.0, length(texColor.rgb - vec3(0.5)) < 0.01);\n return f * texColor + (1.0 - f) * fragPosition;\n}\n",c="src/sample/fractalCube/main.ts";let u=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),c=await a.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio||1;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:f,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:"premultiplied"});let m=c.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(i.zS),m.unmap();let d=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:s}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=c.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),g=c.createTexture({size:[n.width,n.height],format:f,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST}),x=c.createSampler({magFilter:"linear",minFilter:"linear"}),v=c.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}},{binding:1,resource:x},{binding:2,resource:g.createView()}]}),b={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},w=n.width/n.height,P=r._E.perspective(2*Math.PI/5,w,1,100),T=r._E.create();requestAnimationFrame(function e(){if(!t.active)return;let a=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotate(e,r.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),r._E.multiply(P,e,T),T}();c.queue.writeBuffer(h,0,a.buffer,a.byteOffset,a.byteLength);let o=u.getCurrentTexture();b.colorAttachments[0].view=o.createView();let s=c.createCommandEncoder(),l=s.beginRenderPass(b);l.setPipeline(d),l.setBindGroup(0,v),l.setVertexBuffer(0,m),l.draw(i.MO),l.end(),s.copyTextureToTexture({texture:o},{texture:g},[n.width,n.height]),c.queue.submit([s.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Fractal Cube",description:"This example uses the previous frame's rendering result as the source texture for the next frame.",init:u,sources:[{name:c.substring(23),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleSelfWGSL from './sampleSelf.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n\n // Specify we want both RENDER_ATTACHMENT and COPY_SRC since we\n // will copy out of the swapchain texture.\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleSelfWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // We will copy the frame's rendering results into this texture and\n // sample it on the next frame.\n const cubeTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: presentationFormat,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\n });\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n\n const swapChainTexture = context.getCurrentTexture();\n // prettier-ignore\n renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n\n // Copy the rendering results from the swapchain into |cubeTexture|.\n commandEncoder.copyTextureToTexture(\n {\n texture: swapChainTexture,\n },\n {\n texture: cubeTexture,\n },\n [canvas.width, canvas.height]\n );\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst FractalCube: () => JSX.Element = () =>\n makeSample({\n name: 'Fractal Cube',\n description:\n \"This example uses the previous frame's rendering result \\\n as the source texture for the next frame.\",\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleSelf.frag.wgsl',\n contents: sampleSelfWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default FractalCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleSelf.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var f=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/112.964d8a7e473b18ae.js b/_next/static/chunks/112.964d8a7e473b18ae.js deleted file mode 100644 index 3e59ea78..00000000 --- a/_next/static/chunks/112.964d8a7e473b18ae.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[112],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return c},hu:function(){return p}});var r=t(5893),i=t(9008),o=t.n(i),a=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let d=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let o=t(4631);n=o(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),l=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),c=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,a.useRouter)(),h=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,g]=(0,s.useState)(null),[E,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?v(h[1]):v(i[0].name),d&&l.current)for(l.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();p&&c.current&&(p.dom.style.position="absolute",p.showPanel(1),c.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let a=e.init({canvas:o,pageState:t,gui:d,stats:p});a instanceof Promise&&a.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:c}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":E==e.name,onClick(){v(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":E==e.name},n))]})]})},c=e=>(0,r.jsx)(d,{...e});function p(e,n){if(!e)throw Error(n)}},8112:function(e,n,t){"use strict";let r;t.r(n),t.d(n,{default:function(){return g}});var i,o,a=t(5671),s=t(134);let l=(e,n,t,r,i,o,a)=>{let s=[];for(let l=0;l{let n=async n=>{let{canvas:t,pageState:r,gui:i,stats:o}=n,a=await navigator.gpu.requestAdapter(),s=await a.requestDevice();if(!r.active)return;let l=t.getContext("webgpu"),u=window.devicePixelRatio||1;t.width=t.clientWidth*u,t.height=t.clientHeight*u;let d=navigator.gpu.getPreferredCanvasFormat();l.configure({device:s,format:d,alphaMode:"premultiplied"}),e({canvas:t,pageState:r,gui:i,device:s,context:l,presentationFormat:d,stats:o})};return n};class d{executeRun(e,n,t,r){let i=e.beginRenderPass(n);i.setPipeline(t);for(let o=0;o{this.bindGroupMap[r[n]]=e}),this.pipeline=super.create2DRenderPipeline(e,o,[s.bindGroupLayout,this.computeBGDescript.bindGroupLayout],c,n),this.switchBindGroup=e=>{this.currentBindGroup=this.bindGroupMap[e],this.currentBindGroupName=e},this.setArguments=n=>{super.setUniformArguments(e,a,n,["width","height"])}}}p.sourceInfo={name:"src/sample/bitonicSort/bitonicDisplay.ts".substring(23),contents:"import {\n BindGroupsObjectsAndLayout,\n createBindGroupDescriptor,\n Base2DRendererClass,\n} from './utils';\n\nimport bitonicDisplay from './bitonicDisplay.frag.wgsl';\n\ninterface BitonicDisplayRenderArgs {\n width: number;\n height: number;\n}\n\nexport default class BitonicDisplayRenderer extends Base2DRendererClass {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n switchBindGroup: (name: string) => void;\n setArguments: (args: BitonicDisplayRenderArgs) => void;\n computeBGDescript: BindGroupsObjectsAndLayout;\n\n constructor(\n device: GPUDevice,\n presentationFormat: GPUTextureFormat,\n renderPassDescriptor: GPURenderPassDescriptor,\n bindGroupNames: string[],\n computeBGDescript: BindGroupsObjectsAndLayout,\n label: string\n ) {\n super();\n this.renderPassDescriptor = renderPassDescriptor;\n this.computeBGDescript = computeBGDescript;\n\n const uniformBuffer = device.createBuffer({\n size: Float32Array.BYTES_PER_ELEMENT * 2,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const bgDescript = createBindGroupDescriptor(\n [0],\n [GPUShaderStage.FRAGMENT],\n ['buffer'],\n [{ type: 'uniform' }],\n [[{ buffer: uniformBuffer }]],\n label,\n device\n );\n\n this.currentBindGroup = bgDescript.bindGroups[0];\n this.currentBindGroupName = bindGroupNames[0];\n\n this.bindGroupMap = {};\n\n bgDescript.bindGroups.forEach((bg, idx) => {\n this.bindGroupMap[bindGroupNames[idx]] = bg;\n });\n\n this.pipeline = super.create2DRenderPipeline(\n device,\n label,\n [bgDescript.bindGroupLayout, this.computeBGDescript.bindGroupLayout],\n bitonicDisplay,\n presentationFormat\n );\n\n this.switchBindGroup = (name: string) => {\n this.currentBindGroup = this.bindGroupMap[name];\n this.currentBindGroupName = name;\n };\n\n this.setArguments = (args: BitonicDisplayRenderArgs) => {\n super.setUniformArguments(device, uniformBuffer, args, [\n 'width',\n 'height',\n ]);\n };\n }\n\n startRun(commandEncoder: GPUCommandEncoder, args: BitonicDisplayRenderArgs) {\n this.setArguments(args);\n super.executeRun(commandEncoder, this.renderPassDescriptor, this.pipeline, [\n this.currentBindGroup,\n this.computeBGDescript.bindGroups[0],\n ]);\n }\n}\n"};let m=e=>((e%2!=0||e>256)&&(e=256),"\n\nstruct Uniforms {\n width: f32,\n height: f32,\n algo: u32,\n blockHeight: u32,\n}\n\n// Create local workgroup data that can contain all elements\n\nvar local_data: array;\n\n//Compare and swap values in local_data\nfn compare_and_swap(idx_before: u32, idx_after: u32) {\n //idx_before should always be < idx_after\n if (local_data[idx_after] < local_data[idx_before]) {\n var temp: u32 = local_data[idx_before];\n local_data[idx_before] = local_data[idx_after];\n local_data[idx_after] = temp;\n }\n return;\n}\n\n// thread_id goes from 0 to threadsPerWorkgroup\nfn prepare_flip(thread_id: u32, block_height: u32) {\n let q: u32 = ((2 * thread_id) / block_height) * block_height;\n let half_height = block_height / 2;\n var idx: vec2 = vec2(\n thread_id % half_height, block_height - (thread_id % half_height) - 1,\n );\n idx.x += q;\n idx.y += q;\n compare_and_swap(idx.x, idx.y);\n}\n\nfn prepare_disperse(thread_id: u32, block_height: u32) {\n var q: u32 = ((2 * thread_id) / block_height) * block_height;\n let half_height = block_height / 2;\n var idx: vec2 = vec2(\n thread_id % half_height, (thread_id % half_height) + half_height\n );\n idx.x += q;\n idx.y += q;\n compare_and_swap(idx.x, idx.y);\n}\n\n@group(0) @binding(0) var input_data: array;\n@group(0) @binding(1) var output_data: array;\n@group(0) @binding(2) var uniforms: Uniforms;\n\n// Our compute shader will execute specified # of threads or elements / 2 threads\n@compute @workgroup_size(").concat(e,", 1, 1)\nfn computeMain(\n @builtin(global_invocation_id) global_id: vec3,\n @builtin(local_invocation_id) local_id: vec3,\n) {\n //Each thread will populate the workgroup data... (1 thread for every 2 elements)\n local_data[local_id.x * 2] = input_data[local_id.x * 2];\n local_data[local_id.x * 2 + 1] = input_data[local_id.x * 2 + 1];\n\n //...and wait for each other to finish their own bit of data population.\n workgroupBarrier();\n\n var num_elements = uniforms.width * uniforms.height;\n\n switch uniforms.algo {\n case 1: { //Local Flip\n prepare_flip(local_id.x, uniforms.blockHeight);\n }\n case 2: { //Local Disperse\n prepare_disperse(local_id.x, uniforms.blockHeight);\n }\n default: { \n \n }\n }\n\n //Ensure that all threads have swapped their own regions of data\n workgroupBarrier();\n\n //Repopulate global data with local data\n output_data[local_id.x * 2] = local_data[local_id.x * 2];\n output_data[local_id.x * 2 + 1] = local_data[local_id.x * 2 + 1];\n\n}"));var h="src/sample/bitonicSort/main.ts";(i=o||(o={}))[i.NONE=0]="NONE",i[i.FLIP_LOCAL=1]="FLIP_LOCAL",i[i.DISPERSE_LOCAL=2]="DISPERSE_LOCAL",i[i.FLIP_DISPERSE_LOCAL=3]="FLIP_DISPERSE_LOCAL",u(async e=>{let{pageState:n,device:t,gui:r,presentationFormat:i,context:a,canvas:s}=e,u=t.limits.maxComputeWorkgroupSizeX,d=[];for(let c=2*u;c>=4;c/=2)d.push(c);let h={"Total Elements":16,"Grid Width":4,"Grid Height":4,"Total Threads":8,hoveredElement:0,swappedElement:1,"Prev Step":"NONE","Next Step":"FLIP_LOCAL","Prev Swap Span":0,"Next Swap Span":2,workLoads:1,executeStep:!1,"Randomize Values"(){},"Execute Sort Step"(){},"Log Elements"(){},"Complete Sort"(){},sortSpeed:200},f=new Uint32Array(Array.from({length:h["Total Elements"]},(e,n)=>n)),g=512*Float32Array.BYTES_PER_ELEMENT,E=t.createBuffer({size:g,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),v=t.createBuffer({size:g,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),S=t.createBuffer({size:g,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),x=t.createBuffer({size:4*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),b=l([0,1,2],[GPUShaderStage.COMPUTE|GPUShaderStage.FRAGMENT,GPUShaderStage.COMPUTE,GPUShaderStage.COMPUTE],["buffer","buffer","buffer"],[{type:"read-only-storage"},{type:"storage"},{type:"uniform"}],[[{buffer:E},{buffer:v},{buffer:x}]],"NaiveBitonicSort",t),y=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[b.bindGroupLayout]}),compute:{module:t.createShaderModule({code:m(h["Total Threads"])}),entryPoint:"computeMain"}}),_={colorAttachments:[{view:void 0,clearValue:{r:.1,g:.4,b:.5,a:1},loadOp:"clear",storeOp:"store"}]},w=new p(t,i,_,["default"],b,"BitonicDisplay"),P=()=>{U.setValue(h["Total Elements"]/2);let e=Math.sqrt(h["Total Elements"])%2==0?Math.floor(Math.sqrt(h["Total Elements"])):Math.floor(Math.sqrt(h["Total Elements"]/2)),n=h["Total Elements"]/e;V.setValue(e),z.setValue(n),F.setValue("NONE"),k.setValue("FLIP_LOCAL"),M.setValue(0),H.setValue(2),q=2},B=()=>{let e=f.length;for(;0!==e;){let n=Math.floor(Math.random()*e);e-=1,[f[e],f[n]]=[f[n],f[e]]}},G=()=>{f=new Uint32Array(Array.from({length:h["Total Elements"]},(e,n)=>n)),P(),y=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[b.bindGroupLayout]}),compute:{module:t.createShaderModule({code:m(h["Total Elements"]/2)}),entryPoint:"computeMain"}}),B(),q=2};B();let C=()=>{let e;switch(h["Next Step"]){case"FLIP_LOCAL":{let n=h["Next Swap Span"],t=Math.floor(h.hoveredElement/n)+1,r=h.hoveredElement%n;e=n*t-r-1,R.setValue(e)}break;case"DISPERSE_LOCAL":{let i=h["Next Swap Span"],o=i/2;e=h.hoveredElement%i{null!==I&&(clearInterval(I),I=null)},T=()=>{I=setInterval(()=>{"NONE"===h["Next Step"]&&(clearInterval(I),I=null),h.executeStep=!0,C()},h.sortSpeed)};r.add(h,"Total Elements",d).onChange(()=>{L(),G()});let U=r.add(h,"Total Threads"),D=r.addFolder("Sort Controls");D.add(h,"Execute Sort Step").onChange(()=>{L(),h.executeStep=!0}),D.add(h,"Randomize Values").onChange(()=>{L(),B(),P()}),D.add(h,"Log Elements").onChange(()=>console.log(f)),D.add(h,"Complete Sort").onChange(T),D.open();let A=r.addFolder("Hover Information"),N=A.add(h,"hoveredElement").onChange(C),R=A.add(h,"swappedElement"),O=r.addFolder("Execution Information"),F=O.add(h,"Prev Step"),k=O.add(h,"Next Step"),M=O.add(h,"Prev Swap Span"),H=O.add(h,"Next Swap Span"),V=O.add(h,"Grid Width"),z=O.add(h,"Grid Height"),W=document.getElementsByClassName("cr function");for(let j=0;j{let n=s.getBoundingClientRect().width,t=s.getBoundingClientRect().height,r=[n/h["Grid Width"],t/h["Grid Height"]],i=Math.floor(e.offsetX/r[0]),o=h["Grid Height"]-1-Math.floor(e.offsetY/r[1]);N.setValue(o*h["Grid Width"]+i),h.hoveredElement=o*h["Grid Width"]+i}),F.domElement.style.pointerEvents="none",M.domElement.style.pointerEvents="none",k.domElement.style.pointerEvents="none",H.domElement.style.pointerEvents="none",U.domElement.style.pointerEvents="none",V.domElement.style.pointerEvents="none",z.domElement.style.pointerEvents="none";let q=2;async function Y(){if(!n.active)return;t.queue.writeBuffer(E,0,f.buffer,f.byteOffset,f.byteLength);let e=new Float32Array([h["Grid Width"],h["Grid Height"]]),r=new Uint32Array([o[h["Next Step"]],h["Next Swap Span"]]);t.queue.writeBuffer(x,0,e.buffer,e.byteOffset,e.byteLength),t.queue.writeBuffer(x,8,r),_.colorAttachments[0].view=a.getCurrentTexture().createView();let i=t.createCommandEncoder();if(w.startRun(i,{width:h["Grid Width"],height:h["Grid Height"]}),h.executeStep&&q!==2*h["Total Elements"]){let s=i.beginComputePass();s.setPipeline(y),s.setBindGroup(0,b.bindGroups[0]),s.dispatchWorkgroups(1),s.end(),F.setValue(h["Next Step"]),M.setValue(h["Next Swap Span"]),H.setValue(h["Next Swap Span"]/2),1===h["Next Swap Span"]?(q*=2,k.setValue(q===2*h["Total Elements"]?"NONE":"FLIP_LOCAL"),H.setValue(q===2*h["Total Elements"]?0:q)):k.setValue("DISPERSE_LOCAL"),i.copyBufferToBuffer(v,0,S,0,g)}if(t.queue.submit([i.finish()]),h.executeStep){await S.mapAsync(GPUMapMode.READ,0,g);let l=S.getMappedRange(0,g),u=l.slice(0,Uint32Array.BYTES_PER_ELEMENT*h["Total Elements"]),d=new Uint32Array(u);S.unmap(),f=d,C()}h.executeStep=!1,requestAnimationFrame(Y)}requestAnimationFrame(Y)}).then(e=>r=e);let f=()=>(0,a.Tl)({name:"Bitonic Sort",description:"A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each invocation of the bitonic sort shader dispatches a workgroup containing elements/2 threads. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.",init:r,gui:!0,sources:[{name:h.substring(23),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { SampleInitFactoryWebGPU } from './utils';\nimport { createBindGroupDescriptor } from './utils';\nimport BitonicDisplayRenderer from './bitonicDisplay';\nimport bitonicDisplay from './bitonicDisplay.frag.wgsl';\nimport { NaiveBitonicCompute } from './computeShader';\nimport fullscreenTexturedQuad from '../../shaders/fullscreenTexturedQuad.wgsl';\n\n// Type of step that will be executed in our shader\nenum StepEnum {\n NONE = 0,\n FLIP_LOCAL = 1,\n DISPERSE_LOCAL = 2,\n FLIP_DISPERSE_LOCAL = 3,\n}\n\n// String access to StepEnum\ntype StepType =\n | 'NONE'\n | 'FLIP_LOCAL'\n | 'DISPERSE_LOCAL'\n | 'FLIP_DISPERSE_LOCAL';\n\n// Gui settings object\ninterface SettingsInterface {\n 'Total Elements': number;\n 'Grid Width': number;\n 'Grid Height': number;\n 'Total Threads': number;\n hoveredElement: number;\n swappedElement: number;\n 'Prev Step': StepType;\n 'Next Step': StepType;\n 'Prev Swap Span': number;\n 'Next Swap Span': number;\n workLoads: number;\n executeStep: boolean;\n 'Randomize Values': () => void;\n 'Execute Sort Step': () => void;\n 'Log Elements': () => void;\n 'Complete Sort': () => void;\n sortSpeed: number;\n}\n\nlet init: SampleInit;\nSampleInitFactoryWebGPU(\n async ({ pageState, device, gui, presentationFormat, context, canvas }) => {\n const maxWorkgroupsX = device.limits.maxComputeWorkgroupSizeX;\n\n const totalElementLengths = [];\n for (let i = maxWorkgroupsX * 2; i >= 4; i /= 2) {\n totalElementLengths.push(i);\n }\n\n const settings: SettingsInterface = {\n // number of cellElements. Must equal gridWidth * gridHeight and 'Total Threads' * 2\n 'Total Elements': 16,\n // width of screen in cells.\n 'Grid Width': 4,\n // height of screen in cells\n 'Grid Height': 4,\n // number of threads to execute in a workgroup ('Total Threads', 1, 1)\n 'Total Threads': 16 / 2,\n // currently highlighted element\n hoveredElement: 0,\n // element the hoveredElement just swapped with,\n swappedElement: 1,\n // Previously executed step\n 'Prev Step': 'NONE',\n // Next step to execute\n 'Next Step': 'FLIP_LOCAL',\n // Max thread span of previous block\n 'Prev Swap Span': 0,\n // Max thread span of next block\n 'Next Swap Span': 2,\n // workloads to dispatch per frame,\n workLoads: 1,\n // Whether we will dispatch a workload this frame\n executeStep: false,\n 'Randomize Values': () => {\n return;\n },\n 'Execute Sort Step': () => {\n return;\n },\n 'Log Elements': () => {\n return;\n },\n 'Complete Sort': () => {\n return;\n },\n sortSpeed: 200,\n };\n\n // Initialize initial elements array\n let elements = new Uint32Array(\n Array.from({ length: settings['Total Elements'] }, (_, i) => i)\n );\n\n // Initialize elementsBuffer and elementsStagingBuffer\n const elementsBufferSize = Float32Array.BYTES_PER_ELEMENT * 512;\n // Initialize input, output, staging buffers\n const elementsInputBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n const elementsOutputBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n });\n const elementsStagingBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,\n });\n\n // Create uniform buffer for compute shader\n const computeUniformsBuffer = device.createBuffer({\n // width, height, blockHeight, algo\n size: Float32Array.BYTES_PER_ELEMENT * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const computeBGDescript = createBindGroupDescriptor(\n [0, 1, 2],\n [\n GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT,\n GPUShaderStage.COMPUTE,\n GPUShaderStage.COMPUTE,\n ],\n ['buffer', 'buffer', 'buffer'],\n [{ type: 'read-only-storage' }, { type: 'storage' }, { type: 'uniform' }],\n [\n [\n { buffer: elementsInputBuffer },\n { buffer: elementsOutputBuffer },\n { buffer: computeUniformsBuffer },\n ],\n ],\n 'NaiveBitonicSort',\n device\n );\n\n let computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGDescript.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(settings['Total Threads']),\n }),\n entryPoint: 'computeMain',\n },\n });\n\n // Create bitonic debug renderer\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.1, g: 0.4, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const bitonicDisplayRenderer = new BitonicDisplayRenderer(\n device,\n presentationFormat,\n renderPassDescriptor,\n ['default'],\n computeBGDescript,\n 'BitonicDisplay'\n );\n\n const resetExecutionInformation = () => {\n totalThreadsCell.setValue(settings['Total Elements'] / 2);\n\n // Get new width and height of screen display in cells\n const newCellWidth =\n Math.sqrt(settings['Total Elements']) % 2 === 0\n ? Math.floor(Math.sqrt(settings['Total Elements']))\n : Math.floor(Math.sqrt(settings['Total Elements'] / 2));\n const newCellHeight = settings['Total Elements'] / newCellWidth;\n gridWidthCell.setValue(newCellWidth);\n gridHeightCell.setValue(newCellHeight);\n\n // Set prevStep to None (restart) and next step to FLIP\n prevStepCell.setValue('NONE');\n nextStepCell.setValue('FLIP_LOCAL');\n\n // Reset block heights\n prevBlockHeightCell.setValue(0);\n nextBlockHeightCell.setValue(2);\n highestBlockHeight = 2;\n };\n\n const randomizeElementArray = () => {\n let currentIndex = elements.length;\n // While there are elements to shuffle\n while (currentIndex !== 0) {\n // Pick a remaining element\n const randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex -= 1;\n [elements[currentIndex], elements[randomIndex]] = [\n elements[randomIndex],\n elements[currentIndex],\n ];\n }\n };\n\n const resizeElementArray = () => {\n // Recreate elements array with new length\n elements = new Uint32Array(\n Array.from({ length: settings['Total Elements'] }, (_, i) => i)\n );\n\n resetExecutionInformation();\n\n // Create new shader invocation with workgroupSize that reflects number of threads\n computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGDescript.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(settings['Total Elements'] / 2),\n }),\n entryPoint: 'computeMain',\n },\n });\n // Randomize array elements\n randomizeElementArray();\n highestBlockHeight = 2;\n };\n\n randomizeElementArray();\n\n const setSwappedElement = () => {\n let swappedIndex: number;\n switch (settings['Next Step']) {\n case 'FLIP_LOCAL':\n {\n const blockHeight = settings['Next Swap Span'];\n const p2 = Math.floor(settings.hoveredElement / blockHeight) + 1;\n const p3 = settings.hoveredElement % blockHeight;\n swappedIndex = blockHeight * p2 - p3 - 1;\n swappedElementCell.setValue(swappedIndex);\n }\n break;\n case 'DISPERSE_LOCAL':\n {\n const blockHeight = settings['Next Swap Span'];\n const halfHeight = blockHeight / 2;\n swappedIndex =\n settings.hoveredElement % blockHeight < halfHeight\n ? settings.hoveredElement + halfHeight\n : settings.hoveredElement - halfHeight;\n swappedElementCell.setValue(swappedIndex);\n }\n break;\n case 'NONE': {\n swappedIndex = settings.hoveredElement;\n swappedElementCell.setValue(swappedIndex);\n }\n default:\n {\n swappedIndex = settings.hoveredElement;\n swappedElementCell.setValue(swappedIndex);\n }\n break;\n }\n };\n\n let completeSortIntervalID: ReturnType | null = null;\n const endSortInterval = () => {\n if (completeSortIntervalID !== null) {\n clearInterval(completeSortIntervalID);\n completeSortIntervalID = null;\n }\n };\n const startSortInterval = () => {\n completeSortIntervalID = setInterval(() => {\n if (settings['Next Step'] === 'NONE') {\n clearInterval(completeSortIntervalID);\n completeSortIntervalID = null;\n }\n settings.executeStep = true;\n setSwappedElement();\n }, settings.sortSpeed);\n };\n\n // At top level, basic information about the number of elements sorted and the number of threads\n // deployed per workgroup.\n gui.add(settings, 'Total Elements', totalElementLengths).onChange(() => {\n endSortInterval();\n resizeElementArray();\n });\n const totalThreadsCell = gui.add(settings, 'Total Threads');\n\n // Folder with functions that control the execution of the sort\n const controlFolder = gui.addFolder('Sort Controls');\n controlFolder.add(settings, 'Execute Sort Step').onChange(() => {\n endSortInterval();\n settings.executeStep = true;\n });\n controlFolder.add(settings, 'Randomize Values').onChange(() => {\n endSortInterval();\n randomizeElementArray();\n resetExecutionInformation();\n });\n controlFolder\n .add(settings, 'Log Elements')\n .onChange(() => console.log(elements));\n controlFolder.add(settings, 'Complete Sort').onChange(startSortInterval);\n controlFolder.open();\n\n // Folder with indexes of the hovered element\n const hoverFolder = gui.addFolder('Hover Information');\n const hoveredElementCell = hoverFolder\n .add(settings, 'hoveredElement')\n .onChange(setSwappedElement);\n const swappedElementCell = hoverFolder.add(settings, 'swappedElement');\n\n // Additional Information about the execution state of the sort\n const executionInformationFolder = gui.addFolder('Execution Information');\n const prevStepCell = executionInformationFolder.add(settings, 'Prev Step');\n const nextStepCell = executionInformationFolder.add(settings, 'Next Step');\n const prevBlockHeightCell = executionInformationFolder.add(\n settings,\n 'Prev Swap Span'\n );\n const nextBlockHeightCell = executionInformationFolder.add(\n settings,\n 'Next Swap Span'\n );\n const gridWidthCell = executionInformationFolder.add(\n settings,\n 'Grid Width'\n );\n const gridHeightCell = executionInformationFolder.add(\n settings,\n 'Grid Height'\n );\n\n // Adjust styles of Function List Elements within GUI\n const liFunctionElements = document.getElementsByClassName('cr function');\n for (let i = 0; i < liFunctionElements.length; i++) {\n (liFunctionElements[i].children[0] as HTMLElement).style.display = 'flex';\n (liFunctionElements[i].children[0] as HTMLElement).style.justifyContent =\n 'center';\n (\n liFunctionElements[i].children[0].children[1] as HTMLElement\n ).style.position = 'absolute';\n }\n\n canvas.addEventListener('mousemove', (event) => {\n const currWidth = canvas.getBoundingClientRect().width;\n const currHeight = canvas.getBoundingClientRect().height;\n const cellSize: [number, number] = [\n currWidth / settings['Grid Width'],\n currHeight / settings['Grid Height'],\n ];\n const xIndex = Math.floor(event.offsetX / cellSize[0]);\n const yIndex =\n settings['Grid Height'] - 1 - Math.floor(event.offsetY / cellSize[1]);\n hoveredElementCell.setValue(yIndex * settings['Grid Width'] + xIndex);\n settings.hoveredElement = yIndex * settings['Grid Width'] + xIndex;\n });\n\n // Deactivate interaction with select GUI elements\n prevStepCell.domElement.style.pointerEvents = 'none';\n prevBlockHeightCell.domElement.style.pointerEvents = 'none';\n nextStepCell.domElement.style.pointerEvents = 'none';\n nextBlockHeightCell.domElement.style.pointerEvents = 'none';\n totalThreadsCell.domElement.style.pointerEvents = 'none';\n gridWidthCell.domElement.style.pointerEvents = 'none';\n gridHeightCell.domElement.style.pointerEvents = 'none';\n\n let highestBlockHeight = 2;\n\n async function frame() {\n if (!pageState.active) return;\n\n // Write elements buffer\n device.queue.writeBuffer(\n elementsInputBuffer,\n 0,\n elements.buffer,\n elements.byteOffset,\n elements.byteLength\n );\n\n const dims = new Float32Array([\n settings['Grid Width'],\n settings['Grid Height'],\n ]);\n const stepDetails = new Uint32Array([\n StepEnum[settings['Next Step']],\n settings['Next Swap Span'],\n ]);\n device.queue.writeBuffer(\n computeUniformsBuffer,\n 0,\n dims.buffer,\n dims.byteOffset,\n dims.byteLength\n );\n\n device.queue.writeBuffer(computeUniformsBuffer, 8, stepDetails);\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n bitonicDisplayRenderer.startRun(commandEncoder, {\n width: settings['Grid Width'],\n height: settings['Grid Height'],\n });\n if (\n settings.executeStep &&\n highestBlockHeight !== settings['Total Elements'] * 2\n ) {\n const computePassEncoder = commandEncoder.beginComputePass();\n computePassEncoder.setPipeline(computePipeline);\n computePassEncoder.setBindGroup(0, computeBGDescript.bindGroups[0]);\n computePassEncoder.dispatchWorkgroups(1);\n computePassEncoder.end();\n\n prevStepCell.setValue(settings['Next Step']);\n prevBlockHeightCell.setValue(settings['Next Swap Span']);\n nextBlockHeightCell.setValue(settings['Next Swap Span'] / 2);\n if (settings['Next Swap Span'] === 1) {\n highestBlockHeight *= 2;\n nextStepCell.setValue(\n highestBlockHeight === settings['Total Elements'] * 2\n ? 'NONE'\n : 'FLIP_LOCAL'\n );\n nextBlockHeightCell.setValue(\n highestBlockHeight === settings['Total Elements'] * 2\n ? 0\n : highestBlockHeight\n );\n } else {\n nextStepCell.setValue('DISPERSE_LOCAL');\n }\n commandEncoder.copyBufferToBuffer(\n elementsOutputBuffer,\n 0,\n elementsStagingBuffer,\n 0,\n elementsBufferSize\n );\n }\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.executeStep) {\n // Copy GPU element data to CPU\n await elementsStagingBuffer.mapAsync(\n GPUMapMode.READ,\n 0,\n elementsBufferSize\n );\n const copyElementsBuffer = elementsStagingBuffer.getMappedRange(\n 0,\n elementsBufferSize\n );\n // Get correct range of data from CPU copy of GPU Data\n const elementsData = copyElementsBuffer.slice(\n 0,\n Uint32Array.BYTES_PER_ELEMENT * settings['Total Elements']\n );\n // Extract data\n const elementsOutput = new Uint32Array(elementsData);\n elementsStagingBuffer.unmap();\n elements = elementsOutput;\n setSwappedElement();\n }\n settings.executeStep = false;\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n }\n).then((resultInit) => (init = resultInit));\n\nconst bitonicSortExample: () => JSX.Element = () =>\n makeSample({\n name: 'Bitonic Sort',\n description:\n \"A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each invocation of the bitonic sort shader dispatches a workgroup containing elements/2 threads. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.\",\n init,\n gui: true,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n BitonicDisplayRenderer.sourceInfo,\n {\n name: '../../../shaders/fullscreenTexturedQuad.vert.wgsl',\n contents: fullscreenTexturedQuad,\n },\n {\n name: './bitonicDisplay.frag.wgsl',\n contents: bitonicDisplay,\n },\n {\n name: './bitonicCompute.frag.wgsl',\n contents: NaiveBitonicCompute(16),\n },\n ],\n filename: __filename,\n });\n\nexport default bitonicSortExample;\n"},p.sourceInfo,{name:"../../../shaders/fullscreenTexturedQuad.vert.wgsl",contents:s.Z},{name:"./bitonicDisplay.frag.wgsl",contents:c},{name:"./bitonicCompute.frag.wgsl",contents:m(16)}],filename:h});var g=f},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/112.be7dd3c74cc1b516.js b/_next/static/chunks/112.be7dd3c74cc1b516.js new file mode 100644 index 00000000..283da887 --- /dev/null +++ b/_next/static/chunks/112.be7dd3c74cc1b516.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[112],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return c},hu:function(){return p}});var r=t(5893),i=t(9008),o=t.n(i),a=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let d=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let o=t(4631);n=o(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),l=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),c=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,a.useRouter)(),h=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,g]=(0,s.useState)(null),[E,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?v(h[1]):v(i[0].name),d&&l.current)for(l.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();p&&c.current&&(p.dom.style.position="absolute",p.showPanel(1),c.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let a=e.init({canvas:o,pageState:t,gui:d,stats:p});a instanceof Promise&&a.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:c}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":E==e.name,onClick(){v(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":E==e.name},n))]})]})},c=e=>(0,r.jsx)(d,{...e});function p(e,n){if(!e)throw Error(n)}},8112:function(e,n,t){"use strict";let r;t.r(n),t.d(n,{default:function(){return g}});var i,o,a=t(5671),s=t(134);let l=(e,n,t,r,i,o,a)=>{let s=[];for(let l=0;l{let n=async n=>{let{canvas:t,pageState:r,gui:i,stats:o}=n,a=await navigator.gpu.requestAdapter(),s=await a.requestDevice();if(!r.active)return;let l=t.getContext("webgpu"),u=window.devicePixelRatio;t.width=t.clientWidth*u,t.height=t.clientHeight*u;let d=navigator.gpu.getPreferredCanvasFormat();l.configure({device:s,format:d,alphaMode:"premultiplied"}),e({canvas:t,pageState:r,gui:i,device:s,context:l,presentationFormat:d,stats:o})};return n};class d{executeRun(e,n,t,r){let i=e.beginRenderPass(n);i.setPipeline(t);for(let o=0;o{this.bindGroupMap[r[n]]=e}),this.pipeline=super.create2DRenderPipeline(e,o,[s.bindGroupLayout,this.computeBGDescript.bindGroupLayout],c,n),this.switchBindGroup=e=>{this.currentBindGroup=this.bindGroupMap[e],this.currentBindGroupName=e},this.setArguments=n=>{super.setUniformArguments(e,a,n,["width","height"])}}}p.sourceInfo={name:"src/sample/bitonicSort/bitonicDisplay.ts".substring(23),contents:"import {\n BindGroupsObjectsAndLayout,\n createBindGroupDescriptor,\n Base2DRendererClass,\n} from './utils';\n\nimport bitonicDisplay from './bitonicDisplay.frag.wgsl';\n\ninterface BitonicDisplayRenderArgs {\n width: number;\n height: number;\n}\n\nexport default class BitonicDisplayRenderer extends Base2DRendererClass {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n switchBindGroup: (name: string) => void;\n setArguments: (args: BitonicDisplayRenderArgs) => void;\n computeBGDescript: BindGroupsObjectsAndLayout;\n\n constructor(\n device: GPUDevice,\n presentationFormat: GPUTextureFormat,\n renderPassDescriptor: GPURenderPassDescriptor,\n bindGroupNames: string[],\n computeBGDescript: BindGroupsObjectsAndLayout,\n label: string\n ) {\n super();\n this.renderPassDescriptor = renderPassDescriptor;\n this.computeBGDescript = computeBGDescript;\n\n const uniformBuffer = device.createBuffer({\n size: Float32Array.BYTES_PER_ELEMENT * 2,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const bgDescript = createBindGroupDescriptor(\n [0],\n [GPUShaderStage.FRAGMENT],\n ['buffer'],\n [{ type: 'uniform' }],\n [[{ buffer: uniformBuffer }]],\n label,\n device\n );\n\n this.currentBindGroup = bgDescript.bindGroups[0];\n this.currentBindGroupName = bindGroupNames[0];\n\n this.bindGroupMap = {};\n\n bgDescript.bindGroups.forEach((bg, idx) => {\n this.bindGroupMap[bindGroupNames[idx]] = bg;\n });\n\n this.pipeline = super.create2DRenderPipeline(\n device,\n label,\n [bgDescript.bindGroupLayout, this.computeBGDescript.bindGroupLayout],\n bitonicDisplay,\n presentationFormat\n );\n\n this.switchBindGroup = (name: string) => {\n this.currentBindGroup = this.bindGroupMap[name];\n this.currentBindGroupName = name;\n };\n\n this.setArguments = (args: BitonicDisplayRenderArgs) => {\n super.setUniformArguments(device, uniformBuffer, args, [\n 'width',\n 'height',\n ]);\n };\n }\n\n startRun(commandEncoder: GPUCommandEncoder, args: BitonicDisplayRenderArgs) {\n this.setArguments(args);\n super.executeRun(commandEncoder, this.renderPassDescriptor, this.pipeline, [\n this.currentBindGroup,\n this.computeBGDescript.bindGroups[0],\n ]);\n }\n}\n"};let m=e=>((e%2!=0||e>256)&&(e=256),"\n\nstruct Uniforms {\n width: f32,\n height: f32,\n algo: u32,\n blockHeight: u32,\n}\n\n// Create local workgroup data that can contain all elements\n\nvar local_data: array;\n\n//Compare and swap values in local_data\nfn compare_and_swap(idx_before: u32, idx_after: u32) {\n //idx_before should always be < idx_after\n if (local_data[idx_after] < local_data[idx_before]) {\n var temp: u32 = local_data[idx_before];\n local_data[idx_before] = local_data[idx_after];\n local_data[idx_after] = temp;\n }\n return;\n}\n\n// thread_id goes from 0 to threadsPerWorkgroup\nfn prepare_flip(thread_id: u32, block_height: u32) {\n let q: u32 = ((2 * thread_id) / block_height) * block_height;\n let half_height = block_height / 2;\n var idx: vec2 = vec2(\n thread_id % half_height, block_height - (thread_id % half_height) - 1,\n );\n idx.x += q;\n idx.y += q;\n compare_and_swap(idx.x, idx.y);\n}\n\nfn prepare_disperse(thread_id: u32, block_height: u32) {\n var q: u32 = ((2 * thread_id) / block_height) * block_height;\n let half_height = block_height / 2;\n var idx: vec2 = vec2(\n thread_id % half_height, (thread_id % half_height) + half_height\n );\n idx.x += q;\n idx.y += q;\n compare_and_swap(idx.x, idx.y);\n}\n\n@group(0) @binding(0) var input_data: array;\n@group(0) @binding(1) var output_data: array;\n@group(0) @binding(2) var uniforms: Uniforms;\n\n// Our compute shader will execute specified # of threads or elements / 2 threads\n@compute @workgroup_size(").concat(e,", 1, 1)\nfn computeMain(\n @builtin(global_invocation_id) global_id: vec3,\n @builtin(local_invocation_id) local_id: vec3,\n) {\n //Each thread will populate the workgroup data... (1 thread for every 2 elements)\n local_data[local_id.x * 2] = input_data[local_id.x * 2];\n local_data[local_id.x * 2 + 1] = input_data[local_id.x * 2 + 1];\n\n //...and wait for each other to finish their own bit of data population.\n workgroupBarrier();\n\n var num_elements = uniforms.width * uniforms.height;\n\n switch uniforms.algo {\n case 1: { //Local Flip\n prepare_flip(local_id.x, uniforms.blockHeight);\n }\n case 2: { //Local Disperse\n prepare_disperse(local_id.x, uniforms.blockHeight);\n }\n default: { \n \n }\n }\n\n //Ensure that all threads have swapped their own regions of data\n workgroupBarrier();\n\n //Repopulate global data with local data\n output_data[local_id.x * 2] = local_data[local_id.x * 2];\n output_data[local_id.x * 2 + 1] = local_data[local_id.x * 2 + 1];\n\n}"));var h="src/sample/bitonicSort/main.ts";(i=o||(o={}))[i.NONE=0]="NONE",i[i.FLIP_LOCAL=1]="FLIP_LOCAL",i[i.DISPERSE_LOCAL=2]="DISPERSE_LOCAL",i[i.FLIP_DISPERSE_LOCAL=3]="FLIP_DISPERSE_LOCAL",u(async e=>{let{pageState:n,device:t,gui:r,presentationFormat:i,context:a,canvas:s}=e,u=t.limits.maxComputeWorkgroupSizeX,d=[];for(let c=2*u;c>=4;c/=2)d.push(c);let h={"Total Elements":16,"Grid Width":4,"Grid Height":4,"Total Threads":8,hoveredElement:0,swappedElement:1,"Prev Step":"NONE","Next Step":"FLIP_LOCAL","Prev Swap Span":0,"Next Swap Span":2,workLoads:1,executeStep:!1,"Randomize Values"(){},"Execute Sort Step"(){},"Log Elements"(){},"Complete Sort"(){},sortSpeed:200},f=new Uint32Array(Array.from({length:h["Total Elements"]},(e,n)=>n)),g=512*Float32Array.BYTES_PER_ELEMENT,E=t.createBuffer({size:g,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),v=t.createBuffer({size:g,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),S=t.createBuffer({size:g,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),x=t.createBuffer({size:4*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),b=l([0,1,2],[GPUShaderStage.COMPUTE|GPUShaderStage.FRAGMENT,GPUShaderStage.COMPUTE,GPUShaderStage.COMPUTE],["buffer","buffer","buffer"],[{type:"read-only-storage"},{type:"storage"},{type:"uniform"}],[[{buffer:E},{buffer:v},{buffer:x}]],"NaiveBitonicSort",t),y=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[b.bindGroupLayout]}),compute:{module:t.createShaderModule({code:m(h["Total Threads"])}),entryPoint:"computeMain"}}),_={colorAttachments:[{view:void 0,clearValue:{r:.1,g:.4,b:.5,a:1},loadOp:"clear",storeOp:"store"}]},w=new p(t,i,_,["default"],b,"BitonicDisplay"),P=()=>{U.setValue(h["Total Elements"]/2);let e=Math.sqrt(h["Total Elements"])%2==0?Math.floor(Math.sqrt(h["Total Elements"])):Math.floor(Math.sqrt(h["Total Elements"]/2)),n=h["Total Elements"]/e;V.setValue(e),z.setValue(n),F.setValue("NONE"),k.setValue("FLIP_LOCAL"),M.setValue(0),H.setValue(2),q=2},B=()=>{let e=f.length;for(;0!==e;){let n=Math.floor(Math.random()*e);e-=1,[f[e],f[n]]=[f[n],f[e]]}},G=()=>{f=new Uint32Array(Array.from({length:h["Total Elements"]},(e,n)=>n)),P(),y=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[b.bindGroupLayout]}),compute:{module:t.createShaderModule({code:m(h["Total Elements"]/2)}),entryPoint:"computeMain"}}),B(),q=2};B();let C=()=>{let e;switch(h["Next Step"]){case"FLIP_LOCAL":{let n=h["Next Swap Span"],t=Math.floor(h.hoveredElement/n)+1,r=h.hoveredElement%n;e=n*t-r-1,R.setValue(e)}break;case"DISPERSE_LOCAL":{let i=h["Next Swap Span"],o=i/2;e=h.hoveredElement%i{null!==I&&(clearInterval(I),I=null)},T=()=>{I=setInterval(()=>{"NONE"===h["Next Step"]&&(clearInterval(I),I=null),h.executeStep=!0,C()},h.sortSpeed)};r.add(h,"Total Elements",d).onChange(()=>{L(),G()});let U=r.add(h,"Total Threads"),D=r.addFolder("Sort Controls");D.add(h,"Execute Sort Step").onChange(()=>{L(),h.executeStep=!0}),D.add(h,"Randomize Values").onChange(()=>{L(),B(),P()}),D.add(h,"Log Elements").onChange(()=>console.log(f)),D.add(h,"Complete Sort").onChange(T),D.open();let A=r.addFolder("Hover Information"),N=A.add(h,"hoveredElement").onChange(C),R=A.add(h,"swappedElement"),O=r.addFolder("Execution Information"),F=O.add(h,"Prev Step"),k=O.add(h,"Next Step"),M=O.add(h,"Prev Swap Span"),H=O.add(h,"Next Swap Span"),V=O.add(h,"Grid Width"),z=O.add(h,"Grid Height"),W=document.getElementsByClassName("cr function");for(let j=0;j{let n=s.getBoundingClientRect().width,t=s.getBoundingClientRect().height,r=[n/h["Grid Width"],t/h["Grid Height"]],i=Math.floor(e.offsetX/r[0]),o=h["Grid Height"]-1-Math.floor(e.offsetY/r[1]);N.setValue(o*h["Grid Width"]+i),h.hoveredElement=o*h["Grid Width"]+i}),F.domElement.style.pointerEvents="none",M.domElement.style.pointerEvents="none",k.domElement.style.pointerEvents="none",H.domElement.style.pointerEvents="none",U.domElement.style.pointerEvents="none",V.domElement.style.pointerEvents="none",z.domElement.style.pointerEvents="none";let q=2;async function Y(){if(!n.active)return;t.queue.writeBuffer(E,0,f.buffer,f.byteOffset,f.byteLength);let e=new Float32Array([h["Grid Width"],h["Grid Height"]]),r=new Uint32Array([o[h["Next Step"]],h["Next Swap Span"]]);t.queue.writeBuffer(x,0,e.buffer,e.byteOffset,e.byteLength),t.queue.writeBuffer(x,8,r),_.colorAttachments[0].view=a.getCurrentTexture().createView();let i=t.createCommandEncoder();if(w.startRun(i,{width:h["Grid Width"],height:h["Grid Height"]}),h.executeStep&&q!==2*h["Total Elements"]){let s=i.beginComputePass();s.setPipeline(y),s.setBindGroup(0,b.bindGroups[0]),s.dispatchWorkgroups(1),s.end(),F.setValue(h["Next Step"]),M.setValue(h["Next Swap Span"]),H.setValue(h["Next Swap Span"]/2),1===h["Next Swap Span"]?(q*=2,k.setValue(q===2*h["Total Elements"]?"NONE":"FLIP_LOCAL"),H.setValue(q===2*h["Total Elements"]?0:q)):k.setValue("DISPERSE_LOCAL"),i.copyBufferToBuffer(v,0,S,0,g)}if(t.queue.submit([i.finish()]),h.executeStep){await S.mapAsync(GPUMapMode.READ,0,g);let l=S.getMappedRange(0,g),u=l.slice(0,Uint32Array.BYTES_PER_ELEMENT*h["Total Elements"]),d=new Uint32Array(u);S.unmap(),f=d,C()}h.executeStep=!1,requestAnimationFrame(Y)}requestAnimationFrame(Y)}).then(e=>r=e);let f=()=>(0,a.Tl)({name:"Bitonic Sort",description:"A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each invocation of the bitonic sort shader dispatches a workgroup containing elements/2 threads. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.",init:r,gui:!0,sources:[{name:h.substring(23),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { SampleInitFactoryWebGPU } from './utils';\nimport { createBindGroupDescriptor } from './utils';\nimport BitonicDisplayRenderer from './bitonicDisplay';\nimport bitonicDisplay from './bitonicDisplay.frag.wgsl';\nimport { NaiveBitonicCompute } from './computeShader';\nimport fullscreenTexturedQuad from '../../shaders/fullscreenTexturedQuad.wgsl';\n\n// Type of step that will be executed in our shader\nenum StepEnum {\n NONE = 0,\n FLIP_LOCAL = 1,\n DISPERSE_LOCAL = 2,\n FLIP_DISPERSE_LOCAL = 3,\n}\n\n// String access to StepEnum\ntype StepType =\n | 'NONE'\n | 'FLIP_LOCAL'\n | 'DISPERSE_LOCAL'\n | 'FLIP_DISPERSE_LOCAL';\n\n// Gui settings object\ninterface SettingsInterface {\n 'Total Elements': number;\n 'Grid Width': number;\n 'Grid Height': number;\n 'Total Threads': number;\n hoveredElement: number;\n swappedElement: number;\n 'Prev Step': StepType;\n 'Next Step': StepType;\n 'Prev Swap Span': number;\n 'Next Swap Span': number;\n workLoads: number;\n executeStep: boolean;\n 'Randomize Values': () => void;\n 'Execute Sort Step': () => void;\n 'Log Elements': () => void;\n 'Complete Sort': () => void;\n sortSpeed: number;\n}\n\nlet init: SampleInit;\nSampleInitFactoryWebGPU(\n async ({ pageState, device, gui, presentationFormat, context, canvas }) => {\n const maxWorkgroupsX = device.limits.maxComputeWorkgroupSizeX;\n\n const totalElementLengths = [];\n for (let i = maxWorkgroupsX * 2; i >= 4; i /= 2) {\n totalElementLengths.push(i);\n }\n\n const settings: SettingsInterface = {\n // number of cellElements. Must equal gridWidth * gridHeight and 'Total Threads' * 2\n 'Total Elements': 16,\n // width of screen in cells.\n 'Grid Width': 4,\n // height of screen in cells\n 'Grid Height': 4,\n // number of threads to execute in a workgroup ('Total Threads', 1, 1)\n 'Total Threads': 16 / 2,\n // currently highlighted element\n hoveredElement: 0,\n // element the hoveredElement just swapped with,\n swappedElement: 1,\n // Previously executed step\n 'Prev Step': 'NONE',\n // Next step to execute\n 'Next Step': 'FLIP_LOCAL',\n // Max thread span of previous block\n 'Prev Swap Span': 0,\n // Max thread span of next block\n 'Next Swap Span': 2,\n // workloads to dispatch per frame,\n workLoads: 1,\n // Whether we will dispatch a workload this frame\n executeStep: false,\n 'Randomize Values': () => {\n return;\n },\n 'Execute Sort Step': () => {\n return;\n },\n 'Log Elements': () => {\n return;\n },\n 'Complete Sort': () => {\n return;\n },\n sortSpeed: 200,\n };\n\n // Initialize initial elements array\n let elements = new Uint32Array(\n Array.from({ length: settings['Total Elements'] }, (_, i) => i)\n );\n\n // Initialize elementsBuffer and elementsStagingBuffer\n const elementsBufferSize = Float32Array.BYTES_PER_ELEMENT * 512;\n // Initialize input, output, staging buffers\n const elementsInputBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n const elementsOutputBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n });\n const elementsStagingBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,\n });\n\n // Create uniform buffer for compute shader\n const computeUniformsBuffer = device.createBuffer({\n // width, height, blockHeight, algo\n size: Float32Array.BYTES_PER_ELEMENT * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const computeBGDescript = createBindGroupDescriptor(\n [0, 1, 2],\n [\n GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT,\n GPUShaderStage.COMPUTE,\n GPUShaderStage.COMPUTE,\n ],\n ['buffer', 'buffer', 'buffer'],\n [{ type: 'read-only-storage' }, { type: 'storage' }, { type: 'uniform' }],\n [\n [\n { buffer: elementsInputBuffer },\n { buffer: elementsOutputBuffer },\n { buffer: computeUniformsBuffer },\n ],\n ],\n 'NaiveBitonicSort',\n device\n );\n\n let computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGDescript.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(settings['Total Threads']),\n }),\n entryPoint: 'computeMain',\n },\n });\n\n // Create bitonic debug renderer\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.1, g: 0.4, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const bitonicDisplayRenderer = new BitonicDisplayRenderer(\n device,\n presentationFormat,\n renderPassDescriptor,\n ['default'],\n computeBGDescript,\n 'BitonicDisplay'\n );\n\n const resetExecutionInformation = () => {\n totalThreadsCell.setValue(settings['Total Elements'] / 2);\n\n // Get new width and height of screen display in cells\n const newCellWidth =\n Math.sqrt(settings['Total Elements']) % 2 === 0\n ? Math.floor(Math.sqrt(settings['Total Elements']))\n : Math.floor(Math.sqrt(settings['Total Elements'] / 2));\n const newCellHeight = settings['Total Elements'] / newCellWidth;\n gridWidthCell.setValue(newCellWidth);\n gridHeightCell.setValue(newCellHeight);\n\n // Set prevStep to None (restart) and next step to FLIP\n prevStepCell.setValue('NONE');\n nextStepCell.setValue('FLIP_LOCAL');\n\n // Reset block heights\n prevBlockHeightCell.setValue(0);\n nextBlockHeightCell.setValue(2);\n highestBlockHeight = 2;\n };\n\n const randomizeElementArray = () => {\n let currentIndex = elements.length;\n // While there are elements to shuffle\n while (currentIndex !== 0) {\n // Pick a remaining element\n const randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex -= 1;\n [elements[currentIndex], elements[randomIndex]] = [\n elements[randomIndex],\n elements[currentIndex],\n ];\n }\n };\n\n const resizeElementArray = () => {\n // Recreate elements array with new length\n elements = new Uint32Array(\n Array.from({ length: settings['Total Elements'] }, (_, i) => i)\n );\n\n resetExecutionInformation();\n\n // Create new shader invocation with workgroupSize that reflects number of threads\n computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGDescript.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(settings['Total Elements'] / 2),\n }),\n entryPoint: 'computeMain',\n },\n });\n // Randomize array elements\n randomizeElementArray();\n highestBlockHeight = 2;\n };\n\n randomizeElementArray();\n\n const setSwappedElement = () => {\n let swappedIndex: number;\n switch (settings['Next Step']) {\n case 'FLIP_LOCAL':\n {\n const blockHeight = settings['Next Swap Span'];\n const p2 = Math.floor(settings.hoveredElement / blockHeight) + 1;\n const p3 = settings.hoveredElement % blockHeight;\n swappedIndex = blockHeight * p2 - p3 - 1;\n swappedElementCell.setValue(swappedIndex);\n }\n break;\n case 'DISPERSE_LOCAL':\n {\n const blockHeight = settings['Next Swap Span'];\n const halfHeight = blockHeight / 2;\n swappedIndex =\n settings.hoveredElement % blockHeight < halfHeight\n ? settings.hoveredElement + halfHeight\n : settings.hoveredElement - halfHeight;\n swappedElementCell.setValue(swappedIndex);\n }\n break;\n case 'NONE': {\n swappedIndex = settings.hoveredElement;\n swappedElementCell.setValue(swappedIndex);\n }\n default:\n {\n swappedIndex = settings.hoveredElement;\n swappedElementCell.setValue(swappedIndex);\n }\n break;\n }\n };\n\n let completeSortIntervalID: ReturnType | null = null;\n const endSortInterval = () => {\n if (completeSortIntervalID !== null) {\n clearInterval(completeSortIntervalID);\n completeSortIntervalID = null;\n }\n };\n const startSortInterval = () => {\n completeSortIntervalID = setInterval(() => {\n if (settings['Next Step'] === 'NONE') {\n clearInterval(completeSortIntervalID);\n completeSortIntervalID = null;\n }\n settings.executeStep = true;\n setSwappedElement();\n }, settings.sortSpeed);\n };\n\n // At top level, basic information about the number of elements sorted and the number of threads\n // deployed per workgroup.\n gui.add(settings, 'Total Elements', totalElementLengths).onChange(() => {\n endSortInterval();\n resizeElementArray();\n });\n const totalThreadsCell = gui.add(settings, 'Total Threads');\n\n // Folder with functions that control the execution of the sort\n const controlFolder = gui.addFolder('Sort Controls');\n controlFolder.add(settings, 'Execute Sort Step').onChange(() => {\n endSortInterval();\n settings.executeStep = true;\n });\n controlFolder.add(settings, 'Randomize Values').onChange(() => {\n endSortInterval();\n randomizeElementArray();\n resetExecutionInformation();\n });\n controlFolder\n .add(settings, 'Log Elements')\n .onChange(() => console.log(elements));\n controlFolder.add(settings, 'Complete Sort').onChange(startSortInterval);\n controlFolder.open();\n\n // Folder with indexes of the hovered element\n const hoverFolder = gui.addFolder('Hover Information');\n const hoveredElementCell = hoverFolder\n .add(settings, 'hoveredElement')\n .onChange(setSwappedElement);\n const swappedElementCell = hoverFolder.add(settings, 'swappedElement');\n\n // Additional Information about the execution state of the sort\n const executionInformationFolder = gui.addFolder('Execution Information');\n const prevStepCell = executionInformationFolder.add(settings, 'Prev Step');\n const nextStepCell = executionInformationFolder.add(settings, 'Next Step');\n const prevBlockHeightCell = executionInformationFolder.add(\n settings,\n 'Prev Swap Span'\n );\n const nextBlockHeightCell = executionInformationFolder.add(\n settings,\n 'Next Swap Span'\n );\n const gridWidthCell = executionInformationFolder.add(\n settings,\n 'Grid Width'\n );\n const gridHeightCell = executionInformationFolder.add(\n settings,\n 'Grid Height'\n );\n\n // Adjust styles of Function List Elements within GUI\n const liFunctionElements = document.getElementsByClassName('cr function');\n for (let i = 0; i < liFunctionElements.length; i++) {\n (liFunctionElements[i].children[0] as HTMLElement).style.display = 'flex';\n (liFunctionElements[i].children[0] as HTMLElement).style.justifyContent =\n 'center';\n (\n liFunctionElements[i].children[0].children[1] as HTMLElement\n ).style.position = 'absolute';\n }\n\n canvas.addEventListener('mousemove', (event) => {\n const currWidth = canvas.getBoundingClientRect().width;\n const currHeight = canvas.getBoundingClientRect().height;\n const cellSize: [number, number] = [\n currWidth / settings['Grid Width'],\n currHeight / settings['Grid Height'],\n ];\n const xIndex = Math.floor(event.offsetX / cellSize[0]);\n const yIndex =\n settings['Grid Height'] - 1 - Math.floor(event.offsetY / cellSize[1]);\n hoveredElementCell.setValue(yIndex * settings['Grid Width'] + xIndex);\n settings.hoveredElement = yIndex * settings['Grid Width'] + xIndex;\n });\n\n // Deactivate interaction with select GUI elements\n prevStepCell.domElement.style.pointerEvents = 'none';\n prevBlockHeightCell.domElement.style.pointerEvents = 'none';\n nextStepCell.domElement.style.pointerEvents = 'none';\n nextBlockHeightCell.domElement.style.pointerEvents = 'none';\n totalThreadsCell.domElement.style.pointerEvents = 'none';\n gridWidthCell.domElement.style.pointerEvents = 'none';\n gridHeightCell.domElement.style.pointerEvents = 'none';\n\n let highestBlockHeight = 2;\n\n async function frame() {\n if (!pageState.active) return;\n\n // Write elements buffer\n device.queue.writeBuffer(\n elementsInputBuffer,\n 0,\n elements.buffer,\n elements.byteOffset,\n elements.byteLength\n );\n\n const dims = new Float32Array([\n settings['Grid Width'],\n settings['Grid Height'],\n ]);\n const stepDetails = new Uint32Array([\n StepEnum[settings['Next Step']],\n settings['Next Swap Span'],\n ]);\n device.queue.writeBuffer(\n computeUniformsBuffer,\n 0,\n dims.buffer,\n dims.byteOffset,\n dims.byteLength\n );\n\n device.queue.writeBuffer(computeUniformsBuffer, 8, stepDetails);\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n bitonicDisplayRenderer.startRun(commandEncoder, {\n width: settings['Grid Width'],\n height: settings['Grid Height'],\n });\n if (\n settings.executeStep &&\n highestBlockHeight !== settings['Total Elements'] * 2\n ) {\n const computePassEncoder = commandEncoder.beginComputePass();\n computePassEncoder.setPipeline(computePipeline);\n computePassEncoder.setBindGroup(0, computeBGDescript.bindGroups[0]);\n computePassEncoder.dispatchWorkgroups(1);\n computePassEncoder.end();\n\n prevStepCell.setValue(settings['Next Step']);\n prevBlockHeightCell.setValue(settings['Next Swap Span']);\n nextBlockHeightCell.setValue(settings['Next Swap Span'] / 2);\n if (settings['Next Swap Span'] === 1) {\n highestBlockHeight *= 2;\n nextStepCell.setValue(\n highestBlockHeight === settings['Total Elements'] * 2\n ? 'NONE'\n : 'FLIP_LOCAL'\n );\n nextBlockHeightCell.setValue(\n highestBlockHeight === settings['Total Elements'] * 2\n ? 0\n : highestBlockHeight\n );\n } else {\n nextStepCell.setValue('DISPERSE_LOCAL');\n }\n commandEncoder.copyBufferToBuffer(\n elementsOutputBuffer,\n 0,\n elementsStagingBuffer,\n 0,\n elementsBufferSize\n );\n }\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.executeStep) {\n // Copy GPU element data to CPU\n await elementsStagingBuffer.mapAsync(\n GPUMapMode.READ,\n 0,\n elementsBufferSize\n );\n const copyElementsBuffer = elementsStagingBuffer.getMappedRange(\n 0,\n elementsBufferSize\n );\n // Get correct range of data from CPU copy of GPU Data\n const elementsData = copyElementsBuffer.slice(\n 0,\n Uint32Array.BYTES_PER_ELEMENT * settings['Total Elements']\n );\n // Extract data\n const elementsOutput = new Uint32Array(elementsData);\n elementsStagingBuffer.unmap();\n elements = elementsOutput;\n setSwappedElement();\n }\n settings.executeStep = false;\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n }\n).then((resultInit) => (init = resultInit));\n\nconst bitonicSortExample: () => JSX.Element = () =>\n makeSample({\n name: 'Bitonic Sort',\n description:\n \"A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each invocation of the bitonic sort shader dispatches a workgroup containing elements/2 threads. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.\",\n init,\n gui: true,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n BitonicDisplayRenderer.sourceInfo,\n {\n name: '../../../shaders/fullscreenTexturedQuad.vert.wgsl',\n contents: fullscreenTexturedQuad,\n },\n {\n name: './bitonicDisplay.frag.wgsl',\n contents: bitonicDisplay,\n },\n {\n name: './bitonicCompute.frag.wgsl',\n contents: NaiveBitonicCompute(16),\n },\n ],\n filename: __filename,\n });\n\nexport default bitonicSortExample;\n"},p.sourceInfo,{name:"../../../shaders/fullscreenTexturedQuad.vert.wgsl",contents:s.Z},{name:"./bitonicDisplay.frag.wgsl",contents:c},{name:"./bitonicCompute.frag.wgsl",contents:m(16)}],filename:h});var g=f},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/15.2fa60b27f2d410f8.js b/_next/static/chunks/15.2fa60b27f2d410f8.js deleted file mode 100644 index d2921d10..00000000 --- a/_next/static/chunks/15.2fa60b27f2d410f8.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[15],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,i.useRouter)(),p=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,v]=(0,s.useState)(null),[g,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?x(p[1]):x(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();d&&f.current&&(d.dom.style.position="absolute",d.showPanel(1),f.current.appendChild(d.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:l,stats:d});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":g==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function d(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return o},MO:function(){return i},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,o=32,i=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},9015:function(e,n,t){"use strict";var r="src/sample/rotatingCube/main.ts";t.r(n);var a=t(6416),o=t(5671),i=t(4655),s=t(3569),c=t(1945);let u=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),o=await r.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio||1;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:o,format:f,alphaMode:"premultiplied"});let d=o.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(d.getMappedRange()).set(i.zS),d.unmap();let m=o.createRenderPipeline({layout:"auto",vertex:{module:o.createShaderModule({code:s.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:o.createShaderModule({code:c.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=o.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=o.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=o.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),g={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},x=n.width/n.height,b=a._E.perspective(2*Math.PI/5,x,1,100),w=a._E.create();requestAnimationFrame(function e(){if(!t.active)return;let n=function(){let e=a._E.identity();a._E.translate(e,a.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return a._E.rotate(e,a.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),a._E.multiply(b,e,w),w}();o.queue.writeBuffer(h,0,n.buffer,n.byteOffset,n.byteLength),g.colorAttachments[0].view=u.getCurrentTexture().createView();let r=o.createCommandEncoder(),s=r.beginRenderPass(g);s.setPipeline(m),s.setBindGroup(0,v),s.setVertexBuffer(0,d),s.draw(i.MO),s.end(),o.queue.submit([r.finish()]),requestAnimationFrame(e)})},l=()=>(0,o.Tl)({name:"Rotating Cube",description:"This example shows how to upload uniform data every frame to render a rotating object.",init:u,sources:[{name:r.substring(24),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst RotatingCube: () => JSX.Element = () =>\n makeSample({\n name: 'Rotating Cube',\n description:\n 'This example shows how to upload uniform data every frame to render a rotating object.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default RotatingCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:s.Z,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:c.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/15.61f6ba68172ab7f4.js b/_next/static/chunks/15.61f6ba68172ab7f4.js new file mode 100644 index 00000000..e966652d --- /dev/null +++ b/_next/static/chunks/15.61f6ba68172ab7f4.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[15],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,i.useRouter)(),p=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,v]=(0,s.useState)(null),[g,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?x(p[1]):x(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();d&&f.current&&(d.dom.style.position="absolute",d.showPanel(1),f.current.appendChild(d.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:l,stats:d});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":g==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function d(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return o},MO:function(){return i},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,o=32,i=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},9015:function(e,n,t){"use strict";var r="src/sample/rotatingCube/main.ts";t.r(n);var a=t(6416),o=t(5671),i=t(4655),s=t(3569),c=t(1945);let u=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),o=await r.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:o,format:f,alphaMode:"premultiplied"});let d=o.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(d.getMappedRange()).set(i.zS),d.unmap();let m=o.createRenderPipeline({layout:"auto",vertex:{module:o.createShaderModule({code:s.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:o.createShaderModule({code:c.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=o.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=o.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=o.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),g={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},x=n.width/n.height,b=a._E.perspective(2*Math.PI/5,x,1,100),w=a._E.create();requestAnimationFrame(function e(){if(!t.active)return;let n=function(){let e=a._E.identity();a._E.translate(e,a.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return a._E.rotate(e,a.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),a._E.multiply(b,e,w),w}();o.queue.writeBuffer(h,0,n.buffer,n.byteOffset,n.byteLength),g.colorAttachments[0].view=u.getCurrentTexture().createView();let r=o.createCommandEncoder(),s=r.beginRenderPass(g);s.setPipeline(m),s.setBindGroup(0,v),s.setVertexBuffer(0,d),s.draw(i.MO),s.end(),o.queue.submit([r.finish()]),requestAnimationFrame(e)})},l=()=>(0,o.Tl)({name:"Rotating Cube",description:"This example shows how to upload uniform data every frame to render a rotating object.",init:u,sources:[{name:r.substring(24),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst RotatingCube: () => JSX.Element = () =>\n makeSample({\n name: 'Rotating Cube',\n description:\n 'This example shows how to upload uniform data every frame to render a rotating object.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default RotatingCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:s.Z,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:c.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/167.6de92b4762d053c6.js b/_next/static/chunks/167.6de92b4762d053c6.js new file mode 100644 index 00000000..503e8365 --- /dev/null +++ b/_next/static/chunks/167.6de92b4762d053c6.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[167],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return p}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),l=t.n(u);t(7319);let c=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),m=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,s.useState)(null),[h,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?b(m[1]):b(i[0].name),c&&u.current)for(u.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();p&&d.current&&(p.dom.style.position="absolute",p.showPanel(1),d.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:c,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":h==e.name,onClick(){b(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":h==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function p(e,n){if(!e)throw Error(n)}},6167:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var r=t(6416),i=t(5671),a="////////////////////////////////////////////////////////////////////////////////\n// Utilities\n////////////////////////////////////////////////////////////////////////////////\nvar rand_seed : vec2;\n\nfn init_rand(invocation_id : u32, seed : vec4) {\n rand_seed = seed.xz;\n rand_seed = fract(rand_seed * cos(35.456+f32(invocation_id) * seed.yw));\n rand_seed = fract(rand_seed * cos(41.235+f32(invocation_id) * seed.xw));\n}\n\nfn rand() -> f32 {\n rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168);\n rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645);\n return rand_seed.y;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Vertex shader\n////////////////////////////////////////////////////////////////////////////////\nstruct RenderParams {\n modelViewProjectionMatrix : mat4x4,\n right : vec3,\n up : vec3\n}\n@binding(0) @group(0) var render_params : RenderParams;\n\nstruct VertexInput {\n @location(0) position : vec3,\n @location(1) color : vec4,\n @location(2) quad_pos : vec2, // -1..+1\n}\n\nstruct VertexOutput {\n @builtin(position) position : vec4,\n @location(0) color : vec4,\n @location(1) quad_pos : vec2, // -1..+1\n}\n\n@vertex\nfn vs_main(in : VertexInput) -> VertexOutput {\n var quad_pos = mat2x3(render_params.right, render_params.up) * in.quad_pos;\n var position = in.position + quad_pos * 0.01;\n var out : VertexOutput;\n out.position = render_params.modelViewProjectionMatrix * vec4(position, 1.0);\n out.color = in.color;\n out.quad_pos = in.quad_pos;\n return out;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Fragment shader\n////////////////////////////////////////////////////////////////////////////////\n@fragment\nfn fs_main(in : VertexOutput) -> @location(0) vec4 {\n var color = in.color;\n // Apply a circular particle alpha mask\n color.a = color.a * max(1.0 - length(in.quad_pos), 0.0);\n return color;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Simulation Compute shader\n////////////////////////////////////////////////////////////////////////////////\nstruct SimulationParams {\n deltaTime : f32,\n seed : vec4,\n}\n\nstruct Particle {\n position : vec3,\n lifetime : f32,\n color : vec4,\n velocity : vec3,\n}\n\nstruct Particles {\n particles : array,\n}\n\n@binding(0) @group(0) var sim_params : SimulationParams;\n@binding(1) @group(0) var data : Particles;\n@binding(2) @group(0) var texture : texture_2d;\n\n@compute @workgroup_size(64)\nfn simulate(@builtin(global_invocation_id) global_invocation_id : vec3) {\n let idx = global_invocation_id.x;\n\n init_rand(idx, sim_params.seed);\n\n var particle = data.particles[idx];\n\n // Apply gravity\n particle.velocity.z = particle.velocity.z - sim_params.deltaTime * 0.5;\n\n // Basic velocity integration\n particle.position = particle.position + sim_params.deltaTime * particle.velocity;\n\n // Age each particle. Fade out before vanishing.\n particle.lifetime = particle.lifetime - sim_params.deltaTime;\n particle.color.a = smoothstep(0.0, 0.5, particle.lifetime);\n\n // If the lifetime has gone negative, then the particle is dead and should be\n // respawned.\n if (particle.lifetime < 0.0) {\n // Use the probability map to find where the particle should be spawned.\n // Starting with the 1x1 mip level.\n var coord : vec2;\n for (var level = u32(textureNumLevels(texture) - 1); level > 0; level--) {\n // Load the probability value from the mip-level\n // Generate a random number and using the probabilty values, pick the\n // next texel in the next largest mip level:\n //\n // 0.0 probabilites.r probabilites.g probabilites.b 1.0\n // | | | | |\n // | TOP-LEFT | TOP-RIGHT | BOTTOM-LEFT | BOTTOM_RIGHT |\n //\n let probabilites = textureLoad(texture, coord, level);\n let value = vec4(rand());\n let mask = (value >= vec4(0.0, probabilites.xyz)) & (value < probabilites);\n coord = coord * 2;\n coord.x = coord.x + select(0, 1, any(mask.yw)); // x y\n coord.y = coord.y + select(0, 1, any(mask.zw)); // z w\n }\n let uv = vec2(coord) / vec2(textureDimensions(texture));\n particle.position = vec3((uv - 0.5) * 3.0 * vec2(1.0, -1.0), 0.0);\n particle.color = textureLoad(texture, coord, 0);\n particle.velocity.x = (rand() - 0.5) * 0.1;\n particle.velocity.y = (rand() - 0.5) * 0.1;\n particle.velocity.z = rand() * 0.3;\n particle.lifetime = 0.5 + rand() * 3.0;\n }\n\n // Store the new particle value\n data.particles[idx] = particle;\n}\n",o="struct UBO {\n width : u32,\n}\n\nstruct Buffer {\n weights : array,\n}\n\n@binding(0) @group(0) var ubo : UBO;\n@binding(1) @group(0) var buf_in : Buffer;\n@binding(2) @group(0) var buf_out : Buffer;\n@binding(3) @group(0) var tex_in : texture_2d;\n@binding(3) @group(0) var tex_out : texture_storage_2d;\n\n\n////////////////////////////////////////////////////////////////////////////////\n// import_level\n//\n// Loads the alpha channel from a texel of the source image, and writes it to\n// the buf_out.weights.\n////////////////////////////////////////////////////////////////////////////////\n@compute @workgroup_size(64)\nfn import_level(@builtin(global_invocation_id) coord : vec3) {\n _ = &buf_in;\n let offset = coord.x + coord.y * ubo.width;\n buf_out.weights[offset] = textureLoad(tex_in, vec2(coord.xy), 0).w;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// export_level\n//\n// Loads 4 f32 weight values from buf_in.weights, and stores summed value into\n// buf_out.weights, along with the calculated 'probabilty' vec4 values into the\n// mip level of tex_out. See simulate() in particle.wgsl to understand the\n// probability logic.\n////////////////////////////////////////////////////////////////////////////////\n@compute @workgroup_size(64)\nfn export_level(@builtin(global_invocation_id) coord : vec3) {\n if (all(coord.xy < vec2(textureDimensions(tex_out)))) {\n let dst_offset = coord.x + coord.y * ubo.width;\n let src_offset = coord.x*2u + coord.y*2u * ubo.width;\n\n let a = buf_in.weights[src_offset + 0u];\n let b = buf_in.weights[src_offset + 1u];\n let c = buf_in.weights[src_offset + 0u + ubo.width];\n let d = buf_in.weights[src_offset + 1u + ubo.width];\n let sum = dot(vec4(a, b, c, d), vec4(1.0));\n\n buf_out.weights[dst_offset] = sum / 4.0;\n\n let probabilities = vec4(a, a+b, a+b+c, sum) / max(sum, 0.0001);\n textureStore(tex_out, vec2(coord.xy), probabilities);\n }\n}\n",s="src/sample/particles/main.ts";let u=async e=>{let n,{canvas:i,pageState:s,gui:u}=e,l=await navigator.gpu.requestAdapter(),c=await l.requestDevice();if(!s.active)return;let d=i.getContext("webgpu"),p=window.devicePixelRatio;i.width=i.clientWidth*p,i.height=i.clientHeight*p;let f=navigator.gpu.getPreferredCanvasFormat();d.configure({device:c,format:f,alphaMode:"premultiplied"});let m=c.createBuffer({size:24e5,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE}),v=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:a}),entryPoint:"vs_main",buffers:[{arrayStride:48,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:16,format:"float32x4"}]},{arrayStride:8,stepMode:"vertex",attributes:[{shaderLocation:2,offset:0,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:a}),entryPoint:"fs_main",targets:[{format:f,blend:{color:{srcFactor:"src-alpha",dstFactor:"one",operation:"add"},alpha:{srcFactor:"zero",dstFactor:"one",operation:"add"}}}]},primitive:{topology:"triangle-list"},depthStencil:{depthWriteEnabled:!1,depthCompare:"less",format:"depth24plus"}}),g=c.createTexture({size:[i.width,i.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:96,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),b=c.createBindGroup({layout:v.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),x={colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:g.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},_=c.createBuffer({size:48,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(_.getMappedRange()).set([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),_.unmap();let w=1,P=1,y=1;{let B=await fetch(new t.U(t(9516)).toString()),U=await createImageBitmap(await B.blob());for(;w>O,R=P>>O,z=0==O?E.getBindGroupLayout(0):G.getBindGroupLayout(0),A=c.createBindGroup({layout:z,entries:[{binding:0,resource:{buffer:T}},{binding:1,resource:{buffer:1&O?M:S}},{binding:2,resource:{buffer:1&O?S:M}},{binding:3,resource:n.createView({format:"rgba8unorm",dimension:"2d",baseMipLevel:O,mipLevelCount:1})}]});if(0==O){let F=C.beginComputePass();F.setPipeline(E),F.setBindGroup(0,A),F.dispatchWorkgroups(Math.ceil(L/64),R),F.end()}else{let I=C.beginComputePass();I.setPipeline(G),I.setBindGroup(0,A),I.dispatchWorkgroups(Math.ceil(L/64),R),I.end()}}c.queue.submit([C.finish()])}let V={simulate:!0,deltaTime:.04},q=c.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});Object.keys(V).forEach(e=>{u.add(V,e)});let j=c.createComputePipeline({layout:"auto",compute:{module:c.createShaderModule({code:a}),entryPoint:"simulate"}}),N=c.createBindGroup({layout:j.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:q}},{binding:1,resource:{buffer:m,offset:0,size:24e5}},{binding:2,resource:n.createView()}]}),W=i.width/i.height,k=r._E.perspective(2*Math.PI/5,W,1,100),D=r._E.create(),H=r._E.create();requestAnimationFrame(function e(){if(!s.active)return;c.queue.writeBuffer(q,0,new Float32Array([V.simulate?V.deltaTime:0,0,0,0,100*Math.random(),100*Math.random(),1+Math.random(),1+Math.random()])),r._E.identity(D),r._E.translate(D,r.R3.fromValues(0,0,-3),D),r._E.rotateX(D,-.2*Math.PI,D),r._E.multiply(k,D,H),c.queue.writeBuffer(h,0,new Float32Array([H[0],H[1],H[2],H[3],H[4],H[5],H[6],H[7],H[8],H[9],H[10],H[11],H[12],H[13],H[14],H[15],D[0],D[4],D[8],0,D[1],D[5],D[9],0]));let n=d.getCurrentTexture();x.colorAttachments[0].view=n.createView();let t=c.createCommandEncoder();{let i=t.beginComputePass();i.setPipeline(j),i.setBindGroup(0,N),i.dispatchWorkgroups(Math.ceil(781.25)),i.end()}{let a=t.beginRenderPass(x);a.setPipeline(v),a.setBindGroup(0,b),a.setVertexBuffer(0,m),a.setVertexBuffer(1,_),a.draw(6,5e4,0,0),a.end()}c.queue.submit([t.finish()]),requestAnimationFrame(e)})},l=()=>(0,i.Tl)({name:"Particles",description:"This example demonstrates rendering of particles simulated with compute shaders.",gui:!0,init:u,sources:[{name:s.substring(21),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport particleWGSL from './particle.wgsl';\nimport probabilityMapWGSL from './probabilityMap.wgsl';\n\nconst numParticles = 50000;\nconst particlePositionOffset = 0;\nconst particleColorOffset = 4 * 4;\nconst particleInstanceByteSize =\n 3 * 4 + // position\n 1 * 4 + // lifetime\n 4 * 4 + // color\n 3 * 4 + // velocity\n 1 * 4 + // padding\n 0;\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const particlesBuffer = device.createBuffer({\n size: numParticles * particleInstanceByteSize,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n });\n\n const renderPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'vs_main',\n buffers: [\n {\n // instanced particles buffer\n arrayStride: particleInstanceByteSize,\n stepMode: 'instance',\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: particlePositionOffset,\n format: 'float32x3',\n },\n {\n // color\n shaderLocation: 1,\n offset: particleColorOffset,\n format: 'float32x4',\n },\n ],\n },\n {\n // quad vertex buffer\n arrayStride: 2 * 4, // vec2\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 2,\n offset: 0,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'fs_main',\n targets: [\n {\n format: presentationFormat,\n blend: {\n color: {\n srcFactor: 'src-alpha',\n dstFactor: 'one',\n operation: 'add',\n },\n alpha: {\n srcFactor: 'zero',\n dstFactor: 'one',\n operation: 'add',\n },\n },\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n\n depthStencil: {\n depthWriteEnabled: false,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize =\n 4 * 4 * 4 + // modelViewProjectionMatrix : mat4x4\n 3 * 4 + // right : vec3\n 4 + // padding\n 3 * 4 + // up : vec3\n 4 + // padding\n 0;\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: renderPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n //////////////////////////////////////////////////////////////////////////////\n // Quad vertex buffer\n //////////////////////////////////////////////////////////////////////////////\n const quadVertexBuffer = device.createBuffer({\n size: 6 * 2 * 4, // 6x vec2\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n // prettier-ignore\n const vertexData = [\n -1.0, -1.0, +1.0, -1.0, -1.0, +1.0, -1.0, +1.0, +1.0, -1.0, +1.0, +1.0,\n ];\n new Float32Array(quadVertexBuffer.getMappedRange()).set(vertexData);\n quadVertexBuffer.unmap();\n\n //////////////////////////////////////////////////////////////////////////////\n // Texture\n //////////////////////////////////////////////////////////////////////////////\n let texture: GPUTexture;\n let textureWidth = 1;\n let textureHeight = 1;\n let numMipLevels = 1;\n {\n const response = await fetch(\n new URL('../../../assets/img/webgpu.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n // Calculate number of mip levels required to generate the probability map\n while (\n textureWidth < imageBitmap.width ||\n textureHeight < imageBitmap.height\n ) {\n textureWidth *= 2;\n textureHeight *= 2;\n numMipLevels++;\n }\n texture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n mipLevelCount: numMipLevels,\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: texture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n //////////////////////////////////////////////////////////////////////////////\n // Probability map generation\n // The 0'th mip level of texture holds the color data and spawn-probability in\n // the alpha channel. The mip levels 1..N are generated to hold spawn\n // probabilities up to the top 1x1 mip level.\n //////////////////////////////////////////////////////////////////////////////\n {\n const probabilityMapImportLevelPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({ code: probabilityMapWGSL }),\n entryPoint: 'import_level',\n },\n });\n const probabilityMapExportLevelPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({ code: probabilityMapWGSL }),\n entryPoint: 'export_level',\n },\n });\n\n const probabilityMapUBOBufferSize =\n 1 * 4 + // stride\n 3 * 4 + // padding\n 0;\n const probabilityMapUBOBuffer = device.createBuffer({\n size: probabilityMapUBOBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const buffer_a = device.createBuffer({\n size: textureWidth * textureHeight * 4,\n usage: GPUBufferUsage.STORAGE,\n });\n const buffer_b = device.createBuffer({\n size: textureWidth * textureHeight * 4,\n usage: GPUBufferUsage.STORAGE,\n });\n device.queue.writeBuffer(\n probabilityMapUBOBuffer,\n 0,\n new Int32Array([textureWidth])\n );\n const commandEncoder = device.createCommandEncoder();\n for (let level = 0; level < numMipLevels; level++) {\n const levelWidth = textureWidth >> level;\n const levelHeight = textureHeight >> level;\n const pipeline =\n level == 0\n ? probabilityMapImportLevelPipeline.getBindGroupLayout(0)\n : probabilityMapExportLevelPipeline.getBindGroupLayout(0);\n const probabilityMapBindGroup = device.createBindGroup({\n layout: pipeline,\n entries: [\n {\n // ubo\n binding: 0,\n resource: { buffer: probabilityMapUBOBuffer },\n },\n {\n // buf_in\n binding: 1,\n resource: { buffer: level & 1 ? buffer_a : buffer_b },\n },\n {\n // buf_out\n binding: 2,\n resource: { buffer: level & 1 ? buffer_b : buffer_a },\n },\n {\n // tex_in / tex_out\n binding: 3,\n resource: texture.createView({\n format: 'rgba8unorm',\n dimension: '2d',\n baseMipLevel: level,\n mipLevelCount: 1,\n }),\n },\n ],\n });\n if (level == 0) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(probabilityMapImportLevelPipeline);\n passEncoder.setBindGroup(0, probabilityMapBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(levelWidth / 64), levelHeight);\n passEncoder.end();\n } else {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(probabilityMapExportLevelPipeline);\n passEncoder.setBindGroup(0, probabilityMapBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(levelWidth / 64), levelHeight);\n passEncoder.end();\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n }\n\n //////////////////////////////////////////////////////////////////////////////\n // Simulation compute pipeline\n //////////////////////////////////////////////////////////////////////////////\n const simulationParams = {\n simulate: true,\n deltaTime: 0.04,\n };\n\n const simulationUBOBufferSize =\n 1 * 4 + // deltaTime\n 3 * 4 + // padding\n 4 * 4 + // seed\n 0;\n const simulationUBOBuffer = device.createBuffer({\n size: simulationUBOBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n Object.keys(simulationParams).forEach((k) => {\n gui.add(simulationParams, k);\n });\n\n const computePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'simulate',\n },\n });\n const computeBindGroup = device.createBindGroup({\n layout: computePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: simulationUBOBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: particlesBuffer,\n offset: 0,\n size: numParticles * particleInstanceByteSize,\n },\n },\n {\n binding: 2,\n resource: texture.createView(),\n },\n ],\n });\n\n const aspect = canvas.width / canvas.height;\n const projection = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 100.0);\n const view = mat4.create();\n const mvp = mat4.create();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n device.queue.writeBuffer(\n simulationUBOBuffer,\n 0,\n new Float32Array([\n simulationParams.simulate ? simulationParams.deltaTime : 0.0,\n 0.0,\n 0.0,\n 0.0, // padding\n Math.random() * 100,\n Math.random() * 100, // seed.xy\n 1 + Math.random(),\n 1 + Math.random(), // seed.zw\n ])\n );\n\n mat4.identity(view);\n mat4.translate(view, vec3.fromValues(0, 0, -3), view);\n mat4.rotateX(view, Math.PI * -0.2, view);\n mat4.multiply(projection, view, mvp);\n\n // prettier-ignore\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n new Float32Array([\n // modelViewProjectionMatrix\n mvp[0], mvp[1], mvp[2], mvp[3],\n mvp[4], mvp[5], mvp[6], mvp[7],\n mvp[8], mvp[9], mvp[10], mvp[11],\n mvp[12], mvp[13], mvp[14], mvp[15],\n\n view[0], view[4], view[8], // right\n\n 0, // padding\n\n view[1], view[5], view[9], // up\n\n 0, // padding\n ])\n );\n const swapChainTexture = context.getCurrentTexture();\n // prettier-ignore\n renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(computePipeline);\n passEncoder.setBindGroup(0, computeBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(numParticles / 64));\n passEncoder.end();\n }\n {\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(renderPipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, particlesBuffer);\n passEncoder.setVertexBuffer(1, quadVertexBuffer);\n passEncoder.draw(6, numParticles, 0, 0);\n passEncoder.end();\n }\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst Particles: () => JSX.Element = () =>\n makeSample({\n name: 'Particles',\n description:\n 'This example demonstrates rendering of particles simulated with compute shaders.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './particle.wgsl',\n contents: particleWGSL,\n editable: true,\n },\n {\n name: './probabilityMap.wgsl',\n contents: probabilityMapWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default Particles;\n"},{name:"./particle.wgsl",contents:a,editable:!0},{name:"./probabilityMap.wgsl",contents:o,editable:!0}],filename:s});var c=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},9516:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/webgpu.fd85b973fb5ae811.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/167.97e8a7131bbc2b02.js b/_next/static/chunks/167.97e8a7131bbc2b02.js deleted file mode 100644 index aeaa8b36..00000000 --- a/_next/static/chunks/167.97e8a7131bbc2b02.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[167],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return p}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),l=t.n(u);t(7319);let c=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),m=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,s.useState)(null),[h,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?b(m[1]):b(i[0].name),c&&u.current)for(u.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();p&&d.current&&(p.dom.style.position="absolute",p.showPanel(1),d.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:c,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":h==e.name,onClick(){b(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":h==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function p(e,n){if(!e)throw Error(n)}},6167:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var r=t(6416),i=t(5671),a="////////////////////////////////////////////////////////////////////////////////\n// Utilities\n////////////////////////////////////////////////////////////////////////////////\nvar rand_seed : vec2;\n\nfn init_rand(invocation_id : u32, seed : vec4) {\n rand_seed = seed.xz;\n rand_seed = fract(rand_seed * cos(35.456+f32(invocation_id) * seed.yw));\n rand_seed = fract(rand_seed * cos(41.235+f32(invocation_id) * seed.xw));\n}\n\nfn rand() -> f32 {\n rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168);\n rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645);\n return rand_seed.y;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Vertex shader\n////////////////////////////////////////////////////////////////////////////////\nstruct RenderParams {\n modelViewProjectionMatrix : mat4x4,\n right : vec3,\n up : vec3\n}\n@binding(0) @group(0) var render_params : RenderParams;\n\nstruct VertexInput {\n @location(0) position : vec3,\n @location(1) color : vec4,\n @location(2) quad_pos : vec2, // -1..+1\n}\n\nstruct VertexOutput {\n @builtin(position) position : vec4,\n @location(0) color : vec4,\n @location(1) quad_pos : vec2, // -1..+1\n}\n\n@vertex\nfn vs_main(in : VertexInput) -> VertexOutput {\n var quad_pos = mat2x3(render_params.right, render_params.up) * in.quad_pos;\n var position = in.position + quad_pos * 0.01;\n var out : VertexOutput;\n out.position = render_params.modelViewProjectionMatrix * vec4(position, 1.0);\n out.color = in.color;\n out.quad_pos = in.quad_pos;\n return out;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Fragment shader\n////////////////////////////////////////////////////////////////////////////////\n@fragment\nfn fs_main(in : VertexOutput) -> @location(0) vec4 {\n var color = in.color;\n // Apply a circular particle alpha mask\n color.a = color.a * max(1.0 - length(in.quad_pos), 0.0);\n return color;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Simulation Compute shader\n////////////////////////////////////////////////////////////////////////////////\nstruct SimulationParams {\n deltaTime : f32,\n seed : vec4,\n}\n\nstruct Particle {\n position : vec3,\n lifetime : f32,\n color : vec4,\n velocity : vec3,\n}\n\nstruct Particles {\n particles : array,\n}\n\n@binding(0) @group(0) var sim_params : SimulationParams;\n@binding(1) @group(0) var data : Particles;\n@binding(2) @group(0) var texture : texture_2d;\n\n@compute @workgroup_size(64)\nfn simulate(@builtin(global_invocation_id) global_invocation_id : vec3) {\n let idx = global_invocation_id.x;\n\n init_rand(idx, sim_params.seed);\n\n var particle = data.particles[idx];\n\n // Apply gravity\n particle.velocity.z = particle.velocity.z - sim_params.deltaTime * 0.5;\n\n // Basic velocity integration\n particle.position = particle.position + sim_params.deltaTime * particle.velocity;\n\n // Age each particle. Fade out before vanishing.\n particle.lifetime = particle.lifetime - sim_params.deltaTime;\n particle.color.a = smoothstep(0.0, 0.5, particle.lifetime);\n\n // If the lifetime has gone negative, then the particle is dead and should be\n // respawned.\n if (particle.lifetime < 0.0) {\n // Use the probability map to find where the particle should be spawned.\n // Starting with the 1x1 mip level.\n var coord : vec2;\n for (var level = u32(textureNumLevels(texture) - 1); level > 0; level--) {\n // Load the probability value from the mip-level\n // Generate a random number and using the probabilty values, pick the\n // next texel in the next largest mip level:\n //\n // 0.0 probabilites.r probabilites.g probabilites.b 1.0\n // | | | | |\n // | TOP-LEFT | TOP-RIGHT | BOTTOM-LEFT | BOTTOM_RIGHT |\n //\n let probabilites = textureLoad(texture, coord, level);\n let value = vec4(rand());\n let mask = (value >= vec4(0.0, probabilites.xyz)) & (value < probabilites);\n coord = coord * 2;\n coord.x = coord.x + select(0, 1, any(mask.yw)); // x y\n coord.y = coord.y + select(0, 1, any(mask.zw)); // z w\n }\n let uv = vec2(coord) / vec2(textureDimensions(texture));\n particle.position = vec3((uv - 0.5) * 3.0 * vec2(1.0, -1.0), 0.0);\n particle.color = textureLoad(texture, coord, 0);\n particle.velocity.x = (rand() - 0.5) * 0.1;\n particle.velocity.y = (rand() - 0.5) * 0.1;\n particle.velocity.z = rand() * 0.3;\n particle.lifetime = 0.5 + rand() * 3.0;\n }\n\n // Store the new particle value\n data.particles[idx] = particle;\n}\n",o="struct UBO {\n width : u32,\n}\n\nstruct Buffer {\n weights : array,\n}\n\n@binding(0) @group(0) var ubo : UBO;\n@binding(1) @group(0) var buf_in : Buffer;\n@binding(2) @group(0) var buf_out : Buffer;\n@binding(3) @group(0) var tex_in : texture_2d;\n@binding(3) @group(0) var tex_out : texture_storage_2d;\n\n\n////////////////////////////////////////////////////////////////////////////////\n// import_level\n//\n// Loads the alpha channel from a texel of the source image, and writes it to\n// the buf_out.weights.\n////////////////////////////////////////////////////////////////////////////////\n@compute @workgroup_size(64)\nfn import_level(@builtin(global_invocation_id) coord : vec3) {\n _ = &buf_in;\n let offset = coord.x + coord.y * ubo.width;\n buf_out.weights[offset] = textureLoad(tex_in, vec2(coord.xy), 0).w;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// export_level\n//\n// Loads 4 f32 weight values from buf_in.weights, and stores summed value into\n// buf_out.weights, along with the calculated 'probabilty' vec4 values into the\n// mip level of tex_out. See simulate() in particle.wgsl to understand the\n// probability logic.\n////////////////////////////////////////////////////////////////////////////////\n@compute @workgroup_size(64)\nfn export_level(@builtin(global_invocation_id) coord : vec3) {\n if (all(coord.xy < vec2(textureDimensions(tex_out)))) {\n let dst_offset = coord.x + coord.y * ubo.width;\n let src_offset = coord.x*2u + coord.y*2u * ubo.width;\n\n let a = buf_in.weights[src_offset + 0u];\n let b = buf_in.weights[src_offset + 1u];\n let c = buf_in.weights[src_offset + 0u + ubo.width];\n let d = buf_in.weights[src_offset + 1u + ubo.width];\n let sum = dot(vec4(a, b, c, d), vec4(1.0));\n\n buf_out.weights[dst_offset] = sum / 4.0;\n\n let probabilities = vec4(a, a+b, a+b+c, sum) / max(sum, 0.0001);\n textureStore(tex_out, vec2(coord.xy), probabilities);\n }\n}\n",s="src/sample/particles/main.ts";let u=async e=>{let n,{canvas:i,pageState:s,gui:u}=e,l=await navigator.gpu.requestAdapter(),c=await l.requestDevice();if(!s.active)return;let d=i.getContext("webgpu"),p=window.devicePixelRatio||1;i.width=i.clientWidth*p,i.height=i.clientHeight*p;let f=navigator.gpu.getPreferredCanvasFormat();d.configure({device:c,format:f,alphaMode:"premultiplied"});let m=c.createBuffer({size:24e5,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE}),v=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:a}),entryPoint:"vs_main",buffers:[{arrayStride:48,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:16,format:"float32x4"}]},{arrayStride:8,stepMode:"vertex",attributes:[{shaderLocation:2,offset:0,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:a}),entryPoint:"fs_main",targets:[{format:f,blend:{color:{srcFactor:"src-alpha",dstFactor:"one",operation:"add"},alpha:{srcFactor:"zero",dstFactor:"one",operation:"add"}}}]},primitive:{topology:"triangle-list"},depthStencil:{depthWriteEnabled:!1,depthCompare:"less",format:"depth24plus"}}),g=c.createTexture({size:[i.width,i.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:96,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),b=c.createBindGroup({layout:v.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),x={colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:g.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},_=c.createBuffer({size:48,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(_.getMappedRange()).set([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),_.unmap();let w=1,P=1,y=1;{let B=await fetch(new t.U(t(9516)).toString()),U=await createImageBitmap(await B.blob());for(;w>O,R=P>>O,z=0==O?E.getBindGroupLayout(0):G.getBindGroupLayout(0),A=c.createBindGroup({layout:z,entries:[{binding:0,resource:{buffer:T}},{binding:1,resource:{buffer:1&O?M:S}},{binding:2,resource:{buffer:1&O?S:M}},{binding:3,resource:n.createView({format:"rgba8unorm",dimension:"2d",baseMipLevel:O,mipLevelCount:1})}]});if(0==O){let F=C.beginComputePass();F.setPipeline(E),F.setBindGroup(0,A),F.dispatchWorkgroups(Math.ceil(L/64),R),F.end()}else{let I=C.beginComputePass();I.setPipeline(G),I.setBindGroup(0,A),I.dispatchWorkgroups(Math.ceil(L/64),R),I.end()}}c.queue.submit([C.finish()])}let V={simulate:!0,deltaTime:.04},q=c.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});Object.keys(V).forEach(e=>{u.add(V,e)});let j=c.createComputePipeline({layout:"auto",compute:{module:c.createShaderModule({code:a}),entryPoint:"simulate"}}),N=c.createBindGroup({layout:j.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:q}},{binding:1,resource:{buffer:m,offset:0,size:24e5}},{binding:2,resource:n.createView()}]}),W=i.width/i.height,k=r._E.perspective(2*Math.PI/5,W,1,100),D=r._E.create(),H=r._E.create();requestAnimationFrame(function e(){if(!s.active)return;c.queue.writeBuffer(q,0,new Float32Array([V.simulate?V.deltaTime:0,0,0,0,100*Math.random(),100*Math.random(),1+Math.random(),1+Math.random()])),r._E.identity(D),r._E.translate(D,r.R3.fromValues(0,0,-3),D),r._E.rotateX(D,-.2*Math.PI,D),r._E.multiply(k,D,H),c.queue.writeBuffer(h,0,new Float32Array([H[0],H[1],H[2],H[3],H[4],H[5],H[6],H[7],H[8],H[9],H[10],H[11],H[12],H[13],H[14],H[15],D[0],D[4],D[8],0,D[1],D[5],D[9],0]));let n=d.getCurrentTexture();x.colorAttachments[0].view=n.createView();let t=c.createCommandEncoder();{let i=t.beginComputePass();i.setPipeline(j),i.setBindGroup(0,N),i.dispatchWorkgroups(Math.ceil(781.25)),i.end()}{let a=t.beginRenderPass(x);a.setPipeline(v),a.setBindGroup(0,b),a.setVertexBuffer(0,m),a.setVertexBuffer(1,_),a.draw(6,5e4,0,0),a.end()}c.queue.submit([t.finish()]),requestAnimationFrame(e)})},l=()=>(0,i.Tl)({name:"Particles",description:"This example demonstrates rendering of particles simulated with compute shaders.",gui:!0,init:u,sources:[{name:s.substring(21),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport particleWGSL from './particle.wgsl';\nimport probabilityMapWGSL from './probabilityMap.wgsl';\n\nconst numParticles = 50000;\nconst particlePositionOffset = 0;\nconst particleColorOffset = 4 * 4;\nconst particleInstanceByteSize =\n 3 * 4 + // position\n 1 * 4 + // lifetime\n 4 * 4 + // color\n 3 * 4 + // velocity\n 1 * 4 + // padding\n 0;\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const particlesBuffer = device.createBuffer({\n size: numParticles * particleInstanceByteSize,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n });\n\n const renderPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'vs_main',\n buffers: [\n {\n // instanced particles buffer\n arrayStride: particleInstanceByteSize,\n stepMode: 'instance',\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: particlePositionOffset,\n format: 'float32x3',\n },\n {\n // color\n shaderLocation: 1,\n offset: particleColorOffset,\n format: 'float32x4',\n },\n ],\n },\n {\n // quad vertex buffer\n arrayStride: 2 * 4, // vec2\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 2,\n offset: 0,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'fs_main',\n targets: [\n {\n format: presentationFormat,\n blend: {\n color: {\n srcFactor: 'src-alpha',\n dstFactor: 'one',\n operation: 'add',\n },\n alpha: {\n srcFactor: 'zero',\n dstFactor: 'one',\n operation: 'add',\n },\n },\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n\n depthStencil: {\n depthWriteEnabled: false,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize =\n 4 * 4 * 4 + // modelViewProjectionMatrix : mat4x4\n 3 * 4 + // right : vec3\n 4 + // padding\n 3 * 4 + // up : vec3\n 4 + // padding\n 0;\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: renderPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n //////////////////////////////////////////////////////////////////////////////\n // Quad vertex buffer\n //////////////////////////////////////////////////////////////////////////////\n const quadVertexBuffer = device.createBuffer({\n size: 6 * 2 * 4, // 6x vec2\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n // prettier-ignore\n const vertexData = [\n -1.0, -1.0, +1.0, -1.0, -1.0, +1.0, -1.0, +1.0, +1.0, -1.0, +1.0, +1.0,\n ];\n new Float32Array(quadVertexBuffer.getMappedRange()).set(vertexData);\n quadVertexBuffer.unmap();\n\n //////////////////////////////////////////////////////////////////////////////\n // Texture\n //////////////////////////////////////////////////////////////////////////////\n let texture: GPUTexture;\n let textureWidth = 1;\n let textureHeight = 1;\n let numMipLevels = 1;\n {\n const response = await fetch(\n new URL('../../../assets/img/webgpu.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n // Calculate number of mip levels required to generate the probability map\n while (\n textureWidth < imageBitmap.width ||\n textureHeight < imageBitmap.height\n ) {\n textureWidth *= 2;\n textureHeight *= 2;\n numMipLevels++;\n }\n texture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n mipLevelCount: numMipLevels,\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: texture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n //////////////////////////////////////////////////////////////////////////////\n // Probability map generation\n // The 0'th mip level of texture holds the color data and spawn-probability in\n // the alpha channel. The mip levels 1..N are generated to hold spawn\n // probabilities up to the top 1x1 mip level.\n //////////////////////////////////////////////////////////////////////////////\n {\n const probabilityMapImportLevelPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({ code: probabilityMapWGSL }),\n entryPoint: 'import_level',\n },\n });\n const probabilityMapExportLevelPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({ code: probabilityMapWGSL }),\n entryPoint: 'export_level',\n },\n });\n\n const probabilityMapUBOBufferSize =\n 1 * 4 + // stride\n 3 * 4 + // padding\n 0;\n const probabilityMapUBOBuffer = device.createBuffer({\n size: probabilityMapUBOBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const buffer_a = device.createBuffer({\n size: textureWidth * textureHeight * 4,\n usage: GPUBufferUsage.STORAGE,\n });\n const buffer_b = device.createBuffer({\n size: textureWidth * textureHeight * 4,\n usage: GPUBufferUsage.STORAGE,\n });\n device.queue.writeBuffer(\n probabilityMapUBOBuffer,\n 0,\n new Int32Array([textureWidth])\n );\n const commandEncoder = device.createCommandEncoder();\n for (let level = 0; level < numMipLevels; level++) {\n const levelWidth = textureWidth >> level;\n const levelHeight = textureHeight >> level;\n const pipeline =\n level == 0\n ? probabilityMapImportLevelPipeline.getBindGroupLayout(0)\n : probabilityMapExportLevelPipeline.getBindGroupLayout(0);\n const probabilityMapBindGroup = device.createBindGroup({\n layout: pipeline,\n entries: [\n {\n // ubo\n binding: 0,\n resource: { buffer: probabilityMapUBOBuffer },\n },\n {\n // buf_in\n binding: 1,\n resource: { buffer: level & 1 ? buffer_a : buffer_b },\n },\n {\n // buf_out\n binding: 2,\n resource: { buffer: level & 1 ? buffer_b : buffer_a },\n },\n {\n // tex_in / tex_out\n binding: 3,\n resource: texture.createView({\n format: 'rgba8unorm',\n dimension: '2d',\n baseMipLevel: level,\n mipLevelCount: 1,\n }),\n },\n ],\n });\n if (level == 0) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(probabilityMapImportLevelPipeline);\n passEncoder.setBindGroup(0, probabilityMapBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(levelWidth / 64), levelHeight);\n passEncoder.end();\n } else {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(probabilityMapExportLevelPipeline);\n passEncoder.setBindGroup(0, probabilityMapBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(levelWidth / 64), levelHeight);\n passEncoder.end();\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n }\n\n //////////////////////////////////////////////////////////////////////////////\n // Simulation compute pipeline\n //////////////////////////////////////////////////////////////////////////////\n const simulationParams = {\n simulate: true,\n deltaTime: 0.04,\n };\n\n const simulationUBOBufferSize =\n 1 * 4 + // deltaTime\n 3 * 4 + // padding\n 4 * 4 + // seed\n 0;\n const simulationUBOBuffer = device.createBuffer({\n size: simulationUBOBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n Object.keys(simulationParams).forEach((k) => {\n gui.add(simulationParams, k);\n });\n\n const computePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'simulate',\n },\n });\n const computeBindGroup = device.createBindGroup({\n layout: computePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: simulationUBOBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: particlesBuffer,\n offset: 0,\n size: numParticles * particleInstanceByteSize,\n },\n },\n {\n binding: 2,\n resource: texture.createView(),\n },\n ],\n });\n\n const aspect = canvas.width / canvas.height;\n const projection = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 100.0);\n const view = mat4.create();\n const mvp = mat4.create();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n device.queue.writeBuffer(\n simulationUBOBuffer,\n 0,\n new Float32Array([\n simulationParams.simulate ? simulationParams.deltaTime : 0.0,\n 0.0,\n 0.0,\n 0.0, // padding\n Math.random() * 100,\n Math.random() * 100, // seed.xy\n 1 + Math.random(),\n 1 + Math.random(), // seed.zw\n ])\n );\n\n mat4.identity(view);\n mat4.translate(view, vec3.fromValues(0, 0, -3), view);\n mat4.rotateX(view, Math.PI * -0.2, view);\n mat4.multiply(projection, view, mvp);\n\n // prettier-ignore\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n new Float32Array([\n // modelViewProjectionMatrix\n mvp[0], mvp[1], mvp[2], mvp[3],\n mvp[4], mvp[5], mvp[6], mvp[7],\n mvp[8], mvp[9], mvp[10], mvp[11],\n mvp[12], mvp[13], mvp[14], mvp[15],\n\n view[0], view[4], view[8], // right\n\n 0, // padding\n\n view[1], view[5], view[9], // up\n\n 0, // padding\n ])\n );\n const swapChainTexture = context.getCurrentTexture();\n // prettier-ignore\n renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(computePipeline);\n passEncoder.setBindGroup(0, computeBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(numParticles / 64));\n passEncoder.end();\n }\n {\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(renderPipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, particlesBuffer);\n passEncoder.setVertexBuffer(1, quadVertexBuffer);\n passEncoder.draw(6, numParticles, 0, 0);\n passEncoder.end();\n }\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst Particles: () => JSX.Element = () =>\n makeSample({\n name: 'Particles',\n description:\n 'This example demonstrates rendering of particles simulated with compute shaders.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './particle.wgsl',\n contents: particleWGSL,\n editable: true,\n },\n {\n name: './probabilityMap.wgsl',\n contents: probabilityMapWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default Particles;\n"},{name:"./particle.wgsl",contents:a,editable:!0},{name:"./probabilityMap.wgsl",contents:o,editable:!0}],filename:s});var c=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},9516:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/webgpu.fd85b973fb5ae811.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/198.0fa663559eaabfe3.js b/_next/static/chunks/198.0fa663559eaabfe3.js new file mode 100644 index 00000000..4f47ecd6 --- /dev/null +++ b/_next/static/chunks/198.0fa663559eaabfe3.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[198],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),g=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,h]=(0,s.useState)(null),[f,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?x(g[1]):x(a[0].name),u&&l.current)for(l.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:u,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":f==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":f==e.name},n))]})]})},d=e=>(0,r.jsx)(u,{...e});function m(e,n){if(!e)throw Error(n)}},1198:function(e,n,t){"use strict";var r="src/sample/helloTriangleMSAA/main.ts";t.r(n);var a=t(5671),i=t(1974),o=t(2690);let s=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),a=await r.requestDevice();if(!t.active)return;let s=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let c=navigator.gpu.getPreferredCanvasFormat();s.configure({device:a,format:c,alphaMode:"premultiplied"});let u=a.createRenderPipeline({layout:"auto",vertex:{module:a.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:a.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:c}]},primitive:{topology:"triangle-list"},multisample:{count:4}}),d=a.createTexture({size:[n.width,n.height],sampleCount:4,format:c,usage:GPUTextureUsage.RENDER_ATTACHMENT}),m=d.createView();requestAnimationFrame(function e(){if(!t.active)return;let n=a.createCommandEncoder(),r={colorAttachments:[{view:m,resolveTarget:s.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"discard"}]},i=n.beginRenderPass(r);i.setPipeline(u),i.draw(3),i.end(),a.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Hello Triangle MSAA",description:"Shows multisampled rendering a basic triangle.",init:s,sources:[{name:r.substring(29),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const sampleCount = 4;\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n multisample: {\n count: 4,\n },\n });\n\n const texture = device.createTexture({\n size: [canvas.width, canvas.height],\n sampleCount,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const view = texture.createView();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view,\n resolveTarget: context.getCurrentTexture().createView(),\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'discard',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst HelloTriangleMSAA: () => JSX.Element = () =>\n makeSample({\n name: 'Hello Triangle MSAA',\n description: 'Shows multisampled rendering a basic triangle.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default HelloTriangleMSAA;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/198.126c3f5463c42bd4.js b/_next/static/chunks/198.126c3f5463c42bd4.js deleted file mode 100644 index 86ee8c03..00000000 --- a/_next/static/chunks/198.126c3f5463c42bd4.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[198],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),g=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,h]=(0,s.useState)(null),[f,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?x(g[1]):x(a[0].name),u&&l.current)for(l.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:u,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":f==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":f==e.name},n))]})]})},d=e=>(0,r.jsx)(u,{...e});function m(e,n){if(!e)throw Error(n)}},1198:function(e,n,t){"use strict";var r="src/sample/helloTriangleMSAA/main.ts";t.r(n);var a=t(5671),i=t(1974),o=t(2690);let s=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),a=await r.requestDevice();if(!t.active)return;let s=n.getContext("webgpu"),l=window.devicePixelRatio||1;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let c=navigator.gpu.getPreferredCanvasFormat();s.configure({device:a,format:c,alphaMode:"premultiplied"});let u=a.createRenderPipeline({layout:"auto",vertex:{module:a.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:a.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:c}]},primitive:{topology:"triangle-list"},multisample:{count:4}}),d=a.createTexture({size:[n.width,n.height],sampleCount:4,format:c,usage:GPUTextureUsage.RENDER_ATTACHMENT}),m=d.createView();requestAnimationFrame(function e(){if(!t.active)return;let n=a.createCommandEncoder(),r={colorAttachments:[{view:m,resolveTarget:s.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"discard"}]},i=n.beginRenderPass(r);i.setPipeline(u),i.draw(3),i.end(),a.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Hello Triangle MSAA",description:"Shows multisampled rendering a basic triangle.",init:s,sources:[{name:r.substring(29),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const sampleCount = 4;\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n multisample: {\n count: 4,\n },\n });\n\n const texture = device.createTexture({\n size: [canvas.width, canvas.height],\n sampleCount,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const view = texture.createView();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view,\n resolveTarget: context.getCurrentTexture().createView(),\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'discard',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst HelloTriangleMSAA: () => JSX.Element = () =>\n makeSample({\n name: 'Hello Triangle MSAA',\n description: 'Shows multisampled rendering a basic triangle.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default HelloTriangleMSAA;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/31.5a1cb197b97b4ac7.js b/_next/static/chunks/31.5a1cb197b97b4ac7.js deleted file mode 100644 index 2c3d3667..00000000 --- a/_next/static/chunks/31.5a1cb197b97b4ac7.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[31],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),v=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,f]=(0,s.useState)(null),[x,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(v?h(v[1]):h(a[0].name),u&&l.current)for(l.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:u,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),f(e)})}catch(s){console.error(s),f(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){h(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},d=e=>(0,r.jsx)(u,{...e});function m(e,n){if(!e)throw Error(n)}},7031:function(e,n,t){"use strict";var r="src/sample/videoUploadingWebCodecs/main.ts";t.r(n);var a=t(5671),i=t(134),o=t(7618);let s=async e=>{let{canvas:n,pageState:r,gui:a}=e,s=document.createElement("video");s.loop=!0,s.autoplay=!0,s.muted=!0,s.src=new t.U(t(9082)).toString(),await s.play();let l=await navigator.gpu.requestAdapter(),c=await l.requestDevice();if(!r.active)return;let u=n.getContext("webgpu"),d=window.devicePixelRatio||1;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let m=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:m,alphaMode:"premultiplied"});let p=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:i.Z}),entryPoint:"vert_main"},fragment:{module:c.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"}}),v=c.createSampler({magFilter:"linear",minFilter:"linear"}),g={requestFrame:"requestAnimationFrame"};function f(){if(!r.active)return;let e=new VideoFrame(s),n=c.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:1,resource:v},{binding:2,resource:c.importExternalTexture({source:e})}]}),t=c.createCommandEncoder(),a=u.getCurrentTexture().createView(),i=t.beginRenderPass({colorAttachments:[{view:a,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});i.setPipeline(p),i.setBindGroup(0,n),i.draw(6),i.end(),c.queue.submit([t.finish()]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)}a.add(g,"requestFrame",["requestAnimationFrame","requestVideoFrameCallback"]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)},l=()=>(0,a.Tl)({name:"Video Uploading with WebCodecs",description:"This example shows how to upload a WebCodecs VideoFrame to WebGPU.",gui:!0,init:s,sources:[{name:r.substring(35),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\nimport sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n // Set video element\n const video = document.createElement('video');\n video.loop = true;\n video.autoplay = true;\n video.muted = true;\n video.src = new URL(\n '../../../assets/video/pano.webm',\n import.meta.url\n ).toString();\n await video.play();\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleExternalTextureWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const settings = {\n requestFrame: 'requestAnimationFrame',\n };\n\n gui.add(settings, 'requestFrame', [\n 'requestAnimationFrame',\n 'requestVideoFrameCallback',\n ]);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const videoFrame = new VideoFrame(video);\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: device.importExternalTexture({\n source: videoFrame as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n }),\n },\n ],\n });\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n }\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n};\n\nconst VideoUploadingWebCodecs: () => JSX.Element = () =>\n makeSample({\n name: 'Video Uploading with WebCodecs',\n description: `This example shows how to upload a WebCodecs VideoFrame to WebGPU.`,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n {\n name: '../../shaders/sampleExternalTexture.wgsl',\n contents: sampleExternalTextureWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default VideoUploadingWebCodecs;\n"},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/sampleExternalTexture.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"},7618:function(e,n){"use strict";n.Z="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_external;\n\n@fragment\nfn main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSampleBaseClampToEdge(myTexture, mySampler, fragUV);\n}\n"},9082:function(e,n,t){"use strict";e.exports=t.p+"static/assets/video/pano.5b0db72b3dd7f1b9.webm"}}]); \ No newline at end of file diff --git a/_next/static/chunks/31.f38644969fca04d8.js b/_next/static/chunks/31.f38644969fca04d8.js new file mode 100644 index 00000000..7074a01a --- /dev/null +++ b/_next/static/chunks/31.f38644969fca04d8.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[31],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),v=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,f]=(0,s.useState)(null),[x,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(v?h(v[1]):h(a[0].name),u&&l.current)for(l.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:u,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),f(e)})}catch(s){console.error(s),f(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){h(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},d=e=>(0,r.jsx)(u,{...e});function m(e,n){if(!e)throw Error(n)}},7031:function(e,n,t){"use strict";var r="src/sample/videoUploadingWebCodecs/main.ts";t.r(n);var a=t(5671),i=t(134),o=t(7618);let s=async e=>{let{canvas:n,pageState:r,gui:a}=e,s=document.createElement("video");s.loop=!0,s.autoplay=!0,s.muted=!0,s.src=new t.U(t(9082)).toString(),await s.play();let l=await navigator.gpu.requestAdapter(),c=await l.requestDevice();if(!r.active)return;let u=n.getContext("webgpu"),d=window.devicePixelRatio;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let m=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:m,alphaMode:"premultiplied"});let p=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:i.Z}),entryPoint:"vert_main"},fragment:{module:c.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"}}),v=c.createSampler({magFilter:"linear",minFilter:"linear"}),g={requestFrame:"requestAnimationFrame"};function f(){if(!r.active)return;let e=new VideoFrame(s),n=c.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:1,resource:v},{binding:2,resource:c.importExternalTexture({source:e})}]}),t=c.createCommandEncoder(),a=u.getCurrentTexture().createView(),i=t.beginRenderPass({colorAttachments:[{view:a,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});i.setPipeline(p),i.setBindGroup(0,n),i.draw(6),i.end(),c.queue.submit([t.finish()]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)}a.add(g,"requestFrame",["requestAnimationFrame","requestVideoFrameCallback"]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)},l=()=>(0,a.Tl)({name:"Video Uploading with WebCodecs",description:"This example shows how to upload a WebCodecs VideoFrame to WebGPU.",gui:!0,init:s,sources:[{name:r.substring(35),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\nimport sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n // Set video element\n const video = document.createElement('video');\n video.loop = true;\n video.autoplay = true;\n video.muted = true;\n video.src = new URL(\n '../../../assets/video/pano.webm',\n import.meta.url\n ).toString();\n await video.play();\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleExternalTextureWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const settings = {\n requestFrame: 'requestAnimationFrame',\n };\n\n gui.add(settings, 'requestFrame', [\n 'requestAnimationFrame',\n 'requestVideoFrameCallback',\n ]);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const videoFrame = new VideoFrame(video);\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: device.importExternalTexture({\n source: videoFrame as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n }),\n },\n ],\n });\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n }\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n};\n\nconst VideoUploadingWebCodecs: () => JSX.Element = () =>\n makeSample({\n name: 'Video Uploading with WebCodecs',\n description: `This example shows how to upload a WebCodecs VideoFrame to WebGPU.`,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n {\n name: '../../shaders/sampleExternalTexture.wgsl',\n contents: sampleExternalTextureWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default VideoUploadingWebCodecs;\n"},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/sampleExternalTexture.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"},7618:function(e,n){"use strict";n.Z="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_external;\n\n@fragment\nfn main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSampleBaseClampToEdge(myTexture, mySampler, fragUV);\n}\n"},9082:function(e,n,t){"use strict";e.exports=t.p+"static/assets/video/pano.5b0db72b3dd7f1b9.webm"}}]); \ No newline at end of file diff --git a/_next/static/chunks/342.41eeb4c29bb255cd.js b/_next/static/chunks/342.41eeb4c29bb255cd.js deleted file mode 100644 index 5c233402..00000000 --- a/_next/static/chunks/342.41eeb4c29bb255cd.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[342],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return f}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),u=t(9147),l=t.n(u);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),m=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,g]=(0,s.useState)(null),[v,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?x(m[1]):x(a[0].name),c&&u.current)for(u.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();f&&d.current&&(f.dom.style.position="absolute",f.showPanel(1),d.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:c,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":v==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function f(e,n){if(!e)throw Error(n)}},6888:function(e,n,t){"use strict";t.d(n,{W:function(){return i}});var r=t(6906),a=t(9385);let i={positions:r.m,triangles:r.g,normals:[],uvs:[]};i.normals=(0,a.b)(i.positions,i.triangles),i.uvs=(0,a.q)(i.positions,"xy"),i.triangles.push([i.positions.length,i.positions.length+2,i.positions.length+1],[i.positions.length,i.positions.length+1,i.positions.length+3]),i.positions.push([-100,20,-100],[100,20,100],[-100,20,100],[100,20,-100]),i.normals.push([0,1,0],[0,1,0],[0,1,0],[0,1,0]),i.uvs.push([0,0],[1,1],[0,1],[1,0])},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return a},q:function(){return o}});var r=t(6416);function a(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[a,i,o]=n,s=e[a],u=e[i],l=e[o],c=r.R3.subtract(u,s),d=r.R3.subtract(l,s);r.R3.normalize(c,c),r.R3.normalize(d,d);let f=r.R3.cross(c,d);r.R3.add(t[a],f,t[a]),r.R3.add(t[i],f,t[i]),r.R3.add(t[o],f,t[o])}),t.forEach(e=>{r.R3.normalize(e,e)}),t}let i={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=i[n],r=e.map(()=>[0,0]),a=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{r[n][0]=e[t[0]],r[n][1]=e[t[1]],a[0]=Math.min(e[t[0]],a[0]),a[1]=Math.min(e[t[1]],a[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),r.forEach(e=>{e[0]=(e[0]-a[0])/(o[0]-a[0]),e[1]=(e[1]-a[1])/(o[1]-a[1])}),r}},2342:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),i=t(6888),o="struct Scene {\n lightViewProjMatrix: mat4x4,\n cameraViewProjMatrix: mat4x4,\n lightPos: vec3,\n}\n\nstruct Model {\n modelMatrix: mat4x4,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(1) @binding(0) var model : Model;\n\n@vertex\nfn main(\n @location(0) position: vec3\n) -> @builtin(position) vec4 {\n return scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n}\n",s="struct Scene {\n lightViewProjMatrix: mat4x4,\n cameraViewProjMatrix: mat4x4,\n lightPos: vec3,\n}\n\nstruct Model {\n modelMatrix: mat4x4,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(1) @binding(0) var model : Model;\n\nstruct VertexOutput {\n @location(0) shadowPos: vec3,\n @location(1) fragPos: vec3,\n @location(2) fragNorm: vec3,\n\n @builtin(position) Position: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position: vec3,\n @location(1) normal: vec3\n) -> VertexOutput {\n var output : VertexOutput;\n\n // XY is in (-1, 1) space, Z is in (0, 1) space\n let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n\n // Convert XY to (0, 1)\n // Y is flipped because texture coords are Y-down.\n output.shadowPos = vec3(\n posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),\n posFromLight.z\n );\n\n output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n output.fragPos = output.Position.xyz;\n output.fragNorm = normal;\n return output;\n}\n",u="override shadowDepthTextureSize: f32 = 1024.0;\n\nstruct Scene {\n lightViewProjMatrix : mat4x4,\n cameraViewProjMatrix : mat4x4,\n lightPos : vec3,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(0) @binding(1) var shadowMap: texture_depth_2d;\n@group(0) @binding(2) var shadowSampler: sampler_comparison;\n\nstruct FragmentInput {\n @location(0) shadowPos : vec3,\n @location(1) fragPos : vec3,\n @location(2) fragNorm : vec3,\n}\n\nconst albedo = vec3(0.9);\nconst ambientFactor = 0.2;\n\n@fragment\nfn main(input : FragmentInput) -> @location(0) vec4 {\n // Percentage-closer filtering. Sample texels in the region\n // to smooth the result.\n var visibility = 0.0;\n let oneOverShadowDepthTextureSize = 1.0 / shadowDepthTextureSize;\n for (var y = -1; y <= 1; y++) {\n for (var x = -1; x <= 1; x++) {\n let offset = vec2(vec2(x, y)) * oneOverShadowDepthTextureSize;\n\n visibility += textureSampleCompare(\n shadowMap, shadowSampler,\n input.shadowPos.xy + offset, input.shadowPos.z - 0.007\n );\n }\n }\n visibility /= 9.0;\n\n let lambertFactor = max(dot(normalize(scene.lightPos - input.fragPos), input.fragNorm), 0.0);\n let lightingFactor = min(ambientFactor + visibility * lambertFactor, 1.0);\n\n return vec4(lightingFactor * albedo, 1.0);\n}\n",l="src/sample/shadowMapping/main.ts";let c=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),l=await a.requestDevice();if(!t.active)return;let c=n.getContext("webgpu"),d=window.devicePixelRatio||1;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let f=n.width/n.height,p=navigator.gpu.getPreferredCanvasFormat();c.configure({device:l,format:p,alphaMode:"premultiplied"});let m=l.createBuffer({size:6*i.W.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});{let h=new Float32Array(m.getMappedRange());for(let g=0;g(0,a.Tl)({name:"Shadow Mapping",description:"This example shows how to sample from a depth texture to render shadows.",init:c,sources:[{name:l.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport { mesh } from '../../meshes/stanfordDragon';\n\nimport vertexShadowWGSL from './vertexShadow.wgsl';\nimport vertexWGSL from './vertex.wgsl';\nimport fragmentWGSL from './fragment.wgsl';\n\nconst shadowDepthTextureSize = 1024;\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const aspect = canvas.width / canvas.height;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create the model vertex buffer.\n const vertexBuffer = device.createBuffer({\n size: mesh.positions.length * 3 * 2 * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], 6 * i);\n mapping.set(mesh.normals[i], 6 * i + 3);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer.\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // Create the depth texture for rendering/sampling the shadow map.\n const shadowDepthTexture = device.createTexture({\n size: [shadowDepthTextureSize, shadowDepthTextureSize, 1],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'depth32float',\n });\n const shadowDepthTextureView = shadowDepthTexture.createView();\n\n // Create some common descriptors used for both the shadow pipeline\n // and the color rendering pipeline.\n const vertexBuffers: Iterable = [\n {\n arrayStride: Float32Array.BYTES_PER_ELEMENT * 6,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: Float32Array.BYTES_PER_ELEMENT * 3,\n format: 'float32x3',\n },\n ],\n },\n ];\n\n const primitive: GPUPrimitiveState = {\n topology: 'triangle-list',\n cullMode: 'back',\n };\n\n const uniformBufferBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const shadowPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [\n uniformBufferBindGroupLayout,\n uniformBufferBindGroupLayout,\n ],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexShadowWGSL,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth32float',\n },\n primitive,\n });\n\n // Create a bind group layout which holds the scene uniforms and\n // the texture+sampler for depth. We create it manually because the WebPU\n // implementation doesn't infer this from the shader (yet).\n const bglForRender = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n sampler: {\n type: 'comparison',\n },\n },\n ],\n });\n\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bglForRender, uniformBufferBindGroupLayout],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexWGSL,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n constants: {\n shadowDepthTextureSize,\n },\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus-stencil8',\n },\n primitive,\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus-stencil8',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n stencilClearValue: 0,\n stencilLoadOp: 'clear',\n stencilStoreOp: 'store',\n },\n };\n\n const modelUniformBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneUniformBuffer = device.createBuffer({\n // Two 4x4 viewProj matrices,\n // one for the camera and one for the light.\n // Then a vec3 for the light position.\n // Rounded to the nearest multiple of 16.\n size: 2 * 4 * 16 + 4 * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneBindGroupForShadow = device.createBindGroup({\n layout: uniformBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sceneUniformBuffer,\n },\n },\n ],\n });\n\n const sceneBindGroupForRender = device.createBindGroup({\n layout: bglForRender,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sceneUniformBuffer,\n },\n },\n {\n binding: 1,\n resource: shadowDepthTextureView,\n },\n {\n binding: 2,\n resource: device.createSampler({\n compare: 'less',\n }),\n },\n ],\n });\n\n const modelBindGroup = device.createBindGroup({\n layout: uniformBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: modelUniformBuffer,\n },\n },\n ],\n });\n\n const eyePosition = vec3.fromValues(0, 50, -100);\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n const lightPosition = vec3.fromValues(50, 100, -100);\n const lightViewMatrix = mat4.lookAt(lightPosition, origin, upVector);\n const lightProjectionMatrix = mat4.create();\n {\n const left = -80;\n const right = 80;\n const bottom = -80;\n const top = 80;\n const near = -200;\n const far = 300;\n mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);\n }\n\n const lightViewProjMatrix = mat4.multiply(\n lightProjectionMatrix,\n lightViewMatrix\n );\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n\n // Move the model so it's centered.\n const modelMatrix = mat4.translation([0, -45, 0]);\n\n // The camera/light aren't moving, so write them into buffers now.\n {\n const lightMatrixData = lightViewProjMatrix as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 0,\n lightMatrixData.buffer,\n lightMatrixData.byteOffset,\n lightMatrixData.byteLength\n );\n\n const cameraMatrixData = viewProjMatrix as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 64,\n cameraMatrixData.buffer,\n cameraMatrixData.byteOffset,\n cameraMatrixData.byteLength\n );\n\n const lightData = lightPosition as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 128,\n lightData.buffer,\n lightData.byteOffset,\n lightData.byteLength\n );\n\n const modelData = modelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 0,\n modelData.buffer,\n modelData.byteOffset,\n modelData.byteLength\n );\n }\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const eyePosition = vec3.fromValues(0, 50, -100);\n\n const rad = Math.PI * (Date.now() / 2000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n mat4.multiply(projectionMatrix, viewMatrix, viewProjMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n const shadowPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [],\n depthStencilAttachment: {\n view: shadowDepthTextureView,\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const cameraViewProj = getCameraViewProjMatrix();\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 64,\n cameraViewProj.buffer,\n cameraViewProj.byteOffset,\n cameraViewProj.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const shadowPass = commandEncoder.beginRenderPass(shadowPassDescriptor);\n shadowPass.setPipeline(shadowPipeline);\n shadowPass.setBindGroup(0, sceneBindGroupForShadow);\n shadowPass.setBindGroup(1, modelBindGroup);\n shadowPass.setVertexBuffer(0, vertexBuffer);\n shadowPass.setIndexBuffer(indexBuffer, 'uint16');\n shadowPass.drawIndexed(indexCount);\n\n shadowPass.end();\n }\n {\n const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor);\n renderPass.setPipeline(pipeline);\n renderPass.setBindGroup(0, sceneBindGroupForRender);\n renderPass.setBindGroup(1, modelBindGroup);\n renderPass.setVertexBuffer(0, vertexBuffer);\n renderPass.setIndexBuffer(indexBuffer, 'uint16');\n renderPass.drawIndexed(indexCount);\n\n renderPass.end();\n }\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ShadowMapping: () => JSX.Element = () =>\n makeSample({\n name: 'Shadow Mapping',\n description:\n 'This example shows how to sample from a depth texture to render shadows.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './vertexShadow.wgsl',\n contents: vertexShadowWGSL,\n editable: true,\n },\n {\n name: './vertex.wgsl',\n contents: vertexWGSL,\n editable: true,\n },\n {\n name: './fragment.wgsl',\n contents: fragmentWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ShadowMapping;\n"},{name:"./vertexShadow.wgsl",contents:o,editable:!0},{name:"./vertex.wgsl",contents:s,editable:!0},{name:"./fragment.wgsl",contents:u,editable:!0}],filename:l});var f=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/342.9edc19314eb3dd02.js b/_next/static/chunks/342.9edc19314eb3dd02.js new file mode 100644 index 00000000..b0d6981e --- /dev/null +++ b/_next/static/chunks/342.9edc19314eb3dd02.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[342],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return f}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),u=t(9147),l=t.n(u);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),m=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,g]=(0,s.useState)(null),[v,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?x(m[1]):x(a[0].name),c&&u.current)for(u.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();f&&d.current&&(f.dom.style.position="absolute",f.showPanel(1),d.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:c,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":v==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function f(e,n){if(!e)throw Error(n)}},6888:function(e,n,t){"use strict";t.d(n,{W:function(){return i}});var r=t(6906),a=t(9385);let i={positions:r.m,triangles:r.g,normals:[],uvs:[]};i.normals=(0,a.b)(i.positions,i.triangles),i.uvs=(0,a.q)(i.positions,"xy"),i.triangles.push([i.positions.length,i.positions.length+2,i.positions.length+1],[i.positions.length,i.positions.length+1,i.positions.length+3]),i.positions.push([-100,20,-100],[100,20,100],[-100,20,100],[100,20,-100]),i.normals.push([0,1,0],[0,1,0],[0,1,0],[0,1,0]),i.uvs.push([0,0],[1,1],[0,1],[1,0])},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return a},q:function(){return o}});var r=t(6416);function a(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[a,i,o]=n,s=e[a],u=e[i],l=e[o],c=r.R3.subtract(u,s),d=r.R3.subtract(l,s);r.R3.normalize(c,c),r.R3.normalize(d,d);let f=r.R3.cross(c,d);r.R3.add(t[a],f,t[a]),r.R3.add(t[i],f,t[i]),r.R3.add(t[o],f,t[o])}),t.forEach(e=>{r.R3.normalize(e,e)}),t}let i={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=i[n],r=e.map(()=>[0,0]),a=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{r[n][0]=e[t[0]],r[n][1]=e[t[1]],a[0]=Math.min(e[t[0]],a[0]),a[1]=Math.min(e[t[1]],a[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),r.forEach(e=>{e[0]=(e[0]-a[0])/(o[0]-a[0]),e[1]=(e[1]-a[1])/(o[1]-a[1])}),r}},2342:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),i=t(6888),o="struct Scene {\n lightViewProjMatrix: mat4x4,\n cameraViewProjMatrix: mat4x4,\n lightPos: vec3,\n}\n\nstruct Model {\n modelMatrix: mat4x4,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(1) @binding(0) var model : Model;\n\n@vertex\nfn main(\n @location(0) position: vec3\n) -> @builtin(position) vec4 {\n return scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n}\n",s="struct Scene {\n lightViewProjMatrix: mat4x4,\n cameraViewProjMatrix: mat4x4,\n lightPos: vec3,\n}\n\nstruct Model {\n modelMatrix: mat4x4,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(1) @binding(0) var model : Model;\n\nstruct VertexOutput {\n @location(0) shadowPos: vec3,\n @location(1) fragPos: vec3,\n @location(2) fragNorm: vec3,\n\n @builtin(position) Position: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position: vec3,\n @location(1) normal: vec3\n) -> VertexOutput {\n var output : VertexOutput;\n\n // XY is in (-1, 1) space, Z is in (0, 1) space\n let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n\n // Convert XY to (0, 1)\n // Y is flipped because texture coords are Y-down.\n output.shadowPos = vec3(\n posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),\n posFromLight.z\n );\n\n output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n output.fragPos = output.Position.xyz;\n output.fragNorm = normal;\n return output;\n}\n",u="override shadowDepthTextureSize: f32 = 1024.0;\n\nstruct Scene {\n lightViewProjMatrix : mat4x4,\n cameraViewProjMatrix : mat4x4,\n lightPos : vec3,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(0) @binding(1) var shadowMap: texture_depth_2d;\n@group(0) @binding(2) var shadowSampler: sampler_comparison;\n\nstruct FragmentInput {\n @location(0) shadowPos : vec3,\n @location(1) fragPos : vec3,\n @location(2) fragNorm : vec3,\n}\n\nconst albedo = vec3(0.9);\nconst ambientFactor = 0.2;\n\n@fragment\nfn main(input : FragmentInput) -> @location(0) vec4 {\n // Percentage-closer filtering. Sample texels in the region\n // to smooth the result.\n var visibility = 0.0;\n let oneOverShadowDepthTextureSize = 1.0 / shadowDepthTextureSize;\n for (var y = -1; y <= 1; y++) {\n for (var x = -1; x <= 1; x++) {\n let offset = vec2(vec2(x, y)) * oneOverShadowDepthTextureSize;\n\n visibility += textureSampleCompare(\n shadowMap, shadowSampler,\n input.shadowPos.xy + offset, input.shadowPos.z - 0.007\n );\n }\n }\n visibility /= 9.0;\n\n let lambertFactor = max(dot(normalize(scene.lightPos - input.fragPos), input.fragNorm), 0.0);\n let lightingFactor = min(ambientFactor + visibility * lambertFactor, 1.0);\n\n return vec4(lightingFactor * albedo, 1.0);\n}\n",l="src/sample/shadowMapping/main.ts";let c=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),l=await a.requestDevice();if(!t.active)return;let c=n.getContext("webgpu"),d=window.devicePixelRatio;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let f=n.width/n.height,p=navigator.gpu.getPreferredCanvasFormat();c.configure({device:l,format:p,alphaMode:"premultiplied"});let m=l.createBuffer({size:6*i.W.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});{let h=new Float32Array(m.getMappedRange());for(let g=0;g(0,a.Tl)({name:"Shadow Mapping",description:"This example shows how to sample from a depth texture to render shadows.",init:c,sources:[{name:l.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport { mesh } from '../../meshes/stanfordDragon';\n\nimport vertexShadowWGSL from './vertexShadow.wgsl';\nimport vertexWGSL from './vertex.wgsl';\nimport fragmentWGSL from './fragment.wgsl';\n\nconst shadowDepthTextureSize = 1024;\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const aspect = canvas.width / canvas.height;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create the model vertex buffer.\n const vertexBuffer = device.createBuffer({\n size: mesh.positions.length * 3 * 2 * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], 6 * i);\n mapping.set(mesh.normals[i], 6 * i + 3);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer.\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // Create the depth texture for rendering/sampling the shadow map.\n const shadowDepthTexture = device.createTexture({\n size: [shadowDepthTextureSize, shadowDepthTextureSize, 1],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'depth32float',\n });\n const shadowDepthTextureView = shadowDepthTexture.createView();\n\n // Create some common descriptors used for both the shadow pipeline\n // and the color rendering pipeline.\n const vertexBuffers: Iterable = [\n {\n arrayStride: Float32Array.BYTES_PER_ELEMENT * 6,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: Float32Array.BYTES_PER_ELEMENT * 3,\n format: 'float32x3',\n },\n ],\n },\n ];\n\n const primitive: GPUPrimitiveState = {\n topology: 'triangle-list',\n cullMode: 'back',\n };\n\n const uniformBufferBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const shadowPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [\n uniformBufferBindGroupLayout,\n uniformBufferBindGroupLayout,\n ],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexShadowWGSL,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth32float',\n },\n primitive,\n });\n\n // Create a bind group layout which holds the scene uniforms and\n // the texture+sampler for depth. We create it manually because the WebPU\n // implementation doesn't infer this from the shader (yet).\n const bglForRender = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n sampler: {\n type: 'comparison',\n },\n },\n ],\n });\n\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bglForRender, uniformBufferBindGroupLayout],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexWGSL,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n constants: {\n shadowDepthTextureSize,\n },\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus-stencil8',\n },\n primitive,\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus-stencil8',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n stencilClearValue: 0,\n stencilLoadOp: 'clear',\n stencilStoreOp: 'store',\n },\n };\n\n const modelUniformBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneUniformBuffer = device.createBuffer({\n // Two 4x4 viewProj matrices,\n // one for the camera and one for the light.\n // Then a vec3 for the light position.\n // Rounded to the nearest multiple of 16.\n size: 2 * 4 * 16 + 4 * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneBindGroupForShadow = device.createBindGroup({\n layout: uniformBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sceneUniformBuffer,\n },\n },\n ],\n });\n\n const sceneBindGroupForRender = device.createBindGroup({\n layout: bglForRender,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sceneUniformBuffer,\n },\n },\n {\n binding: 1,\n resource: shadowDepthTextureView,\n },\n {\n binding: 2,\n resource: device.createSampler({\n compare: 'less',\n }),\n },\n ],\n });\n\n const modelBindGroup = device.createBindGroup({\n layout: uniformBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: modelUniformBuffer,\n },\n },\n ],\n });\n\n const eyePosition = vec3.fromValues(0, 50, -100);\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n const lightPosition = vec3.fromValues(50, 100, -100);\n const lightViewMatrix = mat4.lookAt(lightPosition, origin, upVector);\n const lightProjectionMatrix = mat4.create();\n {\n const left = -80;\n const right = 80;\n const bottom = -80;\n const top = 80;\n const near = -200;\n const far = 300;\n mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);\n }\n\n const lightViewProjMatrix = mat4.multiply(\n lightProjectionMatrix,\n lightViewMatrix\n );\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n\n // Move the model so it's centered.\n const modelMatrix = mat4.translation([0, -45, 0]);\n\n // The camera/light aren't moving, so write them into buffers now.\n {\n const lightMatrixData = lightViewProjMatrix as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 0,\n lightMatrixData.buffer,\n lightMatrixData.byteOffset,\n lightMatrixData.byteLength\n );\n\n const cameraMatrixData = viewProjMatrix as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 64,\n cameraMatrixData.buffer,\n cameraMatrixData.byteOffset,\n cameraMatrixData.byteLength\n );\n\n const lightData = lightPosition as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 128,\n lightData.buffer,\n lightData.byteOffset,\n lightData.byteLength\n );\n\n const modelData = modelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 0,\n modelData.buffer,\n modelData.byteOffset,\n modelData.byteLength\n );\n }\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const eyePosition = vec3.fromValues(0, 50, -100);\n\n const rad = Math.PI * (Date.now() / 2000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n mat4.multiply(projectionMatrix, viewMatrix, viewProjMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n const shadowPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [],\n depthStencilAttachment: {\n view: shadowDepthTextureView,\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const cameraViewProj = getCameraViewProjMatrix();\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 64,\n cameraViewProj.buffer,\n cameraViewProj.byteOffset,\n cameraViewProj.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const shadowPass = commandEncoder.beginRenderPass(shadowPassDescriptor);\n shadowPass.setPipeline(shadowPipeline);\n shadowPass.setBindGroup(0, sceneBindGroupForShadow);\n shadowPass.setBindGroup(1, modelBindGroup);\n shadowPass.setVertexBuffer(0, vertexBuffer);\n shadowPass.setIndexBuffer(indexBuffer, 'uint16');\n shadowPass.drawIndexed(indexCount);\n\n shadowPass.end();\n }\n {\n const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor);\n renderPass.setPipeline(pipeline);\n renderPass.setBindGroup(0, sceneBindGroupForRender);\n renderPass.setBindGroup(1, modelBindGroup);\n renderPass.setVertexBuffer(0, vertexBuffer);\n renderPass.setIndexBuffer(indexBuffer, 'uint16');\n renderPass.drawIndexed(indexCount);\n\n renderPass.end();\n }\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ShadowMapping: () => JSX.Element = () =>\n makeSample({\n name: 'Shadow Mapping',\n description:\n 'This example shows how to sample from a depth texture to render shadows.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './vertexShadow.wgsl',\n contents: vertexShadowWGSL,\n editable: true,\n },\n {\n name: './vertex.wgsl',\n contents: vertexWGSL,\n editable: true,\n },\n {\n name: './fragment.wgsl',\n contents: fragmentWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ShadowMapping;\n"},{name:"./vertexShadow.wgsl",contents:o,editable:!0},{name:"./vertex.wgsl",contents:s,editable:!0},{name:"./fragment.wgsl",contents:u,editable:!0}],filename:l});var f=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/391.161ebc918f56881e.js b/_next/static/chunks/391.161ebc918f56881e.js new file mode 100644 index 00000000..e14b5631 --- /dev/null +++ b/_next/static/chunks/391.161ebc918f56881e.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[391],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return f}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),m=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[b,y]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?y(m[1]):y(i[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();f&&l.current&&(f.dom.style.position="absolute",f.showPanel(1),l.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:d,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){y(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":b==e.name},n))]})]})},l=e=>(0,r.jsx)(d,{...e});function f(e,n){if(!e)throw Error(n)}},7391:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return d}});var r=t(5671),i="@binding(0) @group(0) var size: vec2;\n@binding(1) @group(0) var current: array;\n@binding(2) @group(0) var next: array;\n\noverride blockSize = 8;\n\nfn getIndex(x: u32, y: u32) -> u32 {\n let h = size.y;\n let w = size.x;\n\n return (y % h) * w + (x % w);\n}\n\nfn getCell(x: u32, y: u32) -> u32 {\n return current[getIndex(x, y)];\n}\n\nfn countNeighbors(x: u32, y: u32) -> u32 {\n return getCell(x - 1, y - 1) + getCell(x, y - 1) + getCell(x + 1, y - 1) + \n getCell(x - 1, y) + getCell(x + 1, y) + \n getCell(x - 1, y + 1) + getCell(x, y + 1) + getCell(x + 1, y + 1);\n}\n\n@compute @workgroup_size(blockSize, blockSize)\nfn main(@builtin(global_invocation_id) grid: vec3) {\n let x = grid.x;\n let y = grid.y;\n let n = countNeighbors(x, y);\n next[getIndex(x, y)] = select(u32(n == 3u), u32(n == 2u || n == 3u), getCell(x, y) == 1u); \n} \n",a="struct Out {\n @builtin(position) pos: vec4,\n @location(0) cell: f32,\n}\n\n@binding(0) @group(0) var size: vec2;\n\n@vertex\nfn main(@builtin(instance_index) i: u32, @location(0) cell: u32, @location(1) pos: vec2) -> Out {\n let w = size.x;\n let h = size.y;\n let x = (f32(i % w + pos.x) / f32(w) - 0.5) * 2. * f32(w) / f32(max(w, h));\n let y = (f32((i - (i % w)) / w + pos.y) / f32(h) - 0.5) * 2. * f32(h) / f32(max(w, h));\n\n return Out(vec4(x, y, 0., 1.), f32(cell));\n}\n",o="@fragment\nfn main(@location(0) cell: f32) -> @location(0) vec4 {\n return vec4(cell, cell, cell, 1.);\n}\n",s="src/sample/gameOfLife/main.ts";let u=async e=>{let n,t,{canvas:r,pageState:s,gui:u}=e,c=await navigator.gpu.requestAdapter(),d=await c.requestDevice();if(!s.active)return;let l=r.getContext("webgpu"),f=window.devicePixelRatio;r.width=r.clientWidth*f,r.height=r.clientHeight*f;let p=navigator.gpu.getPreferredCanvasFormat();l.configure({device:d,format:p,alphaMode:"premultiplied"});let m={width:128,height:128,timestep:4,workgroupSize:8},g=d.createShaderModule({code:i}),h=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),b=new Uint32Array([0,0,0,1,1,0,1,1]),y=d.createBuffer({size:b.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Uint32Array(y.getMappedRange()).set(b),y.unmap();let v={arrayStride:2*b.BYTES_PER_ELEMENT,stepMode:"vertex",attributes:[{shaderLocation:1,offset:0,format:"uint32x2"}]},G=d.createShaderModule({code:a}),E=d.createShaderModule({code:o}),w=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}}]}),S={arrayStride:Uint32Array.BYTES_PER_ELEMENT,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"uint32"}]},P=0,x=0,U,C;function B(){let e=d.createComputePipeline({layout:d.createPipelineLayout({bindGroupLayouts:[h]}),compute:{module:g,entryPoint:"main",constants:{blockSize:m.workgroupSize}}}),r=d.createBuffer({size:2*Uint32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST|GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Uint32Array(r.getMappedRange()).set([m.width,m.height]),r.unmap();let i=m.width*m.height,a=new Uint32Array(i);for(let o=0;oMath.random()?1:0;U=d.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX,mappedAtCreation:!0}),new Uint32Array(U.getMappedRange()).set(a),U.unmap(),C=d.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX});let s=d.createBindGroup({layout:h,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:U}},{binding:2,resource:{buffer:C}}]}),u=d.createBindGroup({layout:h,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:C}},{binding:2,resource:{buffer:U}}]}),c=d.createRenderPipeline({layout:d.createPipelineLayout({bindGroupLayouts:[w]}),primitive:{topology:"triangle-strip"},vertex:{module:G,entryPoint:"main",buffers:[S,v]},fragment:{module:E,entryPoint:"main",targets:[{format:p}]}}),f=d.createBindGroup({layout:c.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r,offset:0,size:2*Uint32Array.BYTES_PER_ELEMENT}}]});x=0,t=()=>{let t=l.getCurrentTexture().createView();n=d.createCommandEncoder();let r=n.beginComputePass();r.setPipeline(e),r.setBindGroup(0,x?u:s),r.dispatchWorkgroups(m.width/m.workgroupSize,m.height/m.workgroupSize),r.end();let a=n.beginRenderPass({colorAttachments:[{view:t,loadOp:"clear",storeOp:"store"}]});a.setPipeline(c),a.setVertexBuffer(0,x?C:U),a.setVertexBuffer(1,y),a.setBindGroup(0,f),a.draw(4,i),a.end(),d.queue.submit([n.finish()])}}u.add(m,"timestep",1,60,1),u.add(m,"width",16,1024,16).onFinishChange(B),u.add(m,"height",16,1024,16).onFinishChange(B),u.add(m,"workgroupSize",[4,8,16]).onFinishChange(B),B(),function e(){m.timestep&&++P>=m.timestep&&(t(),P-=m.timestep,x=1-x),requestAnimationFrame(e)}()},c=()=>(0,r.Tl)({name:"Conway's Game of Life",description:"This example shows how to make Conway's game of life. First, use compute shader to calculate how cells grow or die. Then use render pipeline to draw cells by using instance mesh.",gui:!0,init:u,sources:[{name:s.substring(22),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport computeWGSL from './compute.wgsl';\nimport vertWGSL from './vert.wgsl';\nimport fragWGSL from './frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const GameOptions = {\n width: 128,\n height: 128,\n timestep: 4,\n workgroupSize: 8,\n };\n\n const computeShader = device.createShaderModule({ code: computeWGSL });\n const bindGroupLayoutCompute = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'storage',\n },\n },\n ],\n });\n\n const squareVertices = new Uint32Array([0, 0, 0, 1, 1, 0, 1, 1]);\n const squareBuffer = device.createBuffer({\n size: squareVertices.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(squareBuffer.getMappedRange()).set(squareVertices);\n squareBuffer.unmap();\n\n const squareStride: GPUVertexBufferLayout = {\n arrayStride: 2 * squareVertices.BYTES_PER_ELEMENT,\n stepMode: 'vertex',\n attributes: [\n {\n shaderLocation: 1,\n offset: 0,\n format: 'uint32x2',\n },\n ],\n };\n\n const vertexShader = device.createShaderModule({ code: vertWGSL });\n const fragmentShader = device.createShaderModule({ code: fragWGSL });\n let commandEncoder: GPUCommandEncoder;\n\n const bindGroupLayoutRender = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const cellsStride: GPUVertexBufferLayout = {\n arrayStride: Uint32Array.BYTES_PER_ELEMENT,\n stepMode: 'instance',\n attributes: [\n {\n shaderLocation: 0,\n offset: 0,\n format: 'uint32',\n },\n ],\n };\n\n function addGUI() {\n gui.add(GameOptions, 'timestep', 1, 60, 1);\n gui.add(GameOptions, 'width', 16, 1024, 16).onFinishChange(resetGameData);\n gui.add(GameOptions, 'height', 16, 1024, 16).onFinishChange(resetGameData);\n gui\n .add(GameOptions, 'workgroupSize', [4, 8, 16])\n .onFinishChange(resetGameData);\n }\n\n let wholeTime = 0,\n loopTimes = 0,\n buffer0: GPUBuffer,\n buffer1: GPUBuffer;\n let render: () => void;\n function resetGameData() {\n // compute pipeline\n const computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bindGroupLayoutCompute],\n }),\n compute: {\n module: computeShader,\n entryPoint: 'main',\n constants: {\n blockSize: GameOptions.workgroupSize,\n },\n },\n });\n const sizeBuffer = device.createBuffer({\n size: 2 * Uint32Array.BYTES_PER_ELEMENT,\n usage:\n GPUBufferUsage.STORAGE |\n GPUBufferUsage.UNIFORM |\n GPUBufferUsage.COPY_DST |\n GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(sizeBuffer.getMappedRange()).set([\n GameOptions.width,\n GameOptions.height,\n ]);\n sizeBuffer.unmap();\n const length = GameOptions.width * GameOptions.height;\n const cells = new Uint32Array(length);\n for (let i = 0; i < length; i++) {\n cells[i] = Math.random() < 0.25 ? 1 : 0;\n }\n\n buffer0 = device.createBuffer({\n size: cells.byteLength,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(buffer0.getMappedRange()).set(cells);\n buffer0.unmap();\n\n buffer1 = device.createBuffer({\n size: cells.byteLength,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX,\n });\n\n const bindGroup0 = device.createBindGroup({\n layout: bindGroupLayoutCompute,\n entries: [\n { binding: 0, resource: { buffer: sizeBuffer } },\n { binding: 1, resource: { buffer: buffer0 } },\n { binding: 2, resource: { buffer: buffer1 } },\n ],\n });\n\n const bindGroup1 = device.createBindGroup({\n layout: bindGroupLayoutCompute,\n entries: [\n { binding: 0, resource: { buffer: sizeBuffer } },\n { binding: 1, resource: { buffer: buffer1 } },\n { binding: 2, resource: { buffer: buffer0 } },\n ],\n });\n\n const renderPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bindGroupLayoutRender],\n }),\n primitive: {\n topology: 'triangle-strip',\n },\n vertex: {\n module: vertexShader,\n entryPoint: 'main',\n buffers: [cellsStride, squareStride],\n },\n fragment: {\n module: fragmentShader,\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: renderPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sizeBuffer,\n offset: 0,\n size: 2 * Uint32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n loopTimes = 0;\n render = () => {\n const view = context.getCurrentTexture().createView();\n const renderPass: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view,\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n commandEncoder = device.createCommandEncoder();\n\n // compute\n const passEncoderCompute = commandEncoder.beginComputePass();\n passEncoderCompute.setPipeline(computePipeline);\n passEncoderCompute.setBindGroup(0, loopTimes ? bindGroup1 : bindGroup0);\n passEncoderCompute.dispatchWorkgroups(\n GameOptions.width / GameOptions.workgroupSize,\n GameOptions.height / GameOptions.workgroupSize\n );\n passEncoderCompute.end();\n // render\n const passEncoderRender = commandEncoder.beginRenderPass(renderPass);\n passEncoderRender.setPipeline(renderPipeline);\n passEncoderRender.setVertexBuffer(0, loopTimes ? buffer1 : buffer0);\n passEncoderRender.setVertexBuffer(1, squareBuffer);\n passEncoderRender.setBindGroup(0, uniformBindGroup);\n passEncoderRender.draw(4, length);\n passEncoderRender.end();\n\n device.queue.submit([commandEncoder.finish()]);\n };\n }\n\n addGUI();\n resetGameData();\n\n (function loop() {\n if (GameOptions.timestep) {\n wholeTime++;\n if (wholeTime >= GameOptions.timestep) {\n render();\n wholeTime -= GameOptions.timestep;\n loopTimes = 1 - loopTimes;\n }\n }\n\n requestAnimationFrame(loop);\n })();\n};\n\nconst GameOfLife: () => JSX.Element = () =>\n makeSample({\n name: \"Conway's Game of Life\",\n description:\n \"This example shows how to make Conway's game of life. First, use compute shader to calculate how cells grow or die. Then use render pipeline to draw cells by using instance mesh.\",\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './gameOfLife.compute.wgsl',\n contents: computeWGSL,\n editable: true,\n },\n {\n name: './gameOfLife.vert.wgsl',\n contents: vertWGSL,\n editable: true,\n },\n {\n name: './gameOfLife.frag.wgsl',\n contents: fragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default GameOfLife;\n"},{name:"./gameOfLife.compute.wgsl",contents:i,editable:!0},{name:"./gameOfLife.vert.wgsl",contents:a,editable:!0},{name:"./gameOfLife.frag.wgsl",contents:o,editable:!0}],filename:s});var d=c},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/391.b1f5391dad769c47.js b/_next/static/chunks/391.b1f5391dad769c47.js deleted file mode 100644 index 344d83b6..00000000 --- a/_next/static/chunks/391.b1f5391dad769c47.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[391],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return f}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),m=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[b,y]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?y(m[1]):y(i[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();f&&l.current&&(f.dom.style.position="absolute",f.showPanel(1),l.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:d,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){y(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":b==e.name},n))]})]})},l=e=>(0,r.jsx)(d,{...e});function f(e,n){if(!e)throw Error(n)}},7391:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return d}});var r=t(5671),i="@binding(0) @group(0) var size: vec2;\n@binding(1) @group(0) var current: array;\n@binding(2) @group(0) var next: array;\n\noverride blockSize = 8;\n\nfn getIndex(x: u32, y: u32) -> u32 {\n let h = size.y;\n let w = size.x;\n\n return (y % h) * w + (x % w);\n}\n\nfn getCell(x: u32, y: u32) -> u32 {\n return current[getIndex(x, y)];\n}\n\nfn countNeighbors(x: u32, y: u32) -> u32 {\n return getCell(x - 1, y - 1) + getCell(x, y - 1) + getCell(x + 1, y - 1) + \n getCell(x - 1, y) + getCell(x + 1, y) + \n getCell(x - 1, y + 1) + getCell(x, y + 1) + getCell(x + 1, y + 1);\n}\n\n@compute @workgroup_size(blockSize, blockSize)\nfn main(@builtin(global_invocation_id) grid: vec3) {\n let x = grid.x;\n let y = grid.y;\n let n = countNeighbors(x, y);\n next[getIndex(x, y)] = select(u32(n == 3u), u32(n == 2u || n == 3u), getCell(x, y) == 1u); \n} \n",a="struct Out {\n @builtin(position) pos: vec4,\n @location(0) cell: f32,\n}\n\n@binding(0) @group(0) var size: vec2;\n\n@vertex\nfn main(@builtin(instance_index) i: u32, @location(0) cell: u32, @location(1) pos: vec2) -> Out {\n let w = size.x;\n let h = size.y;\n let x = (f32(i % w + pos.x) / f32(w) - 0.5) * 2. * f32(w) / f32(max(w, h));\n let y = (f32((i - (i % w)) / w + pos.y) / f32(h) - 0.5) * 2. * f32(h) / f32(max(w, h));\n\n return Out(vec4(x, y, 0., 1.), f32(cell));\n}\n",o="@fragment\nfn main(@location(0) cell: f32) -> @location(0) vec4 {\n return vec4(cell, cell, cell, 1.);\n}\n",s="src/sample/gameOfLife/main.ts";let u=async e=>{let n,t,{canvas:r,pageState:s,gui:u}=e,c=await navigator.gpu.requestAdapter(),d=await c.requestDevice();if(!s.active)return;let l=r.getContext("webgpu"),f=window.devicePixelRatio||1;r.width=r.clientWidth*f,r.height=r.clientHeight*f;let p=navigator.gpu.getPreferredCanvasFormat();l.configure({device:d,format:p,alphaMode:"premultiplied"});let m={width:128,height:128,timestep:4,workgroupSize:8},g=d.createShaderModule({code:i}),h=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),b=new Uint32Array([0,0,0,1,1,0,1,1]),y=d.createBuffer({size:b.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Uint32Array(y.getMappedRange()).set(b),y.unmap();let v={arrayStride:2*b.BYTES_PER_ELEMENT,stepMode:"vertex",attributes:[{shaderLocation:1,offset:0,format:"uint32x2"}]},G=d.createShaderModule({code:a}),E=d.createShaderModule({code:o}),w=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}}]}),S={arrayStride:Uint32Array.BYTES_PER_ELEMENT,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"uint32"}]},P=0,x=0,U,C;function B(){let e=d.createComputePipeline({layout:d.createPipelineLayout({bindGroupLayouts:[h]}),compute:{module:g,entryPoint:"main",constants:{blockSize:m.workgroupSize}}}),r=d.createBuffer({size:2*Uint32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST|GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Uint32Array(r.getMappedRange()).set([m.width,m.height]),r.unmap();let i=m.width*m.height,a=new Uint32Array(i);for(let o=0;oMath.random()?1:0;U=d.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX,mappedAtCreation:!0}),new Uint32Array(U.getMappedRange()).set(a),U.unmap(),C=d.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX});let s=d.createBindGroup({layout:h,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:U}},{binding:2,resource:{buffer:C}}]}),u=d.createBindGroup({layout:h,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:C}},{binding:2,resource:{buffer:U}}]}),c=d.createRenderPipeline({layout:d.createPipelineLayout({bindGroupLayouts:[w]}),primitive:{topology:"triangle-strip"},vertex:{module:G,entryPoint:"main",buffers:[S,v]},fragment:{module:E,entryPoint:"main",targets:[{format:p}]}}),f=d.createBindGroup({layout:c.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r,offset:0,size:2*Uint32Array.BYTES_PER_ELEMENT}}]});x=0,t=()=>{let t=l.getCurrentTexture().createView();n=d.createCommandEncoder();let r=n.beginComputePass();r.setPipeline(e),r.setBindGroup(0,x?u:s),r.dispatchWorkgroups(m.width/m.workgroupSize,m.height/m.workgroupSize),r.end();let a=n.beginRenderPass({colorAttachments:[{view:t,loadOp:"clear",storeOp:"store"}]});a.setPipeline(c),a.setVertexBuffer(0,x?C:U),a.setVertexBuffer(1,y),a.setBindGroup(0,f),a.draw(4,i),a.end(),d.queue.submit([n.finish()])}}u.add(m,"timestep",1,60,1),u.add(m,"width",16,1024,16).onFinishChange(B),u.add(m,"height",16,1024,16).onFinishChange(B),u.add(m,"workgroupSize",[4,8,16]).onFinishChange(B),B(),function e(){m.timestep&&++P>=m.timestep&&(t(),P-=m.timestep,x=1-x),requestAnimationFrame(e)}()},c=()=>(0,r.Tl)({name:"Conway's Game of Life",description:"This example shows how to make Conway's game of life. First, use compute shader to calculate how cells grow or die. Then use render pipeline to draw cells by using instance mesh.",gui:!0,init:u,sources:[{name:s.substring(22),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport computeWGSL from './compute.wgsl';\nimport vertWGSL from './vert.wgsl';\nimport fragWGSL from './frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const GameOptions = {\n width: 128,\n height: 128,\n timestep: 4,\n workgroupSize: 8,\n };\n\n const computeShader = device.createShaderModule({ code: computeWGSL });\n const bindGroupLayoutCompute = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'storage',\n },\n },\n ],\n });\n\n const squareVertices = new Uint32Array([0, 0, 0, 1, 1, 0, 1, 1]);\n const squareBuffer = device.createBuffer({\n size: squareVertices.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(squareBuffer.getMappedRange()).set(squareVertices);\n squareBuffer.unmap();\n\n const squareStride: GPUVertexBufferLayout = {\n arrayStride: 2 * squareVertices.BYTES_PER_ELEMENT,\n stepMode: 'vertex',\n attributes: [\n {\n shaderLocation: 1,\n offset: 0,\n format: 'uint32x2',\n },\n ],\n };\n\n const vertexShader = device.createShaderModule({ code: vertWGSL });\n const fragmentShader = device.createShaderModule({ code: fragWGSL });\n let commandEncoder: GPUCommandEncoder;\n\n const bindGroupLayoutRender = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const cellsStride: GPUVertexBufferLayout = {\n arrayStride: Uint32Array.BYTES_PER_ELEMENT,\n stepMode: 'instance',\n attributes: [\n {\n shaderLocation: 0,\n offset: 0,\n format: 'uint32',\n },\n ],\n };\n\n function addGUI() {\n gui.add(GameOptions, 'timestep', 1, 60, 1);\n gui.add(GameOptions, 'width', 16, 1024, 16).onFinishChange(resetGameData);\n gui.add(GameOptions, 'height', 16, 1024, 16).onFinishChange(resetGameData);\n gui\n .add(GameOptions, 'workgroupSize', [4, 8, 16])\n .onFinishChange(resetGameData);\n }\n\n let wholeTime = 0,\n loopTimes = 0,\n buffer0: GPUBuffer,\n buffer1: GPUBuffer;\n let render: () => void;\n function resetGameData() {\n // compute pipeline\n const computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bindGroupLayoutCompute],\n }),\n compute: {\n module: computeShader,\n entryPoint: 'main',\n constants: {\n blockSize: GameOptions.workgroupSize,\n },\n },\n });\n const sizeBuffer = device.createBuffer({\n size: 2 * Uint32Array.BYTES_PER_ELEMENT,\n usage:\n GPUBufferUsage.STORAGE |\n GPUBufferUsage.UNIFORM |\n GPUBufferUsage.COPY_DST |\n GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(sizeBuffer.getMappedRange()).set([\n GameOptions.width,\n GameOptions.height,\n ]);\n sizeBuffer.unmap();\n const length = GameOptions.width * GameOptions.height;\n const cells = new Uint32Array(length);\n for (let i = 0; i < length; i++) {\n cells[i] = Math.random() < 0.25 ? 1 : 0;\n }\n\n buffer0 = device.createBuffer({\n size: cells.byteLength,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(buffer0.getMappedRange()).set(cells);\n buffer0.unmap();\n\n buffer1 = device.createBuffer({\n size: cells.byteLength,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX,\n });\n\n const bindGroup0 = device.createBindGroup({\n layout: bindGroupLayoutCompute,\n entries: [\n { binding: 0, resource: { buffer: sizeBuffer } },\n { binding: 1, resource: { buffer: buffer0 } },\n { binding: 2, resource: { buffer: buffer1 } },\n ],\n });\n\n const bindGroup1 = device.createBindGroup({\n layout: bindGroupLayoutCompute,\n entries: [\n { binding: 0, resource: { buffer: sizeBuffer } },\n { binding: 1, resource: { buffer: buffer1 } },\n { binding: 2, resource: { buffer: buffer0 } },\n ],\n });\n\n const renderPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bindGroupLayoutRender],\n }),\n primitive: {\n topology: 'triangle-strip',\n },\n vertex: {\n module: vertexShader,\n entryPoint: 'main',\n buffers: [cellsStride, squareStride],\n },\n fragment: {\n module: fragmentShader,\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: renderPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sizeBuffer,\n offset: 0,\n size: 2 * Uint32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n loopTimes = 0;\n render = () => {\n const view = context.getCurrentTexture().createView();\n const renderPass: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view,\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n commandEncoder = device.createCommandEncoder();\n\n // compute\n const passEncoderCompute = commandEncoder.beginComputePass();\n passEncoderCompute.setPipeline(computePipeline);\n passEncoderCompute.setBindGroup(0, loopTimes ? bindGroup1 : bindGroup0);\n passEncoderCompute.dispatchWorkgroups(\n GameOptions.width / GameOptions.workgroupSize,\n GameOptions.height / GameOptions.workgroupSize\n );\n passEncoderCompute.end();\n // render\n const passEncoderRender = commandEncoder.beginRenderPass(renderPass);\n passEncoderRender.setPipeline(renderPipeline);\n passEncoderRender.setVertexBuffer(0, loopTimes ? buffer1 : buffer0);\n passEncoderRender.setVertexBuffer(1, squareBuffer);\n passEncoderRender.setBindGroup(0, uniformBindGroup);\n passEncoderRender.draw(4, length);\n passEncoderRender.end();\n\n device.queue.submit([commandEncoder.finish()]);\n };\n }\n\n addGUI();\n resetGameData();\n\n (function loop() {\n if (GameOptions.timestep) {\n wholeTime++;\n if (wholeTime >= GameOptions.timestep) {\n render();\n wholeTime -= GameOptions.timestep;\n loopTimes = 1 - loopTimes;\n }\n }\n\n requestAnimationFrame(loop);\n })();\n};\n\nconst GameOfLife: () => JSX.Element = () =>\n makeSample({\n name: \"Conway's Game of Life\",\n description:\n \"This example shows how to make Conway's game of life. First, use compute shader to calculate how cells grow or die. Then use render pipeline to draw cells by using instance mesh.\",\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './gameOfLife.compute.wgsl',\n contents: computeWGSL,\n editable: true,\n },\n {\n name: './gameOfLife.vert.wgsl',\n contents: vertWGSL,\n editable: true,\n },\n {\n name: './gameOfLife.frag.wgsl',\n contents: fragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default GameOfLife;\n"},{name:"./gameOfLife.compute.wgsl",contents:i,editable:!0},{name:"./gameOfLife.vert.wgsl",contents:a,editable:!0},{name:"./gameOfLife.frag.wgsl",contents:o,editable:!0}],filename:s});var d=c},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/428.40f695072a94a253.js b/_next/static/chunks/428.40f695072a94a253.js new file mode 100644 index 00000000..ea09d047 --- /dev/null +++ b/_next/static/chunks/428.40f695072a94a253.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[428],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),h=(0,o.useRouter)(),p=h.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,g]=(0,s.useState)(null),[x,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(a[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&l.current&&(m.dom.style.position="absolute",m.showPanel(1),l.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:d,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){v(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},l=e=>(0,r.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},3428:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return d}});var r=t(6416),a=t(5671);let i={vertexStride:32,positionsOffset:0,normalOffset:12,uvOffset:24};var o="struct Uniforms {\n viewProjectionMatrix : mat4x4f\n}\n@group(0) @binding(0) var uniforms : Uniforms;\n\n@group(1) @binding(0) var modelMatrix : mat4x4f;\n\nstruct VertexInput {\n @location(0) position : vec4f,\n @location(1) normal : vec3f,\n @location(2) uv : vec2f\n}\n\nstruct VertexOutput {\n @builtin(position) position : vec4f,\n @location(0) normal: vec3f,\n @location(1) uv : vec2f,\n}\n\n@vertex\nfn vertexMain(input: VertexInput) -> VertexOutput {\n var output : VertexOutput;\n output.position = uniforms.viewProjectionMatrix * modelMatrix * input.position;\n output.normal = normalize((modelMatrix * vec4(input.normal, 0)).xyz);\n output.uv = input.uv;\n return output;\n}\n\n@group(1) @binding(1) var meshSampler: sampler;\n@group(1) @binding(2) var meshTexture: texture_2d;\n\n// Static directional lighting\nconst lightDir = vec3f(1, 1, 1);\nconst dirColor = vec3(1);\nconst ambientColor = vec3f(0.05);\n\n@fragment\nfn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let textureColor = textureSample(meshTexture, meshSampler, input.uv);\n\n // Very simplified lighting algorithm.\n let lightColor = saturate(ambientColor + max(dot(input.normal, lightDir), 0.0) * dirColor);\n\n return vec4f(textureColor.rgb * lightColor, textureColor.a);\n}",s="src/sample/renderBundles/main.ts";let u=async e=>{let n,a,s,{canvas:u,pageState:c,gui:d,stats:l}=e,m=await navigator.gpu.requestAdapter(),h=await m.requestDevice();if(!c.active)return;let p={useRenderBundles:!0,asteroidCount:5e3};d.add(p,"useRenderBundles"),d.add(p,"asteroidCount",1e3,1e4,1e3).onChange(()=>{I(),D()});let f=u.getContext("webgpu"),g=window.devicePixelRatio;u.width=u.clientWidth*g,u.height=u.clientHeight*g;let x=navigator.gpu.getPreferredCanvasFormat();f.configure({device:h,format:x,alphaMode:"premultiplied"});let v=h.createShaderModule({code:o}),b=h.createRenderPipeline({layout:"auto",vertex:{module:v,entryPoint:"vertexMain",buffers:[{arrayStride:i.vertexStride,attributes:[{shaderLocation:0,offset:i.positionsOffset,format:"float32x3"},{shaderLocation:1,offset:i.normalOffset,format:"float32x3"},{shaderLocation:2,offset:i.uvOffset,format:"float32x2"}]}]},fragment:{module:v,entryPoint:"fragmentMain",targets:[{format:x}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),w=h.createTexture({size:[u.width,u.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),y=h.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let M=await fetch(new t.U(t(9836)).toString()),S=await createImageBitmap(await M.blob());n=h.createTexture({size:[S.width,S.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),h.queue.copyExternalImageToTexture({source:S},{texture:n},[S.width,S.height])}{let B=await fetch(new t.U(t(475)).toString()),P=await createImageBitmap(await B.blob());a=h.createTexture({size:[P.width,P.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),h.queue.copyExternalImageToTexture({source:P},{texture:a},[P.width,P.height])}let T=h.createSampler({magFilter:"linear",minFilter:"linear"});function E(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:32,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:16,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=function(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:32,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:16,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=[],o=[];n=Math.max(3,Math.floor(n)),t=Math.max(2,Math.floor(t));let s=r.R3.create(),u=r.R3.create(),c=r.R3.create(),d=0,l=[];for(let m=0;m<=t;m++){let h=[],p=m/t,f=0;0===m?f=.5/n:m===t&&(f=-.5/n);for(let g=0;g<=n;g++){let x=g/n;if(g==n)r.R3.copy(s,u);else if(0==g||0!=m&&m!==t){let v=e+(Math.random()-.5)*2*a*e;u[0]=-v*Math.cos(x*Math.PI*2)*Math.sin(p*Math.PI),u[1]=v*Math.cos(p*Math.PI),u[2]=v*Math.sin(x*Math.PI*2)*Math.sin(p*Math.PI),0==g&&r.R3.copy(u,s)}i.push(...u),r.R3.copy(u,c),r.R3.normalize(c,c),i.push(...c),i.push(x+f,1-p),h.push(d++)}l.push(h)}for(let b=0;bp.asteroidCount)break}function D(){let e=h.createRenderBundleEncoder({colorFormats:[x],depthStencilFormat:"depth24plus"});N(e),s=e.finish()}D(),requestAnimationFrame(function e(){if(!c.active)return;l.begin();let n=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotateZ(e,.1*Math.PI,e),r._E.rotateX(e,.1*Math.PI,e),r._E.rotateY(e,.05*n,e),r._E.multiply(j,e,F),F}();h.queue.writeBuffer(y,0,n.buffer,n.byteOffset,n.byteLength),A.colorAttachments[0].view=f.getCurrentTexture().createView();let t=h.createCommandEncoder(),a=t.beginRenderPass(A);p.useRenderBundles?a.executeBundles([s]):N(a),a.end(),h.queue.submit([t.finish()]),l.end(),requestAnimationFrame(e)})},c=()=>(0,a.Tl)({name:"Render Bundles",description:"This example shows how to use render bundles. It renders a large number of\n meshes individually as a proxy for a more complex scene in order to demonstrate the reduction\n in JavaScript time spent to issue render commands. (Typically a scene like this would make use\n of instancing to reduce draw overhead.)",gui:!0,stats:!0,init:u,sources:[{name:s.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { createSphereMesh, SphereLayout } from '../../meshes/sphere';\n\nimport meshWGSL from './mesh.wgsl';\n\ninterface Renderable {\n vertices: GPUBuffer;\n indices: GPUBuffer;\n indexCount: number;\n bindGroup?: GPUBindGroup;\n}\n\nconst init: SampleInit = async ({ canvas, pageState, gui, stats }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const settings = {\n useRenderBundles: true,\n asteroidCount: 5000,\n };\n gui.add(settings, 'useRenderBundles');\n gui.add(settings, 'asteroidCount', 1000, 10000, 1000).onChange(() => {\n // If the content of the scene changes the render bundle must be recreated.\n ensureEnoughAsteroids();\n updateRenderBundle();\n });\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const shaderModule = device.createShaderModule({\n code: meshWGSL,\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: shaderModule,\n entryPoint: 'vertexMain',\n buffers: [\n {\n arrayStride: SphereLayout.vertexStride,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: SphereLayout.positionsOffset,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: SphereLayout.normalOffset,\n format: 'float32x3',\n },\n {\n // uv\n shaderLocation: 2,\n offset: SphereLayout.uvOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: shaderModule,\n entryPoint: 'fragmentMain',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the sphere is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the images and upload them into a GPUTexture.\n let planetTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/saturn.jpg', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n planetTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: planetTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n let moonTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/moon.jpg', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n moonTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: moonTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n // Helper functions to create the required meshes and bind groups for each sphere.\n function createSphereRenderable(\n radius: number,\n widthSegments = 32,\n heightSegments = 16,\n randomness = 0\n ): Renderable {\n const sphereMesh = createSphereMesh(\n radius,\n widthSegments,\n heightSegments,\n randomness\n );\n\n // Create a vertex buffer from the sphere data.\n const vertices = device.createBuffer({\n size: sphereMesh.vertices.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(vertices.getMappedRange()).set(sphereMesh.vertices);\n vertices.unmap();\n\n const indices = device.createBuffer({\n size: sphereMesh.indices.byteLength,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n new Uint16Array(indices.getMappedRange()).set(sphereMesh.indices);\n indices.unmap();\n\n return {\n vertices,\n indices,\n indexCount: sphereMesh.indices.length,\n };\n }\n\n function createSphereBindGroup(\n texture: GPUTexture,\n transform: Float32Array\n ): GPUBindGroup {\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n mappedAtCreation: true,\n });\n new Float32Array(uniformBuffer.getMappedRange()).set(transform);\n uniformBuffer.unmap();\n\n const bindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: texture.createView(),\n },\n ],\n });\n\n return bindGroup;\n }\n\n const transform = mat4.create() as Float32Array;\n mat4.identity(transform);\n\n // Create one large central planet surrounded by a large ring of asteroids\n const planet = createSphereRenderable(1.0);\n planet.bindGroup = createSphereBindGroup(planetTexture, transform);\n\n const asteroids = [\n createSphereRenderable(0.01, 8, 6, 0.15),\n createSphereRenderable(0.013, 8, 6, 0.15),\n createSphereRenderable(0.017, 8, 6, 0.15),\n createSphereRenderable(0.02, 8, 6, 0.15),\n createSphereRenderable(0.03, 16, 8, 0.15),\n ];\n\n const renderables = [planet];\n\n function ensureEnoughAsteroids() {\n for (let i = renderables.length; i <= settings.asteroidCount; ++i) {\n // Place copies of the asteroid in a ring.\n const radius = Math.random() * 1.7 + 1.25;\n const angle = Math.random() * Math.PI * 2;\n const x = Math.sin(angle) * radius;\n const y = (Math.random() - 0.5) * 0.015;\n const z = Math.cos(angle) * radius;\n\n mat4.identity(transform);\n mat4.translate(transform, [x, y, z], transform);\n mat4.rotateX(transform, Math.random() * Math.PI, transform);\n mat4.rotateY(transform, Math.random() * Math.PI, transform);\n renderables.push({\n ...asteroids[i % asteroids.length],\n bindGroup: createSphereBindGroup(moonTexture, transform),\n });\n }\n }\n ensureEnoughAsteroids();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n const frameBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n // Tilt the view matrix so the planet looks like it's off-axis.\n mat4.rotateZ(viewMatrix, Math.PI * 0.1, viewMatrix);\n mat4.rotateX(viewMatrix, Math.PI * 0.1, viewMatrix);\n // Rotate the view matrix slowly so the planet appears to spin.\n mat4.rotateY(viewMatrix, now * 0.05, viewMatrix);\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n // Render bundles function as partial, limited render passes, so we can use the\n // same code both to render the scene normally and to build the render bundle.\n function renderScene(\n passEncoder: GPURenderPassEncoder | GPURenderBundleEncoder\n ) {\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, frameBindGroup);\n\n // Loop through every renderable object and draw them individually.\n // (Because many of these meshes are repeated, with only the transforms\n // differing, instancing would be highly effective here. This sample\n // intentionally avoids using instancing in order to emulate a more complex\n // scene, which helps demonstrate the potential time savings a render bundle\n // can provide.)\n let count = 0;\n for (const renderable of renderables) {\n passEncoder.setBindGroup(1, renderable.bindGroup);\n passEncoder.setVertexBuffer(0, renderable.vertices);\n passEncoder.setIndexBuffer(renderable.indices, 'uint16');\n passEncoder.drawIndexed(renderable.indexCount);\n\n if (++count > settings.asteroidCount) {\n break;\n }\n }\n }\n\n // The render bundle can be encoded once and re-used as many times as needed.\n // Because it encodes all of the commands needed to render at the GPU level,\n // those commands will not need to execute the associated JavaScript code upon\n // execution or be re-validated, which can represent a significant time savings.\n //\n // However, because render bundles are immutable once created, they are only\n // appropriate for rendering content where the same commands will be executed\n // every time, with the only changes being the contents of the buffers and\n // textures used. Cases where the executed commands differ from frame-to-frame,\n // such as when using frustrum or occlusion culling, will not benefit from\n // using render bundles as much.\n let renderBundle;\n function updateRenderBundle() {\n const renderBundleEncoder = device.createRenderBundleEncoder({\n colorFormats: [presentationFormat],\n depthStencilFormat: 'depth24plus',\n });\n renderScene(renderBundleEncoder);\n renderBundle = renderBundleEncoder.finish();\n }\n updateRenderBundle();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n stats.begin();\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n\n if (settings.useRenderBundles) {\n // Executing a bundle is equivalent to calling all of the commands encoded\n // in the render bundle as part of the current render pass.\n passEncoder.executeBundles([renderBundle]);\n } else {\n // Alternatively, the same render commands can be encoded manually, which\n // can take longer since each command needs to be interpreted by the\n // JavaScript virtual machine and re-validated each time.\n renderScene(passEncoder);\n }\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n stats.end();\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst RenderBundles: () => JSX.Element = () =>\n makeSample({\n name: 'Render Bundles',\n description: `This example shows how to use render bundles. It renders a large number of\n meshes individually as a proxy for a more complex scene in order to demonstrate the reduction\n in JavaScript time spent to issue render commands. (Typically a scene like this would make use\n of instancing to reduce draw overhead.)`,\n gui: true,\n stats: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './mesh.wgsl',\n contents: meshWGSL,\n editable: true,\n },\n {\n name: '../../meshes/sphere.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/sphere.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default RenderBundles;\n"},{name:"./mesh.wgsl",contents:o,editable:!0},{name:"../../meshes/sphere.ts",contents:t(8557).Z}],filename:s});var d=c},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},8557:function(e,n){"use strict";n.Z="import { vec3 } from 'wgpu-matrix';\n\nexport interface SphereMesh {\n vertices: Float32Array;\n indices: Uint16Array;\n}\n\nexport const SphereLayout = {\n vertexStride: 8 * 4,\n positionsOffset: 0,\n normalOffset: 3 * 4,\n uvOffset: 6 * 4,\n};\n\n// Borrowed and simplified from https://github.com/mrdoob/three.js/blob/master/src/geometries/SphereGeometry.js\nexport function createSphereMesh(\n radius: number,\n widthSegments = 32,\n heightSegments = 16,\n randomness = 0\n): SphereMesh {\n const vertices = [];\n const indices = [];\n\n widthSegments = Math.max(3, Math.floor(widthSegments));\n heightSegments = Math.max(2, Math.floor(heightSegments));\n\n const firstVertex = vec3.create();\n const vertex = vec3.create();\n const normal = vec3.create();\n\n let index = 0;\n const grid = [];\n\n // generate vertices, normals and uvs\n for (let iy = 0; iy <= heightSegments; iy++) {\n const verticesRow = [];\n const v = iy / heightSegments;\n\n // special case for the poles\n let uOffset = 0;\n if (iy === 0) {\n uOffset = 0.5 / widthSegments;\n } else if (iy === heightSegments) {\n uOffset = -0.5 / widthSegments;\n }\n\n for (let ix = 0; ix <= widthSegments; ix++) {\n const u = ix / widthSegments;\n\n // Poles should just use the same position all the way around.\n if (ix == widthSegments) {\n vec3.copy(firstVertex, vertex);\n } else if (ix == 0 || (iy != 0 && iy !== heightSegments)) {\n const rr = radius + (Math.random() - 0.5) * 2 * randomness * radius;\n\n // vertex\n vertex[0] = -rr * Math.cos(u * Math.PI * 2) * Math.sin(v * Math.PI);\n vertex[1] = rr * Math.cos(v * Math.PI);\n vertex[2] = rr * Math.sin(u * Math.PI * 2) * Math.sin(v * Math.PI);\n\n if (ix == 0) {\n vec3.copy(vertex, firstVertex);\n }\n }\n\n vertices.push(...vertex);\n\n // normal\n vec3.copy(vertex, normal);\n vec3.normalize(normal, normal);\n vertices.push(...normal);\n\n // uv\n vertices.push(u + uOffset, 1 - v);\n verticesRow.push(index++);\n }\n\n grid.push(verticesRow);\n }\n\n // indices\n for (let iy = 0; iy < heightSegments; iy++) {\n for (let ix = 0; ix < widthSegments; ix++) {\n const a = grid[iy][ix + 1];\n const b = grid[iy][ix];\n const c = grid[iy + 1][ix];\n const d = grid[iy + 1][ix + 1];\n\n if (iy !== 0) indices.push(a, b, d);\n if (iy !== heightSegments - 1) indices.push(b, c, d);\n }\n }\n\n return {\n vertices: new Float32Array(vertices),\n indices: new Uint16Array(indices),\n };\n}\n"},475:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/moon.4c08987edf01a109.jpg"},9836:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/saturn.630a019530ef5704.jpg"}}]); \ No newline at end of file diff --git a/_next/static/chunks/428.fe2387dfb9c8620f.js b/_next/static/chunks/428.fe2387dfb9c8620f.js deleted file mode 100644 index b5e0077a..00000000 --- a/_next/static/chunks/428.fe2387dfb9c8620f.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[428],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),h=(0,o.useRouter)(),p=h.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,g]=(0,s.useState)(null),[x,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(a[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&l.current&&(m.dom.style.position="absolute",m.showPanel(1),l.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:d,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){v(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},l=e=>(0,r.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},3428:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return d}});var r=t(6416),a=t(5671);let i={vertexStride:32,positionsOffset:0,normalOffset:12,uvOffset:24};var o="struct Uniforms {\n viewProjectionMatrix : mat4x4f\n}\n@group(0) @binding(0) var uniforms : Uniforms;\n\n@group(1) @binding(0) var modelMatrix : mat4x4f;\n\nstruct VertexInput {\n @location(0) position : vec4f,\n @location(1) normal : vec3f,\n @location(2) uv : vec2f\n}\n\nstruct VertexOutput {\n @builtin(position) position : vec4f,\n @location(0) normal: vec3f,\n @location(1) uv : vec2f,\n}\n\n@vertex\nfn vertexMain(input: VertexInput) -> VertexOutput {\n var output : VertexOutput;\n output.position = uniforms.viewProjectionMatrix * modelMatrix * input.position;\n output.normal = normalize((modelMatrix * vec4(input.normal, 0)).xyz);\n output.uv = input.uv;\n return output;\n}\n\n@group(1) @binding(1) var meshSampler: sampler;\n@group(1) @binding(2) var meshTexture: texture_2d;\n\n// Static directional lighting\nconst lightDir = vec3f(1, 1, 1);\nconst dirColor = vec3(1);\nconst ambientColor = vec3f(0.05);\n\n@fragment\nfn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let textureColor = textureSample(meshTexture, meshSampler, input.uv);\n\n // Very simplified lighting algorithm.\n let lightColor = saturate(ambientColor + max(dot(input.normal, lightDir), 0.0) * dirColor);\n\n return vec4f(textureColor.rgb * lightColor, textureColor.a);\n}",s="src/sample/renderBundles/main.ts";let u=async e=>{let n,a,s,{canvas:u,pageState:c,gui:d,stats:l}=e,m=await navigator.gpu.requestAdapter(),h=await m.requestDevice();if(!c.active)return;let p={useRenderBundles:!0,asteroidCount:5e3};d.add(p,"useRenderBundles"),d.add(p,"asteroidCount",1e3,1e4,1e3).onChange(()=>{I(),D()});let f=u.getContext("webgpu"),g=window.devicePixelRatio||1;u.width=u.clientWidth*g,u.height=u.clientHeight*g;let x=navigator.gpu.getPreferredCanvasFormat();f.configure({device:h,format:x,alphaMode:"premultiplied"});let v=h.createShaderModule({code:o}),b=h.createRenderPipeline({layout:"auto",vertex:{module:v,entryPoint:"vertexMain",buffers:[{arrayStride:i.vertexStride,attributes:[{shaderLocation:0,offset:i.positionsOffset,format:"float32x3"},{shaderLocation:1,offset:i.normalOffset,format:"float32x3"},{shaderLocation:2,offset:i.uvOffset,format:"float32x2"}]}]},fragment:{module:v,entryPoint:"fragmentMain",targets:[{format:x}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),w=h.createTexture({size:[u.width,u.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),y=h.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let M=await fetch(new t.U(t(9836)).toString()),S=await createImageBitmap(await M.blob());n=h.createTexture({size:[S.width,S.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),h.queue.copyExternalImageToTexture({source:S},{texture:n},[S.width,S.height])}{let B=await fetch(new t.U(t(475)).toString()),P=await createImageBitmap(await B.blob());a=h.createTexture({size:[P.width,P.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),h.queue.copyExternalImageToTexture({source:P},{texture:a},[P.width,P.height])}let T=h.createSampler({magFilter:"linear",minFilter:"linear"});function E(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:32,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:16,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=function(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:32,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:16,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=[],o=[];n=Math.max(3,Math.floor(n)),t=Math.max(2,Math.floor(t));let s=r.R3.create(),u=r.R3.create(),c=r.R3.create(),d=0,l=[];for(let m=0;m<=t;m++){let h=[],p=m/t,f=0;0===m?f=.5/n:m===t&&(f=-.5/n);for(let g=0;g<=n;g++){let x=g/n;if(g==n)r.R3.copy(s,u);else if(0==g||0!=m&&m!==t){let v=e+(Math.random()-.5)*2*a*e;u[0]=-v*Math.cos(x*Math.PI*2)*Math.sin(p*Math.PI),u[1]=v*Math.cos(p*Math.PI),u[2]=v*Math.sin(x*Math.PI*2)*Math.sin(p*Math.PI),0==g&&r.R3.copy(u,s)}i.push(...u),r.R3.copy(u,c),r.R3.normalize(c,c),i.push(...c),i.push(x+f,1-p),h.push(d++)}l.push(h)}for(let b=0;bp.asteroidCount)break}function D(){let e=h.createRenderBundleEncoder({colorFormats:[x],depthStencilFormat:"depth24plus"});N(e),s=e.finish()}D(),requestAnimationFrame(function e(){if(!c.active)return;l.begin();let n=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotateZ(e,.1*Math.PI,e),r._E.rotateX(e,.1*Math.PI,e),r._E.rotateY(e,.05*n,e),r._E.multiply(j,e,F),F}();h.queue.writeBuffer(y,0,n.buffer,n.byteOffset,n.byteLength),A.colorAttachments[0].view=f.getCurrentTexture().createView();let t=h.createCommandEncoder(),a=t.beginRenderPass(A);p.useRenderBundles?a.executeBundles([s]):N(a),a.end(),h.queue.submit([t.finish()]),l.end(),requestAnimationFrame(e)})},c=()=>(0,a.Tl)({name:"Render Bundles",description:"This example shows how to use render bundles. It renders a large number of\n meshes individually as a proxy for a more complex scene in order to demonstrate the reduction\n in JavaScript time spent to issue render commands. (Typically a scene like this would make use\n of instancing to reduce draw overhead.)",gui:!0,stats:!0,init:u,sources:[{name:s.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { createSphereMesh, SphereLayout } from '../../meshes/sphere';\n\nimport meshWGSL from './mesh.wgsl';\n\ninterface Renderable {\n vertices: GPUBuffer;\n indices: GPUBuffer;\n indexCount: number;\n bindGroup?: GPUBindGroup;\n}\n\nconst init: SampleInit = async ({ canvas, pageState, gui, stats }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const settings = {\n useRenderBundles: true,\n asteroidCount: 5000,\n };\n gui.add(settings, 'useRenderBundles');\n gui.add(settings, 'asteroidCount', 1000, 10000, 1000).onChange(() => {\n // If the content of the scene changes the render bundle must be recreated.\n ensureEnoughAsteroids();\n updateRenderBundle();\n });\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const shaderModule = device.createShaderModule({\n code: meshWGSL,\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: shaderModule,\n entryPoint: 'vertexMain',\n buffers: [\n {\n arrayStride: SphereLayout.vertexStride,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: SphereLayout.positionsOffset,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: SphereLayout.normalOffset,\n format: 'float32x3',\n },\n {\n // uv\n shaderLocation: 2,\n offset: SphereLayout.uvOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: shaderModule,\n entryPoint: 'fragmentMain',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the sphere is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the images and upload them into a GPUTexture.\n let planetTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/saturn.jpg', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n planetTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: planetTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n let moonTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/moon.jpg', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n moonTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: moonTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n // Helper functions to create the required meshes and bind groups for each sphere.\n function createSphereRenderable(\n radius: number,\n widthSegments = 32,\n heightSegments = 16,\n randomness = 0\n ): Renderable {\n const sphereMesh = createSphereMesh(\n radius,\n widthSegments,\n heightSegments,\n randomness\n );\n\n // Create a vertex buffer from the sphere data.\n const vertices = device.createBuffer({\n size: sphereMesh.vertices.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(vertices.getMappedRange()).set(sphereMesh.vertices);\n vertices.unmap();\n\n const indices = device.createBuffer({\n size: sphereMesh.indices.byteLength,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n new Uint16Array(indices.getMappedRange()).set(sphereMesh.indices);\n indices.unmap();\n\n return {\n vertices,\n indices,\n indexCount: sphereMesh.indices.length,\n };\n }\n\n function createSphereBindGroup(\n texture: GPUTexture,\n transform: Float32Array\n ): GPUBindGroup {\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n mappedAtCreation: true,\n });\n new Float32Array(uniformBuffer.getMappedRange()).set(transform);\n uniformBuffer.unmap();\n\n const bindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: texture.createView(),\n },\n ],\n });\n\n return bindGroup;\n }\n\n const transform = mat4.create() as Float32Array;\n mat4.identity(transform);\n\n // Create one large central planet surrounded by a large ring of asteroids\n const planet = createSphereRenderable(1.0);\n planet.bindGroup = createSphereBindGroup(planetTexture, transform);\n\n const asteroids = [\n createSphereRenderable(0.01, 8, 6, 0.15),\n createSphereRenderable(0.013, 8, 6, 0.15),\n createSphereRenderable(0.017, 8, 6, 0.15),\n createSphereRenderable(0.02, 8, 6, 0.15),\n createSphereRenderable(0.03, 16, 8, 0.15),\n ];\n\n const renderables = [planet];\n\n function ensureEnoughAsteroids() {\n for (let i = renderables.length; i <= settings.asteroidCount; ++i) {\n // Place copies of the asteroid in a ring.\n const radius = Math.random() * 1.7 + 1.25;\n const angle = Math.random() * Math.PI * 2;\n const x = Math.sin(angle) * radius;\n const y = (Math.random() - 0.5) * 0.015;\n const z = Math.cos(angle) * radius;\n\n mat4.identity(transform);\n mat4.translate(transform, [x, y, z], transform);\n mat4.rotateX(transform, Math.random() * Math.PI, transform);\n mat4.rotateY(transform, Math.random() * Math.PI, transform);\n renderables.push({\n ...asteroids[i % asteroids.length],\n bindGroup: createSphereBindGroup(moonTexture, transform),\n });\n }\n }\n ensureEnoughAsteroids();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n const frameBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n // Tilt the view matrix so the planet looks like it's off-axis.\n mat4.rotateZ(viewMatrix, Math.PI * 0.1, viewMatrix);\n mat4.rotateX(viewMatrix, Math.PI * 0.1, viewMatrix);\n // Rotate the view matrix slowly so the planet appears to spin.\n mat4.rotateY(viewMatrix, now * 0.05, viewMatrix);\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n // Render bundles function as partial, limited render passes, so we can use the\n // same code both to render the scene normally and to build the render bundle.\n function renderScene(\n passEncoder: GPURenderPassEncoder | GPURenderBundleEncoder\n ) {\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, frameBindGroup);\n\n // Loop through every renderable object and draw them individually.\n // (Because many of these meshes are repeated, with only the transforms\n // differing, instancing would be highly effective here. This sample\n // intentionally avoids using instancing in order to emulate a more complex\n // scene, which helps demonstrate the potential time savings a render bundle\n // can provide.)\n let count = 0;\n for (const renderable of renderables) {\n passEncoder.setBindGroup(1, renderable.bindGroup);\n passEncoder.setVertexBuffer(0, renderable.vertices);\n passEncoder.setIndexBuffer(renderable.indices, 'uint16');\n passEncoder.drawIndexed(renderable.indexCount);\n\n if (++count > settings.asteroidCount) {\n break;\n }\n }\n }\n\n // The render bundle can be encoded once and re-used as many times as needed.\n // Because it encodes all of the commands needed to render at the GPU level,\n // those commands will not need to execute the associated JavaScript code upon\n // execution or be re-validated, which can represent a significant time savings.\n //\n // However, because render bundles are immutable once created, they are only\n // appropriate for rendering content where the same commands will be executed\n // every time, with the only changes being the contents of the buffers and\n // textures used. Cases where the executed commands differ from frame-to-frame,\n // such as when using frustrum or occlusion culling, will not benefit from\n // using render bundles as much.\n let renderBundle;\n function updateRenderBundle() {\n const renderBundleEncoder = device.createRenderBundleEncoder({\n colorFormats: [presentationFormat],\n depthStencilFormat: 'depth24plus',\n });\n renderScene(renderBundleEncoder);\n renderBundle = renderBundleEncoder.finish();\n }\n updateRenderBundle();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n stats.begin();\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n\n if (settings.useRenderBundles) {\n // Executing a bundle is equivalent to calling all of the commands encoded\n // in the render bundle as part of the current render pass.\n passEncoder.executeBundles([renderBundle]);\n } else {\n // Alternatively, the same render commands can be encoded manually, which\n // can take longer since each command needs to be interpreted by the\n // JavaScript virtual machine and re-validated each time.\n renderScene(passEncoder);\n }\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n stats.end();\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst RenderBundles: () => JSX.Element = () =>\n makeSample({\n name: 'Render Bundles',\n description: `This example shows how to use render bundles. It renders a large number of\n meshes individually as a proxy for a more complex scene in order to demonstrate the reduction\n in JavaScript time spent to issue render commands. (Typically a scene like this would make use\n of instancing to reduce draw overhead.)`,\n gui: true,\n stats: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './mesh.wgsl',\n contents: meshWGSL,\n editable: true,\n },\n {\n name: '../../meshes/sphere.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/sphere.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default RenderBundles;\n"},{name:"./mesh.wgsl",contents:o,editable:!0},{name:"../../meshes/sphere.ts",contents:t(8557).Z}],filename:s});var d=c},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},8557:function(e,n){"use strict";n.Z="import { vec3 } from 'wgpu-matrix';\n\nexport interface SphereMesh {\n vertices: Float32Array;\n indices: Uint16Array;\n}\n\nexport const SphereLayout = {\n vertexStride: 8 * 4,\n positionsOffset: 0,\n normalOffset: 3 * 4,\n uvOffset: 6 * 4,\n};\n\n// Borrowed and simplified from https://github.com/mrdoob/three.js/blob/master/src/geometries/SphereGeometry.js\nexport function createSphereMesh(\n radius: number,\n widthSegments = 32,\n heightSegments = 16,\n randomness = 0\n): SphereMesh {\n const vertices = [];\n const indices = [];\n\n widthSegments = Math.max(3, Math.floor(widthSegments));\n heightSegments = Math.max(2, Math.floor(heightSegments));\n\n const firstVertex = vec3.create();\n const vertex = vec3.create();\n const normal = vec3.create();\n\n let index = 0;\n const grid = [];\n\n // generate vertices, normals and uvs\n for (let iy = 0; iy <= heightSegments; iy++) {\n const verticesRow = [];\n const v = iy / heightSegments;\n\n // special case for the poles\n let uOffset = 0;\n if (iy === 0) {\n uOffset = 0.5 / widthSegments;\n } else if (iy === heightSegments) {\n uOffset = -0.5 / widthSegments;\n }\n\n for (let ix = 0; ix <= widthSegments; ix++) {\n const u = ix / widthSegments;\n\n // Poles should just use the same position all the way around.\n if (ix == widthSegments) {\n vec3.copy(firstVertex, vertex);\n } else if (ix == 0 || (iy != 0 && iy !== heightSegments)) {\n const rr = radius + (Math.random() - 0.5) * 2 * randomness * radius;\n\n // vertex\n vertex[0] = -rr * Math.cos(u * Math.PI * 2) * Math.sin(v * Math.PI);\n vertex[1] = rr * Math.cos(v * Math.PI);\n vertex[2] = rr * Math.sin(u * Math.PI * 2) * Math.sin(v * Math.PI);\n\n if (ix == 0) {\n vec3.copy(vertex, firstVertex);\n }\n }\n\n vertices.push(...vertex);\n\n // normal\n vec3.copy(vertex, normal);\n vec3.normalize(normal, normal);\n vertices.push(...normal);\n\n // uv\n vertices.push(u + uOffset, 1 - v);\n verticesRow.push(index++);\n }\n\n grid.push(verticesRow);\n }\n\n // indices\n for (let iy = 0; iy < heightSegments; iy++) {\n for (let ix = 0; ix < widthSegments; ix++) {\n const a = grid[iy][ix + 1];\n const b = grid[iy][ix];\n const c = grid[iy + 1][ix];\n const d = grid[iy + 1][ix + 1];\n\n if (iy !== 0) indices.push(a, b, d);\n if (iy !== heightSegments - 1) indices.push(b, c, d);\n }\n }\n\n return {\n vertices: new Float32Array(vertices),\n indices: new Uint16Array(indices),\n };\n}\n"},475:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/moon.4c08987edf01a109.jpg"},9836:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/saturn.630a019530ef5704.jpg"}}]); \ No newline at end of file diff --git a/_next/static/chunks/432.353267ee61f8039e.js b/_next/static/chunks/432.353267ee61f8039e.js deleted file mode 100644 index e0bf901f..00000000 --- a/_next/static/chunks/432.353267ee61f8039e.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[432],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return p}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let m=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),d=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[x,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(d?b(d[1]):b(a[0].name),m&&c.current)for(c.current.appendChild(m.domElement);m.__controllers.length>0;)m.__controllers[0].remove();p&&l.current&&(p.dom.style.position="absolute",p.showPanel(1),l.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:m,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){b(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},l=e=>(0,r.jsx)(m,{...e});function p(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},1432:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return l}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_cube;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n // Our camera and the skybox cube are both centered at (0, 0, 0)\n // so we can use the cube geomtry position to get viewing vector to sample the cube texture.\n // The magnitude of the vector doesn't matter.\n var cubemapVec = fragPosition.xyz - vec3(0.5);\n return textureSample(myTexture, mySampler, cubemapVec);\n}\n",c="src/sample/cubemap/main.ts";let u=async e=>{let n,{canvas:a,pageState:c}=e,u=await navigator.gpu.requestAdapter(),m=await u.requestDevice();if(!c.active)return;let l=a.getContext("webgpu"),p=window.devicePixelRatio||1;a.width=a.clientWidth*p,a.height=a.clientHeight*p;let f=navigator.gpu.getPreferredCanvasFormat();l.configure({device:m,format:f,alphaMode:"premultiplied"});let d=m.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(d.getMappedRange()).set(i.zS),d.unmap();let g=m.createRenderPipeline({layout:"auto",vertex:{module:m.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:m.createShaderModule({code:s}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),h=m.createTexture({size:[a.width,a.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT});{let x=[new t.U(t(8511)).toString(),new t.U(t(5408)).toString(),new t.U(t(3264)).toString(),new t.U(t(2885)).toString(),new t.U(t(459)).toString(),new t.U(t(5450)).toString()],b=x.map(async e=>{let n=await fetch(e);return createImageBitmap(await n.blob())}),v=await Promise.all(b);n=m.createTexture({dimension:"2d",size:[v[0].width,v[0].height,6],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});for(let w=0;w(0,a.Tl)({name:"Cubemap",description:"This example shows how to render and sample from a cubemap texture.",init:u,sources:[{name:c.substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleCubemapWGSL from './sampleCubemap.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleCubemapWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Since we are seeing from inside of the cube\n // and we are using the regular cube geomtry data with outward-facing normals,\n // the cullMode should be 'front' or 'none'.\n cullMode: 'none',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n // Fetch the 6 separate images for negative/positive x, y, z axis of a cubemap\n // and upload it into a GPUTexture.\n let cubemapTexture: GPUTexture;\n {\n // The order of the array layers is [+X, -X, +Y, -Y, +Z, -Z]\n const imgSrcs = [\n new URL(\n `../../../assets/img/cubemap/posx.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/negx.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/posy.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/negy.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/posz.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/negz.jpg`,\n import.meta.url\n ).toString(),\n ];\n const promises = imgSrcs.map(async (src) => {\n const response = await fetch(src);\n return createImageBitmap(await response.blob());\n });\n const imageBitmaps = await Promise.all(promises);\n\n cubemapTexture = device.createTexture({\n dimension: '2d',\n // Create a 2d array texture.\n // Assume each image has the same size.\n size: [imageBitmaps[0].width, imageBitmaps[0].height, 6],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n for (let i = 0; i < imageBitmaps.length; i++) {\n const imageBitmap = imageBitmaps[i];\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubemapTexture, origin: [0, 0, i] },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n }\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: uniformBufferSize,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubemapTexture.createView({\n dimension: 'cube',\n }),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 3000);\n\n const modelMatrix = mat4.scaling(vec3.fromValues(1000, 1000, 1000));\n const modelViewProjectionMatrix = mat4.create() as Float32Array;\n const viewMatrix = mat4.identity();\n\n const tmpMat4 = mat4.create();\n\n // Comppute camera movement:\n // It rotates around Y axis with a slight pitch movement.\n function updateTransformationMatrix() {\n const now = Date.now() / 800;\n\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(1, 0, 0),\n (Math.PI / 10) * Math.sin(now),\n tmpMat4\n );\n mat4.rotate(tmpMat4, vec3.fromValues(0, 1, 0), now * 0.2, tmpMat4);\n\n mat4.multiply(tmpMat4, modelMatrix, modelViewProjectionMatrix);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix,\n modelViewProjectionMatrix\n );\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjectionMatrix.buffer,\n modelViewProjectionMatrix.byteOffset,\n modelViewProjectionMatrix.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst CubemapCubes: () => JSX.Element = () =>\n makeSample({\n name: 'Cubemap',\n description:\n 'This example shows how to render and sample from a cubemap texture.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleCubemap.frag.wgsl',\n contents: sampleCubemapWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default CubemapCubes;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleCubemap.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var l=m},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},5408:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/negx.8b7d6335c5578c00.jpg"},2885:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/negy.6ff91fb0dd77089a.jpg"},5450:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/negz.9f1b40f803d5fb3a.jpg"},8511:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/posx.87997a8f91af66f1.jpg"},3264:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/posy.fed5fc4c9c673958.jpg"},459:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/posz.9abd46cb7a6b51b7.jpg"}}]); \ No newline at end of file diff --git a/_next/static/chunks/432.fa8b0392d17f8d67.js b/_next/static/chunks/432.fa8b0392d17f8d67.js new file mode 100644 index 00000000..1410567f --- /dev/null +++ b/_next/static/chunks/432.fa8b0392d17f8d67.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[432],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return p}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let m=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),d=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[x,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(d?b(d[1]):b(a[0].name),m&&c.current)for(c.current.appendChild(m.domElement);m.__controllers.length>0;)m.__controllers[0].remove();p&&l.current&&(p.dom.style.position="absolute",p.showPanel(1),l.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:m,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){b(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},l=e=>(0,r.jsx)(m,{...e});function p(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},1432:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return l}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_cube;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n // Our camera and the skybox cube are both centered at (0, 0, 0)\n // so we can use the cube geomtry position to get viewing vector to sample the cube texture.\n // The magnitude of the vector doesn't matter.\n var cubemapVec = fragPosition.xyz - vec3(0.5);\n return textureSample(myTexture, mySampler, cubemapVec);\n}\n",c="src/sample/cubemap/main.ts";let u=async e=>{let n,{canvas:a,pageState:c}=e,u=await navigator.gpu.requestAdapter(),m=await u.requestDevice();if(!c.active)return;let l=a.getContext("webgpu"),p=window.devicePixelRatio;a.width=a.clientWidth*p,a.height=a.clientHeight*p;let f=navigator.gpu.getPreferredCanvasFormat();l.configure({device:m,format:f,alphaMode:"premultiplied"});let d=m.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(d.getMappedRange()).set(i.zS),d.unmap();let g=m.createRenderPipeline({layout:"auto",vertex:{module:m.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:m.createShaderModule({code:s}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),h=m.createTexture({size:[a.width,a.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT});{let x=[new t.U(t(8511)).toString(),new t.U(t(5408)).toString(),new t.U(t(3264)).toString(),new t.U(t(2885)).toString(),new t.U(t(459)).toString(),new t.U(t(5450)).toString()],b=x.map(async e=>{let n=await fetch(e);return createImageBitmap(await n.blob())}),v=await Promise.all(b);n=m.createTexture({dimension:"2d",size:[v[0].width,v[0].height,6],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});for(let w=0;w(0,a.Tl)({name:"Cubemap",description:"This example shows how to render and sample from a cubemap texture.",init:u,sources:[{name:c.substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleCubemapWGSL from './sampleCubemap.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleCubemapWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Since we are seeing from inside of the cube\n // and we are using the regular cube geomtry data with outward-facing normals,\n // the cullMode should be 'front' or 'none'.\n cullMode: 'none',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n // Fetch the 6 separate images for negative/positive x, y, z axis of a cubemap\n // and upload it into a GPUTexture.\n let cubemapTexture: GPUTexture;\n {\n // The order of the array layers is [+X, -X, +Y, -Y, +Z, -Z]\n const imgSrcs = [\n new URL(\n `../../../assets/img/cubemap/posx.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/negx.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/posy.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/negy.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/posz.jpg`,\n import.meta.url\n ).toString(),\n new URL(\n `../../../assets/img/cubemap/negz.jpg`,\n import.meta.url\n ).toString(),\n ];\n const promises = imgSrcs.map(async (src) => {\n const response = await fetch(src);\n return createImageBitmap(await response.blob());\n });\n const imageBitmaps = await Promise.all(promises);\n\n cubemapTexture = device.createTexture({\n dimension: '2d',\n // Create a 2d array texture.\n // Assume each image has the same size.\n size: [imageBitmaps[0].width, imageBitmaps[0].height, 6],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n for (let i = 0; i < imageBitmaps.length; i++) {\n const imageBitmap = imageBitmaps[i];\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubemapTexture, origin: [0, 0, i] },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n }\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: uniformBufferSize,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubemapTexture.createView({\n dimension: 'cube',\n }),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 3000);\n\n const modelMatrix = mat4.scaling(vec3.fromValues(1000, 1000, 1000));\n const modelViewProjectionMatrix = mat4.create() as Float32Array;\n const viewMatrix = mat4.identity();\n\n const tmpMat4 = mat4.create();\n\n // Comppute camera movement:\n // It rotates around Y axis with a slight pitch movement.\n function updateTransformationMatrix() {\n const now = Date.now() / 800;\n\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(1, 0, 0),\n (Math.PI / 10) * Math.sin(now),\n tmpMat4\n );\n mat4.rotate(tmpMat4, vec3.fromValues(0, 1, 0), now * 0.2, tmpMat4);\n\n mat4.multiply(tmpMat4, modelMatrix, modelViewProjectionMatrix);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix,\n modelViewProjectionMatrix\n );\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjectionMatrix.buffer,\n modelViewProjectionMatrix.byteOffset,\n modelViewProjectionMatrix.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst CubemapCubes: () => JSX.Element = () =>\n makeSample({\n name: 'Cubemap',\n description:\n 'This example shows how to render and sample from a cubemap texture.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleCubemap.frag.wgsl',\n contents: sampleCubemapWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default CubemapCubes;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleCubemap.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var l=m},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},5408:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/negx.8b7d6335c5578c00.jpg"},2885:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/negy.6ff91fb0dd77089a.jpg"},5450:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/negz.9f1b40f803d5fb3a.jpg"},8511:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/posx.87997a8f91af66f1.jpg"},3264:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/posy.fed5fc4c9c673958.jpg"},459:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/cubemap/posz.9abd46cb7a6b51b7.jpg"}}]); \ No newline at end of file diff --git a/_next/static/chunks/565.41939f902eaeba99.js b/_next/static/chunks/565.41939f902eaeba99.js new file mode 100644 index 00000000..1dddcad0 --- /dev/null +++ b/_next/static/chunks/565.41939f902eaeba99.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[565],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return u},hu:function(){return m}});var a=t(5893),r=t(9008),i=t.n(r),s=t(1163),o=t(7294),c=t(9147),l=t.n(c);t(7319);let d=e=>{let n=(0,o.useRef)(null),r=(0,o.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),c=(0,o.useRef)(null),d=(0,o.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),u=(0,o.useRef)(null),m=(0,o.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),h=(0,s.useRouter)(),p=h.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,o.useState)(null),[f,x]=(0,o.useState)(null);return(0,o.useEffect)(()=>{if(p?x(p[1]):x(r[0].name),d&&c.current)for(c.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&u.current&&(m.dom.style.position="absolute",m.showPanel(1),u.current.appendChild(m.dom));let t={active:!0},a=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let s=e.init({canvas:i,pageState:t,gui:d,stats:m});s instanceof Promise&&s.catch(e=>{console.error(e),g(e)})}catch(o){console.error(o),g(o)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),v?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(v)})]}):null]}),(0,a.jsxs)("div",{className:l().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:u}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:l().sourceFileNav,children:(0,a.jsx)("ul",{children:r.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":f==e.name,onClick(){x(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,a.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":f==e.name},n))]})]})},u=e=>(0,a.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},8565:function(e,n,t){"use strict";var a="src/sample/resizeCanvas/main.ts";t.r(n);var r=t(5671),i=t(1974),s=t(2690),o=t(4057),c=t.n(o);let l=async e=>{let n,t,{canvas:a,pageState:o}=e,l=await navigator.gpu.requestAdapter();(0,r.hu)(l,"requestAdapter returned null");let d=await l.requestDevice();if(!o.active)return;let u=a.getContext("webgpu"),m=navigator.gpu.getPreferredCanvasFormat(),h=window.devicePixelRatio;a.width=a.clientWidth*h,a.height=a.clientHeight*h,u.configure({device:d,format:m,alphaMode:"premultiplied"});let p=d.createRenderPipeline({layout:"auto",vertex:{module:d.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:d.createShaderModule({code:s.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"},multisample:{count:4}});a.classList.add(c().animatedCanvasSize),requestAnimationFrame(function e(){if(!o.active)return;let r=a.clientWidth*h,i=a.clientHeight*h;(r!==a.width||i!==a.height)&&r&&i&&(void 0!==n&&n.destroy(),a.width=r,a.height=i,t=(n=d.createTexture({size:[a.width,a.height],sampleCount:4,format:m,usage:GPUTextureUsage.RENDER_ATTACHMENT})).createView());let s=d.createCommandEncoder(),c={colorAttachments:[{view:t,resolveTarget:u.getCurrentTexture().createView(),clearValue:{r:.2,g:.2,b:.2,a:1},loadOp:"clear",storeOp:"store"}]},l=s.beginRenderPass(c);l.setPipeline(p),l.draw(3),l.end(),d.queue.submit([s.finish()]),requestAnimationFrame(e)})},d=()=>(0,r.Tl)({name:"Resize Canvas",description:"Shows multisampled rendering a basic triangle on a dynamically sized canvas.",init:l,sources:[{name:a.substring(24),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nimport styles from './animatedCanvasSize.module.css';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const sampleCount = 4;\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n multisample: {\n count: 4,\n },\n });\n\n let renderTarget: GPUTexture | undefined = undefined;\n let renderTargetView: GPUTextureView;\n\n canvas.classList.add(styles.animatedCanvasSize);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const currentWidth = canvas.clientWidth * devicePixelRatio;\n const currentHeight = canvas.clientHeight * devicePixelRatio;\n\n // The canvas size is animating via CSS.\n // When the size changes, we need to reallocate the render target.\n // We also need to set the physical size of the canvas to match the computed CSS size.\n if (\n (currentWidth !== canvas.width || currentHeight !== canvas.height) &&\n currentWidth &&\n currentHeight\n ) {\n if (renderTarget !== undefined) {\n // Destroy the previous render target\n renderTarget.destroy();\n }\n\n // Setting the canvas width and height will automatically resize the textures returned\n // when calling getCurrentTexture() on the context.\n canvas.width = currentWidth;\n canvas.height = currentHeight;\n\n // Resize the multisampled render target to match the new canvas size.\n renderTarget = device.createTexture({\n size: [canvas.width, canvas.height],\n sampleCount,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n renderTargetView = renderTarget.createView();\n }\n\n const commandEncoder = device.createCommandEncoder();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: renderTargetView,\n resolveTarget: context.getCurrentTexture().createView(),\n clearValue: { r: 0.2, g: 0.2, b: 0.2, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst ResizeCanvas: () => JSX.Element = () =>\n makeSample({\n name: 'Resize Canvas',\n description:\n 'Shows multisampled rendering a basic triangle on a dynamically sized canvas.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n {\n name: './animatedCanvasSize.module.css',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./animatedCanvasSize.module.css')\n .default,\n },\n ],\n filename: __filename,\n });\n\nexport default ResizeCanvas;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:s.Z,editable:!0},{name:"./animatedCanvasSize.module.css",contents:t(7751).Z}],filename:a});n.default=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},4057:function(e){e.exports={animatedCanvasSize:"animatedCanvasSize_animatedCanvasSize__SMQPJ","animated-size":"animatedCanvasSize_animated-size__fXLtb"}},7751:function(e,n){"use strict";n.Z="@keyframes animated-size {\n 0% {\n width: 10px;\n height: 600px;\n }\n 50% {\n width: 100%;\n height: 600px;\n }\n 100% {\n width: 10px;\n height: 600px;\n }\n}\n\n.animatedCanvasSize {\n animation-duration: 3s;\n animation-iteration-count: infinite;\n animation-name: animated-size;\n animation-timing-function: ease;\n}"},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/565.e187246936cbeebe.js b/_next/static/chunks/565.e187246936cbeebe.js deleted file mode 100644 index 20048159..00000000 --- a/_next/static/chunks/565.e187246936cbeebe.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[565],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return u},hu:function(){return m}});var a=t(5893),r=t(9008),i=t.n(r),s=t(1163),o=t(7294),c=t(9147),l=t.n(c);t(7319);let d=e=>{let n=(0,o.useRef)(null),r=(0,o.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),c=(0,o.useRef)(null),d=(0,o.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),u=(0,o.useRef)(null),m=(0,o.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),h=(0,s.useRouter)(),p=h.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,o.useState)(null),[f,x]=(0,o.useState)(null);return(0,o.useEffect)(()=>{if(p?x(p[1]):x(r[0].name),d&&c.current)for(c.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&u.current&&(m.dom.style.position="absolute",m.showPanel(1),u.current.appendChild(m.dom));let t={active:!0},a=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let s=e.init({canvas:i,pageState:t,gui:d,stats:m});s instanceof Promise&&s.catch(e=>{console.error(e),g(e)})}catch(o){console.error(o),g(o)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),v?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(v)})]}):null]}),(0,a.jsxs)("div",{className:l().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:u}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:l().sourceFileNav,children:(0,a.jsx)("ul",{children:r.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":f==e.name,onClick(){x(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,a.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":f==e.name},n))]})]})},u=e=>(0,a.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},8565:function(e,n,t){"use strict";var a="src/sample/resizeCanvas/main.ts";t.r(n);var r=t(5671),i=t(1974),s=t(2690),o=t(4057),c=t.n(o);let l=async e=>{let n,t,{canvas:a,pageState:o}=e,l=await navigator.gpu.requestAdapter();(0,r.hu)(l,"requestAdapter returned null");let d=await l.requestDevice();if(!o.active)return;let u=a.getContext("webgpu"),m=navigator.gpu.getPreferredCanvasFormat(),h=window.devicePixelRatio||1;a.width=a.clientWidth*h,a.height=a.clientHeight*h,u.configure({device:d,format:m,alphaMode:"premultiplied"});let p=d.createRenderPipeline({layout:"auto",vertex:{module:d.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:d.createShaderModule({code:s.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"},multisample:{count:4}});a.classList.add(c().animatedCanvasSize),requestAnimationFrame(function e(){if(!o.active)return;let r=a.clientWidth*h,i=a.clientHeight*h;(r!==a.width||i!==a.height)&&r&&i&&(void 0!==n&&n.destroy(),a.width=r,a.height=i,t=(n=d.createTexture({size:[a.width,a.height],sampleCount:4,format:m,usage:GPUTextureUsage.RENDER_ATTACHMENT})).createView());let s=d.createCommandEncoder(),c={colorAttachments:[{view:t,resolveTarget:u.getCurrentTexture().createView(),clearValue:{r:.2,g:.2,b:.2,a:1},loadOp:"clear",storeOp:"store"}]},l=s.beginRenderPass(c);l.setPipeline(p),l.draw(3),l.end(),d.queue.submit([s.finish()]),requestAnimationFrame(e)})},d=()=>(0,r.Tl)({name:"Resize Canvas",description:"Shows multisampled rendering a basic triangle on a dynamically sized canvas.",init:l,sources:[{name:a.substring(24),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nimport styles from './animatedCanvasSize.module.css';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const sampleCount = 4;\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n multisample: {\n count: 4,\n },\n });\n\n let renderTarget: GPUTexture | undefined = undefined;\n let renderTargetView: GPUTextureView;\n\n canvas.classList.add(styles.animatedCanvasSize);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const currentWidth = canvas.clientWidth * devicePixelRatio;\n const currentHeight = canvas.clientHeight * devicePixelRatio;\n\n // The canvas size is animating via CSS.\n // When the size changes, we need to reallocate the render target.\n // We also need to set the physical size of the canvas to match the computed CSS size.\n if (\n (currentWidth !== canvas.width || currentHeight !== canvas.height) &&\n currentWidth &&\n currentHeight\n ) {\n if (renderTarget !== undefined) {\n // Destroy the previous render target\n renderTarget.destroy();\n }\n\n // Setting the canvas width and height will automatically resize the textures returned\n // when calling getCurrentTexture() on the context.\n canvas.width = currentWidth;\n canvas.height = currentHeight;\n\n // Resize the multisampled render target to match the new canvas size.\n renderTarget = device.createTexture({\n size: [canvas.width, canvas.height],\n sampleCount,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n renderTargetView = renderTarget.createView();\n }\n\n const commandEncoder = device.createCommandEncoder();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: renderTargetView,\n resolveTarget: context.getCurrentTexture().createView(),\n clearValue: { r: 0.2, g: 0.2, b: 0.2, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst ResizeCanvas: () => JSX.Element = () =>\n makeSample({\n name: 'Resize Canvas',\n description:\n 'Shows multisampled rendering a basic triangle on a dynamically sized canvas.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n {\n name: './animatedCanvasSize.module.css',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./animatedCanvasSize.module.css')\n .default,\n },\n ],\n filename: __filename,\n });\n\nexport default ResizeCanvas;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:s.Z,editable:!0},{name:"./animatedCanvasSize.module.css",contents:t(7751).Z}],filename:a});n.default=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},4057:function(e){e.exports={animatedCanvasSize:"animatedCanvasSize_animatedCanvasSize__SMQPJ","animated-size":"animatedCanvasSize_animated-size__fXLtb"}},7751:function(e,n){"use strict";n.Z="@keyframes animated-size {\n 0% {\n width: 10px;\n height: 600px;\n }\n 50% {\n width: 100%;\n height: 600px;\n }\n 100% {\n width: 10px;\n height: 600px;\n }\n}\n\n.animatedCanvasSize {\n animation-duration: 3s;\n animation-iteration-count: infinite;\n animation-name: animated-size;\n animation-timing-function: ease;\n}"},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/588.a733b5bfae1e4923.js b/_next/static/chunks/588.a733b5bfae1e4923.js new file mode 100644 index 00000000..b56c1965 --- /dev/null +++ b/_next/static/chunks/588.a733b5bfae1e4923.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[588],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return p},hu:function(){return l}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),d=t(9147),u=t.n(d);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),d=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),p=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,i.useRouter)(),m=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,P]=(0,s.useState)(null),[v,g]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?g(m[1]):g(a[0].name),c&&d.current)for(d.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();l&&p.current&&(l.dom.style.position="absolute",l.showPanel(1),p.current.appendChild(l.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:c,stats:l});i instanceof Promise&&i.catch(e=>{console.error(e),P(e)})}catch(s){console.error(s),P(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:d}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){g(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":v==e.name},n))]})]})},p=e=>(0,r.jsx)(c,{...e});function l(e,n){if(!e)throw Error(n)}},7502:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return b},geometryVertexArray:function(){return h}});var r,a,o=t(5671),i=t(6416),s="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragColor : vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4,\n @location(1) color : vec4\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n output.fragColor = color;\n return output;\n}",d="@fragment\nfn main(\n @location(0) fragColor: vec4\n) -> @location(0) vec4 {\n return fragColor;\n}\n",u="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4\n) -> @builtin(position) vec4 {\n return camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n}\n",c="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n const pos = array(\n vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0),\n vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0),\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n",p="@group(0) @binding(0) var depthTexture: texture_depth_2d;\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n let depthValue = textureLoad(depthTexture, vec2(floor(coord.xy)), 0);\n return vec4(depthValue, depthValue, depthValue, 1.0);\n}\n",l="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) clipPos : vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n output.clipPos = output.Position;\n return output;\n}\n",f="@group(1) @binding(0) var depthTexture: texture_depth_2d;\n\n@fragment\nfn main(\n @builtin(position) coord: vec4,\n @location(0) clipPos: vec4\n) -> @location(0) vec4 {\n let depthValue = textureLoad(depthTexture, vec2(floor(coord.xy)), 0);\n let v : f32 = abs(clipPos.z / clipPos.w - depthValue) * 2000000.0;\n return vec4(v, v, v, 1.0);\n}\n",m="src/sample/reversedZ/main.ts";let h=new Float32Array([-1.5,-1,1e-4,1,1,0,0,1,.5,-1,1e-4,1,1,0,0,1,-1.5,1,1e-4,1,1,0,0,1,.5,-1,1e-4,1,1,0,0,1,.5,1,1e-4,1,1,0,0,1,-1.5,1,1e-4,1,1,0,0,1,-.5,-1,-.0001,1,0,1,0,1,1.5,-1,-.0001,1,0,1,0,1,-.5,1,-.0001,1,0,1,0,1,1.5,-1,-.0001,1,0,1,0,1,1.5,1,-.0001,1,0,1,0,1,-.5,1,-.0001,1,0,1,0,1]),P=i._E.identity();P[10]=-1,P[14]=1,(r=a||(a={}))[r.Default=0]="Default",r[r.Reversed=1]="Reversed";let v=[a.Default,a.Reversed],g={[a.Default]:"less",[a.Reversed]:"greater"},x={[a.Default]:1,[a.Reversed]:0},w=async e=>{let{canvas:n,pageState:t,gui:r}=e,o=await navigator.gpu.requestAdapter(),m=await o.requestDevice();if(!t.active)return;let w=n.getContext("webgpu"),y=window.devicePixelRatio;n.width=n.clientWidth*y,n.height=n.clientHeight*y;let b=navigator.gpu.getPreferredCanvasFormat();w.configure({device:m,format:b,alphaMode:"premultiplied"});let B=m.createBuffer({size:h.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(B.getMappedRange()).set(h),B.unmap();let R="depth32float",D=m.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"depth"}}]}),S=m.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}}]}),M=m.createPipelineLayout({bindGroupLayouts:[S]}),G={layout:M,vertex:{module:m.createShaderModule({code:u}),entryPoint:"main",buffers:[{arrayStride:32,attributes:[{shaderLocation:0,offset:0,format:"float32x4"}]}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:R}},C=[];G.depthStencil.depthCompare=g[a.Default],C[a.Default]=m.createRenderPipeline(G),G.depthStencil.depthCompare=g[a.Reversed],C[a.Reversed]=m.createRenderPipeline(G);let T=m.createPipelineLayout({bindGroupLayouts:[S,D]}),L={layout:T,vertex:{module:m.createShaderModule({code:l}),entryPoint:"main",buffers:[{arrayStride:32,attributes:[{shaderLocation:0,offset:0,format:"float32x4"}]}]},fragment:{module:m.createShaderModule({code:f}),entryPoint:"main",targets:[{format:b}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:R}},V=[];L.depthStencil.depthCompare=g[a.Default],V[a.Default]=m.createRenderPipeline(L),L.depthStencil.depthCompare=g[a.Reversed],V[a.Reversed]=m.createRenderPipeline(L);let E=m.createPipelineLayout({bindGroupLayouts:[S]}),U={layout:E,vertex:{module:m.createShaderModule({code:s}),entryPoint:"main",buffers:[{arrayStride:32,attributes:[{shaderLocation:0,offset:0,format:"float32x4"},{shaderLocation:1,offset:16,format:"float32x4"}]}]},fragment:{module:m.createShaderModule({code:d}),entryPoint:"main",targets:[{format:b}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:R}},A=[];U.depthStencil.depthCompare=g[a.Default],A[a.Default]=m.createRenderPipeline(U),U.depthStencil.depthCompare=g[a.Reversed],A[a.Reversed]=m.createRenderPipeline(U);let O=m.createPipelineLayout({bindGroupLayouts:[D]}),_=m.createRenderPipeline({layout:O,vertex:{module:m.createShaderModule({code:c}),entryPoint:"main"},fragment:{module:m.createShaderModule({code:p}),entryPoint:"main",targets:[{format:b}]},primitive:{topology:"triangle-list"}}),F=m.createTexture({size:[n.width,n.height],format:R,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),j=F.createView(),z=m.createTexture({size:[n.width,n.height],format:R,usage:GPUTextureUsage.RENDER_ATTACHMENT}),I=z.createView(),W={colorAttachments:[],depthStencilAttachment:{view:j,depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},Q=[{colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:I,depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},{colorAttachments:[{view:void 0,loadOp:"load",storeOp:"store"}],depthStencilAttachment:{view:I,depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}}],N=[{colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:.5,a:1},loadOp:"clear",storeOp:"store"}]},{colorAttachments:[{view:void 0,loadOp:"load",storeOp:"store"}]}],q=m.createBindGroup({layout:D,entries:[{binding:0,resource:j}]}),k=m.createBuffer({size:320,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),H=m.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),X=m.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),Y=[m.createBindGroup({layout:S,entries:[{binding:0,resource:{buffer:k}},{binding:1,resource:{buffer:H}}]}),m.createBindGroup({layout:S,entries:[{binding:0,resource:{buffer:k}},{binding:1,resource:{buffer:X}}]})],Z=[,,,,,],J=new Float32Array(80),K=0;for(let $=0;$<1;$++)for(let ee=0;ee<5;ee++){let en=-800*K,et=1+50*K;Z[K]=i._E.translation(i.R3.fromValues($-.5+.5,(4-.2*en)*(ee-2.5+1),en)),i._E.scale(Z[K],i.R3.fromValues(et,et,et),Z[K]),K++}let er=i._E.translation(i.R3.fromValues(0,0,-12)),ea=.5*n.width/n.height,eo=i._E.perspective(2*Math.PI/5,ea,5,9999),ei=i._E.multiply(eo,er),es=i._E.multiply(P,ei),ed=ei;m.queue.writeBuffer(H,0,ed.buffer,ed.byteOffset,ed.byteLength),ed=es,m.queue.writeBuffer(X,0,ed.buffer,ed.byteOffset,ed.byteLength);let eu=i._E.create(),ec={mode:"color"};r.add(ec,"mode",["color","precision-error","depth-texture"]),requestAnimationFrame(function e(){if(!t.active)return;(function(){let e=Date.now()/1e3;for(let n=0,t=0;n<5;n++,t+=16)i._E.rotate(Z[n],i.R3.fromValues(Math.sin(e),Math.cos(e),0),Math.PI/180*30,eu),J.set(eu,t)})(),m.queue.writeBuffer(k,0,J.buffer,J.byteOffset,J.byteLength);let r=w.getCurrentTexture().createView(),a=m.createCommandEncoder();if("color"===ec.mode)for(let o of v){Q[o].colorAttachments[0].view=r,Q[o].depthStencilAttachment.depthClearValue=x[o];let s=a.beginRenderPass(Q[o]);s.setPipeline(A[o]),s.setBindGroup(0,Y[o]),s.setVertexBuffer(0,B),s.setViewport(n.width*o/2,0,n.width/2,n.height,0,1),s.draw(12,5,0,0),s.end()}else if("precision-error"===ec.mode)for(let d of v){{W.depthStencilAttachment.depthClearValue=x[d];let u=a.beginRenderPass(W);u.setPipeline(C[d]),u.setBindGroup(0,Y[d]),u.setVertexBuffer(0,B),u.setViewport(n.width*d/2,0,n.width/2,n.height,0,1),u.draw(12,5,0,0),u.end()}{Q[d].colorAttachments[0].view=r,Q[d].depthStencilAttachment.depthClearValue=x[d];let c=a.beginRenderPass(Q[d]);c.setPipeline(V[d]),c.setBindGroup(0,Y[d]),c.setBindGroup(1,q),c.setVertexBuffer(0,B),c.setViewport(n.width*d/2,0,n.width/2,n.height,0,1),c.draw(12,5,0,0),c.end()}}else for(let p of v){{W.depthStencilAttachment.depthClearValue=x[p];let l=a.beginRenderPass(W);l.setPipeline(C[p]),l.setBindGroup(0,Y[p]),l.setVertexBuffer(0,B),l.setViewport(n.width*p/2,0,n.width/2,n.height,0,1),l.draw(12,5,0,0),l.end()}{N[p].colorAttachments[0].view=r;let f=a.beginRenderPass(N[p]);f.setPipeline(_),f.setBindGroup(0,q),f.setViewport(n.width*p/2,0,n.width/2,n.height,0,1),f.draw(6),f.end()}}m.queue.submit([a.finish()]),requestAnimationFrame(e)})},y=()=>(0,o.Tl)({name:"Reversed Z",description:"This example shows the use of reversed z technique for better utilization of depth buffer precision.\n The left column uses regular method, while the right one uses reversed z technique.\n Both are using depth32float as their depth buffer format. A set of red and green planes are positioned very close to each other.\n Higher sets are placed further from camera (and are scaled for better visual purpose).\n To use reversed z to render your scene, you will need depth store value to be 0.0, depth compare function to be greater,\n and remap depth range by multiplying an additional matrix to your projection matrix.\n Related reading:\n https://developer.nvidia.com/content/depth-precision-visualized\n https://thxforthefish.com/posts/reverse_z/\n ",gui:!0,init:w,sources:[{name:m.substring(21),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { mat4, vec3 } from 'wgpu-matrix';\n\nimport vertexWGSL from './vertex.wgsl';\nimport fragmentWGSL from './fragment.wgsl';\nimport vertexDepthPrePassWGSL from './vertexDepthPrePass.wgsl';\nimport vertexTextureQuadWGSL from './vertexTextureQuad.wgsl';\nimport fragmentTextureQuadWGSL from './fragmentTextureQuad.wgsl';\nimport vertexPrecisionErrorPassWGSL from './vertexPrecisionErrorPass.wgsl';\nimport fragmentPrecisionErrorPassWGSL from './fragmentPrecisionErrorPass.wgsl';\n\n// Two planes close to each other for depth precision test\nconst geometryVertexSize = 4 * 8; // Byte size of one geometry vertex.\nconst geometryPositionOffset = 0;\nconst geometryColorOffset = 4 * 4; // Byte offset of geometry vertex color attribute.\nconst geometryDrawCount = 6 * 2;\n\nconst d = 0.0001; // half distance between two planes\nconst o = 0.5; // half x offset to shift planes so they are only partially overlaping\n\n// prettier-ignore\nexport const geometryVertexArray = new Float32Array([\n // float4 position, float4 color\n -1 - o, -1, d, 1, 1, 0, 0, 1,\n 1 - o, -1, d, 1, 1, 0, 0, 1,\n -1 - o, 1, d, 1, 1, 0, 0, 1,\n 1 - o, -1, d, 1, 1, 0, 0, 1,\n 1 - o, 1, d, 1, 1, 0, 0, 1,\n -1 - o, 1, d, 1, 1, 0, 0, 1,\n\n -1 + o, -1, -d, 1, 0, 1, 0, 1,\n 1 + o, -1, -d, 1, 0, 1, 0, 1,\n -1 + o, 1, -d, 1, 0, 1, 0, 1,\n 1 + o, -1, -d, 1, 0, 1, 0, 1,\n 1 + o, 1, -d, 1, 0, 1, 0, 1,\n -1 + o, 1, -d, 1, 0, 1, 0, 1,\n]);\n\nconst xCount = 1;\nconst yCount = 5;\nconst numInstances = xCount * yCount;\nconst matrixFloatCount = 16; // 4x4 matrix\nconst matrixStride = 4 * matrixFloatCount; // 64;\n\nconst depthRangeRemapMatrix = mat4.identity();\ndepthRangeRemapMatrix[10] = -1;\ndepthRangeRemapMatrix[14] = 1;\n\nenum DepthBufferMode {\n Default = 0,\n Reversed,\n}\n\nconst depthBufferModes: DepthBufferMode[] = [\n DepthBufferMode.Default,\n DepthBufferMode.Reversed,\n];\nconst depthCompareFuncs = {\n [DepthBufferMode.Default]: 'less' as GPUCompareFunction,\n [DepthBufferMode.Reversed]: 'greater' as GPUCompareFunction,\n};\nconst depthClearValues = {\n [DepthBufferMode.Default]: 1.0,\n [DepthBufferMode.Reversed]: 0.0,\n};\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const verticesBuffer = device.createBuffer({\n size: geometryVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(geometryVertexArray);\n verticesBuffer.unmap();\n\n const depthBufferFormat = 'depth32float';\n\n const depthTextureBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n ],\n });\n\n // Model, view, projection matrices\n const uniformBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const depthPrePassRenderPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [uniformBindGroupLayout],\n });\n\n // depthPrePass is used to render scene to the depth texture\n // this is not needed if you just want to use reversed z to render a scene\n const depthPrePassRenderPipelineDescriptorBase = {\n layout: depthPrePassRenderPipelineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexDepthPrePassWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: geometryVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: geometryPositionOffset,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: depthBufferFormat,\n },\n } as GPURenderPipelineDescriptor;\n\n // we need the depthCompare to fit the depth buffer mode we are using.\n // this is the same for other passes\n const depthPrePassPipelines: GPURenderPipeline[] = [];\n depthPrePassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Default];\n depthPrePassPipelines[DepthBufferMode.Default] = device.createRenderPipeline(\n depthPrePassRenderPipelineDescriptorBase\n );\n depthPrePassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Reversed];\n depthPrePassPipelines[DepthBufferMode.Reversed] = device.createRenderPipeline(\n depthPrePassRenderPipelineDescriptorBase\n );\n\n // precisionPass is to draw precision error as color of depth value stored in depth buffer\n // compared to that directly calcualated in the shader\n const precisionPassRenderPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [uniformBindGroupLayout, depthTextureBindGroupLayout],\n });\n const precisionPassRenderPipelineDescriptorBase = {\n layout: precisionPassRenderPipelineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexPrecisionErrorPassWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: geometryVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: geometryPositionOffset,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentPrecisionErrorPassWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: depthBufferFormat,\n },\n } as GPURenderPipelineDescriptor;\n const precisionPassPipelines: GPURenderPipeline[] = [];\n precisionPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Default];\n precisionPassPipelines[DepthBufferMode.Default] = device.createRenderPipeline(\n precisionPassRenderPipelineDescriptorBase\n );\n precisionPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Reversed];\n // prettier-ignore\n precisionPassPipelines[DepthBufferMode.Reversed] = device.createRenderPipeline(\n precisionPassRenderPipelineDescriptorBase\n );\n\n // colorPass is the regular render pass to render the scene\n const colorPassRenderPiplineLayout = device.createPipelineLayout({\n bindGroupLayouts: [uniformBindGroupLayout],\n });\n const colorPassRenderPipelineDescriptorBase: GPURenderPipelineDescriptor = {\n layout: colorPassRenderPiplineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: geometryVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: geometryPositionOffset,\n format: 'float32x4',\n },\n {\n // color\n shaderLocation: 1,\n offset: geometryColorOffset,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: depthBufferFormat,\n },\n };\n const colorPassPipelines: GPURenderPipeline[] = [];\n colorPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Default];\n colorPassPipelines[DepthBufferMode.Default] = device.createRenderPipeline(\n colorPassRenderPipelineDescriptorBase\n );\n colorPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Reversed];\n colorPassPipelines[DepthBufferMode.Reversed] = device.createRenderPipeline(\n colorPassRenderPipelineDescriptorBase\n );\n\n // textureQuadPass is draw a full screen quad of depth texture\n // to see the difference of depth value using reversed z compared to default depth buffer usage\n // 0.0 will be the furthest and 1.0 will be the closest\n const textureQuadPassPiplineLayout = device.createPipelineLayout({\n bindGroupLayouts: [depthTextureBindGroupLayout],\n });\n const textureQuadPassPipline = device.createRenderPipeline({\n layout: textureQuadPassPiplineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexTextureQuadWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentTextureQuadWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: depthBufferFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n const depthTextureView = depthTexture.createView();\n\n const defaultDepthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: depthBufferFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const defaultDepthTextureView = defaultDepthTexture.createView();\n\n const depthPrePassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [],\n depthStencilAttachment: {\n view: depthTextureView,\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n // drawPassDescriptor and drawPassLoadDescriptor are used for drawing\n // the scene twice using different depth buffer mode on splitted viewport\n // of the same canvas\n // see the difference of the loadOp of the colorAttachments\n const drawPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.0, g: 0.0, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: defaultDepthTextureView,\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n const drawPassLoadDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // attachment is acquired and set in render loop.\n view: undefined,\n\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: defaultDepthTextureView,\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n const drawPassDescriptors = [drawPassDescriptor, drawPassLoadDescriptor];\n\n const textureQuadPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.0, g: 0.0, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n const textureQuadPassLoadDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n };\n const textureQuadPassDescriptors = [\n textureQuadPassDescriptor,\n textureQuadPassLoadDescriptor,\n ];\n\n const depthTextureBindGroup = device.createBindGroup({\n layout: depthTextureBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: depthTextureView,\n },\n ],\n });\n\n const uniformBufferSize = numInstances * matrixStride;\n\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const cameraMatrixBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const cameraMatrixReversedDepthBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroups = [\n device.createBindGroup({\n layout: uniformBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: cameraMatrixBuffer,\n },\n },\n ],\n }),\n device.createBindGroup({\n layout: uniformBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: cameraMatrixReversedDepthBuffer,\n },\n },\n ],\n }),\n ];\n\n type Mat4 = mat4.default;\n const modelMatrices = new Array(numInstances);\n const mvpMatricesData = new Float32Array(matrixFloatCount * numInstances);\n\n let m = 0;\n for (let x = 0; x < xCount; x++) {\n for (let y = 0; y < yCount; y++) {\n const z = -800 * m;\n const s = 1 + 50 * m;\n\n modelMatrices[m] = mat4.translation(\n vec3.fromValues(\n x - xCount / 2 + 0.5,\n (4.0 - 0.2 * z) * (y - yCount / 2 + 1.0),\n z\n )\n );\n mat4.scale(modelMatrices[m], vec3.fromValues(s, s, s), modelMatrices[m]);\n\n m++;\n }\n }\n\n const viewMatrix = mat4.translation(vec3.fromValues(0, 0, -12));\n\n const aspect = (0.5 * canvas.width) / canvas.height;\n // wgpu-matrix perspective doesn't handle zFar === Infinity now.\n // https://github.com/greggman/wgpu-matrix/issues/9\n const projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 5, 9999);\n\n const viewProjectionMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n // to use 1/z we just multiple depthRangeRemapMatrix to our default camera view projection matrix\n const reversedRangeViewProjectionMatrix = mat4.multiply(\n depthRangeRemapMatrix,\n viewProjectionMatrix\n );\n\n let bufferData = viewProjectionMatrix as Float32Array;\n device.queue.writeBuffer(\n cameraMatrixBuffer,\n 0,\n bufferData.buffer,\n bufferData.byteOffset,\n bufferData.byteLength\n );\n bufferData = reversedRangeViewProjectionMatrix as Float32Array;\n device.queue.writeBuffer(\n cameraMatrixReversedDepthBuffer,\n 0,\n bufferData.buffer,\n bufferData.byteOffset,\n bufferData.byteLength\n );\n\n const tmpMat4 = mat4.create();\n function updateTransformationMatrix() {\n const now = Date.now() / 1000;\n\n for (let i = 0, m = 0; i < numInstances; i++, m += matrixFloatCount) {\n mat4.rotate(\n modelMatrices[i],\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n (Math.PI / 180) * 30,\n tmpMat4\n );\n mvpMatricesData.set(tmpMat4, m);\n }\n }\n\n const settings = {\n mode: 'color',\n };\n gui.add(settings, 'mode', ['color', 'precision-error', 'depth-texture']);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n mvpMatricesData.buffer,\n mvpMatricesData.byteOffset,\n mvpMatricesData.byteLength\n );\n\n const attachment = context.getCurrentTexture().createView();\n const commandEncoder = device.createCommandEncoder();\n if (settings.mode === 'color') {\n for (const m of depthBufferModes) {\n drawPassDescriptors[m].colorAttachments[0].view = attachment;\n drawPassDescriptors[m].depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const colorPass = commandEncoder.beginRenderPass(\n drawPassDescriptors[m]\n );\n colorPass.setPipeline(colorPassPipelines[m]);\n colorPass.setBindGroup(0, uniformBindGroups[m]);\n colorPass.setVertexBuffer(0, verticesBuffer);\n colorPass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n colorPass.draw(geometryDrawCount, numInstances, 0, 0);\n colorPass.end();\n }\n } else if (settings.mode === 'precision-error') {\n for (const m of depthBufferModes) {\n {\n depthPrePassDescriptor.depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const depthPrePass = commandEncoder.beginRenderPass(\n depthPrePassDescriptor\n );\n depthPrePass.setPipeline(depthPrePassPipelines[m]);\n depthPrePass.setBindGroup(0, uniformBindGroups[m]);\n depthPrePass.setVertexBuffer(0, verticesBuffer);\n depthPrePass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n depthPrePass.draw(geometryDrawCount, numInstances, 0, 0);\n depthPrePass.end();\n }\n {\n drawPassDescriptors[m].colorAttachments[0].view = attachment;\n drawPassDescriptors[m].depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const precisionErrorPass = commandEncoder.beginRenderPass(\n drawPassDescriptors[m]\n );\n precisionErrorPass.setPipeline(precisionPassPipelines[m]);\n precisionErrorPass.setBindGroup(0, uniformBindGroups[m]);\n precisionErrorPass.setBindGroup(1, depthTextureBindGroup);\n precisionErrorPass.setVertexBuffer(0, verticesBuffer);\n precisionErrorPass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n precisionErrorPass.draw(geometryDrawCount, numInstances, 0, 0);\n precisionErrorPass.end();\n }\n }\n } else {\n // depth texture quad\n for (const m of depthBufferModes) {\n {\n depthPrePassDescriptor.depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const depthPrePass = commandEncoder.beginRenderPass(\n depthPrePassDescriptor\n );\n depthPrePass.setPipeline(depthPrePassPipelines[m]);\n depthPrePass.setBindGroup(0, uniformBindGroups[m]);\n depthPrePass.setVertexBuffer(0, verticesBuffer);\n depthPrePass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n depthPrePass.draw(geometryDrawCount, numInstances, 0, 0);\n depthPrePass.end();\n }\n {\n textureQuadPassDescriptors[m].colorAttachments[0].view = attachment;\n const depthTextureQuadPass = commandEncoder.beginRenderPass(\n textureQuadPassDescriptors[m]\n );\n depthTextureQuadPass.setPipeline(textureQuadPassPipline);\n depthTextureQuadPass.setBindGroup(0, depthTextureBindGroup);\n depthTextureQuadPass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n depthTextureQuadPass.draw(6);\n depthTextureQuadPass.end();\n }\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ReversedZ: () => JSX.Element = () =>\n makeSample({\n name: 'Reversed Z',\n description: `This example shows the use of reversed z technique for better utilization of depth buffer precision.\n The left column uses regular method, while the right one uses reversed z technique.\n Both are using depth32float as their depth buffer format. A set of red and green planes are positioned very close to each other.\n Higher sets are placed further from camera (and are scaled for better visual purpose).\n To use reversed z to render your scene, you will need depth store value to be 0.0, depth compare function to be greater,\n and remap depth range by multiplying an additional matrix to your projection matrix.\n Related reading:\n https://developer.nvidia.com/content/depth-precision-visualized\n https://thxforthefish.com/posts/reverse_z/\n `,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './vertex.wgsl',\n contents: vertexWGSL,\n editable: true,\n },\n {\n name: './fragment.wgsl',\n contents: fragmentWGSL,\n editable: true,\n },\n {\n name: './vertexDepthPrePass.wgsl',\n contents: vertexDepthPrePassWGSL,\n editable: true,\n },\n {\n name: './vertexTextureQuad.wgsl',\n contents: vertexTextureQuadWGSL,\n editable: true,\n },\n {\n name: './fragmentTextureQuad.wgsl',\n contents: fragmentTextureQuadWGSL,\n editable: true,\n },\n {\n name: './vertexPrecisionErrorPass.wgsl',\n contents: vertexPrecisionErrorPassWGSL,\n editable: true,\n },\n {\n name: './fragmentPrecisionErrorPass.wgsl',\n contents: fragmentPrecisionErrorPassWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ReversedZ;\n"},{name:"./vertex.wgsl",contents:s,editable:!0},{name:"./fragment.wgsl",contents:d,editable:!0},{name:"./vertexDepthPrePass.wgsl",contents:u,editable:!0},{name:"./vertexTextureQuad.wgsl",contents:c,editable:!0},{name:"./fragmentTextureQuad.wgsl",contents:p,editable:!0},{name:"./vertexPrecisionErrorPass.wgsl",contents:l,editable:!0},{name:"./fragmentPrecisionErrorPass.wgsl",contents:f,editable:!0}],filename:m});var b=y},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/588.d89d4588415af0e8.js b/_next/static/chunks/588.d89d4588415af0e8.js deleted file mode 100644 index 7d173590..00000000 --- a/_next/static/chunks/588.d89d4588415af0e8.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[588],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return p},hu:function(){return l}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),d=t(9147),u=t.n(d);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),d=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),p=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,i.useRouter)(),m=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,P]=(0,s.useState)(null),[v,g]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?g(m[1]):g(a[0].name),c&&d.current)for(d.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();l&&p.current&&(l.dom.style.position="absolute",l.showPanel(1),p.current.appendChild(l.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:c,stats:l});i instanceof Promise&&i.catch(e=>{console.error(e),P(e)})}catch(s){console.error(s),P(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:d}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){g(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":v==e.name},n))]})]})},p=e=>(0,r.jsx)(c,{...e});function l(e,n){if(!e)throw Error(n)}},7502:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return b},geometryVertexArray:function(){return h}});var r,a,o=t(5671),i=t(6416),s="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragColor : vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4,\n @location(1) color : vec4\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n output.fragColor = color;\n return output;\n}",d="@fragment\nfn main(\n @location(0) fragColor: vec4\n) -> @location(0) vec4 {\n return fragColor;\n}\n",u="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4\n) -> @builtin(position) vec4 {\n return camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n}\n",c="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n const pos = array(\n vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0),\n vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0),\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n",p="@group(0) @binding(0) var depthTexture: texture_depth_2d;\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n let depthValue = textureLoad(depthTexture, vec2(floor(coord.xy)), 0);\n return vec4(depthValue, depthValue, depthValue, 1.0);\n}\n",l="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) clipPos : vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n output.clipPos = output.Position;\n return output;\n}\n",f="@group(1) @binding(0) var depthTexture: texture_depth_2d;\n\n@fragment\nfn main(\n @builtin(position) coord: vec4,\n @location(0) clipPos: vec4\n) -> @location(0) vec4 {\n let depthValue = textureLoad(depthTexture, vec2(floor(coord.xy)), 0);\n let v : f32 = abs(clipPos.z / clipPos.w - depthValue) * 2000000.0;\n return vec4(v, v, v, 1.0);\n}\n",m="src/sample/reversedZ/main.ts";let h=new Float32Array([-1.5,-1,1e-4,1,1,0,0,1,.5,-1,1e-4,1,1,0,0,1,-1.5,1,1e-4,1,1,0,0,1,.5,-1,1e-4,1,1,0,0,1,.5,1,1e-4,1,1,0,0,1,-1.5,1,1e-4,1,1,0,0,1,-.5,-1,-.0001,1,0,1,0,1,1.5,-1,-.0001,1,0,1,0,1,-.5,1,-.0001,1,0,1,0,1,1.5,-1,-.0001,1,0,1,0,1,1.5,1,-.0001,1,0,1,0,1,-.5,1,-.0001,1,0,1,0,1]),P=i._E.identity();P[10]=-1,P[14]=1,(r=a||(a={}))[r.Default=0]="Default",r[r.Reversed=1]="Reversed";let v=[a.Default,a.Reversed],g={[a.Default]:"less",[a.Reversed]:"greater"},x={[a.Default]:1,[a.Reversed]:0},w=async e=>{let{canvas:n,pageState:t,gui:r}=e,o=await navigator.gpu.requestAdapter(),m=await o.requestDevice();if(!t.active)return;let w=n.getContext("webgpu"),y=window.devicePixelRatio||1;n.width=n.clientWidth*y,n.height=n.clientHeight*y;let b=navigator.gpu.getPreferredCanvasFormat();w.configure({device:m,format:b,alphaMode:"premultiplied"});let B=m.createBuffer({size:h.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(B.getMappedRange()).set(h),B.unmap();let R="depth32float",D=m.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"depth"}}]}),S=m.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}}]}),M=m.createPipelineLayout({bindGroupLayouts:[S]}),G={layout:M,vertex:{module:m.createShaderModule({code:u}),entryPoint:"main",buffers:[{arrayStride:32,attributes:[{shaderLocation:0,offset:0,format:"float32x4"}]}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:R}},C=[];G.depthStencil.depthCompare=g[a.Default],C[a.Default]=m.createRenderPipeline(G),G.depthStencil.depthCompare=g[a.Reversed],C[a.Reversed]=m.createRenderPipeline(G);let T=m.createPipelineLayout({bindGroupLayouts:[S,D]}),L={layout:T,vertex:{module:m.createShaderModule({code:l}),entryPoint:"main",buffers:[{arrayStride:32,attributes:[{shaderLocation:0,offset:0,format:"float32x4"}]}]},fragment:{module:m.createShaderModule({code:f}),entryPoint:"main",targets:[{format:b}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:R}},V=[];L.depthStencil.depthCompare=g[a.Default],V[a.Default]=m.createRenderPipeline(L),L.depthStencil.depthCompare=g[a.Reversed],V[a.Reversed]=m.createRenderPipeline(L);let E=m.createPipelineLayout({bindGroupLayouts:[S]}),U={layout:E,vertex:{module:m.createShaderModule({code:s}),entryPoint:"main",buffers:[{arrayStride:32,attributes:[{shaderLocation:0,offset:0,format:"float32x4"},{shaderLocation:1,offset:16,format:"float32x4"}]}]},fragment:{module:m.createShaderModule({code:d}),entryPoint:"main",targets:[{format:b}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:R}},A=[];U.depthStencil.depthCompare=g[a.Default],A[a.Default]=m.createRenderPipeline(U),U.depthStencil.depthCompare=g[a.Reversed],A[a.Reversed]=m.createRenderPipeline(U);let O=m.createPipelineLayout({bindGroupLayouts:[D]}),_=m.createRenderPipeline({layout:O,vertex:{module:m.createShaderModule({code:c}),entryPoint:"main"},fragment:{module:m.createShaderModule({code:p}),entryPoint:"main",targets:[{format:b}]},primitive:{topology:"triangle-list"}}),F=m.createTexture({size:[n.width,n.height],format:R,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),j=F.createView(),z=m.createTexture({size:[n.width,n.height],format:R,usage:GPUTextureUsage.RENDER_ATTACHMENT}),I=z.createView(),W={colorAttachments:[],depthStencilAttachment:{view:j,depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},Q=[{colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:I,depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},{colorAttachments:[{view:void 0,loadOp:"load",storeOp:"store"}],depthStencilAttachment:{view:I,depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}}],N=[{colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:.5,a:1},loadOp:"clear",storeOp:"store"}]},{colorAttachments:[{view:void 0,loadOp:"load",storeOp:"store"}]}],q=m.createBindGroup({layout:D,entries:[{binding:0,resource:j}]}),k=m.createBuffer({size:320,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),H=m.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),X=m.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),Y=[m.createBindGroup({layout:S,entries:[{binding:0,resource:{buffer:k}},{binding:1,resource:{buffer:H}}]}),m.createBindGroup({layout:S,entries:[{binding:0,resource:{buffer:k}},{binding:1,resource:{buffer:X}}]})],Z=[,,,,,],J=new Float32Array(80),K=0;for(let $=0;$<1;$++)for(let ee=0;ee<5;ee++){let en=-800*K,et=1+50*K;Z[K]=i._E.translation(i.R3.fromValues($-.5+.5,(4-.2*en)*(ee-2.5+1),en)),i._E.scale(Z[K],i.R3.fromValues(et,et,et),Z[K]),K++}let er=i._E.translation(i.R3.fromValues(0,0,-12)),ea=.5*n.width/n.height,eo=i._E.perspective(2*Math.PI/5,ea,5,9999),ei=i._E.multiply(eo,er),es=i._E.multiply(P,ei),ed=ei;m.queue.writeBuffer(H,0,ed.buffer,ed.byteOffset,ed.byteLength),ed=es,m.queue.writeBuffer(X,0,ed.buffer,ed.byteOffset,ed.byteLength);let eu=i._E.create(),ec={mode:"color"};r.add(ec,"mode",["color","precision-error","depth-texture"]),requestAnimationFrame(function e(){if(!t.active)return;(function(){let e=Date.now()/1e3;for(let n=0,t=0;n<5;n++,t+=16)i._E.rotate(Z[n],i.R3.fromValues(Math.sin(e),Math.cos(e),0),Math.PI/180*30,eu),J.set(eu,t)})(),m.queue.writeBuffer(k,0,J.buffer,J.byteOffset,J.byteLength);let r=w.getCurrentTexture().createView(),a=m.createCommandEncoder();if("color"===ec.mode)for(let o of v){Q[o].colorAttachments[0].view=r,Q[o].depthStencilAttachment.depthClearValue=x[o];let s=a.beginRenderPass(Q[o]);s.setPipeline(A[o]),s.setBindGroup(0,Y[o]),s.setVertexBuffer(0,B),s.setViewport(n.width*o/2,0,n.width/2,n.height,0,1),s.draw(12,5,0,0),s.end()}else if("precision-error"===ec.mode)for(let d of v){{W.depthStencilAttachment.depthClearValue=x[d];let u=a.beginRenderPass(W);u.setPipeline(C[d]),u.setBindGroup(0,Y[d]),u.setVertexBuffer(0,B),u.setViewport(n.width*d/2,0,n.width/2,n.height,0,1),u.draw(12,5,0,0),u.end()}{Q[d].colorAttachments[0].view=r,Q[d].depthStencilAttachment.depthClearValue=x[d];let c=a.beginRenderPass(Q[d]);c.setPipeline(V[d]),c.setBindGroup(0,Y[d]),c.setBindGroup(1,q),c.setVertexBuffer(0,B),c.setViewport(n.width*d/2,0,n.width/2,n.height,0,1),c.draw(12,5,0,0),c.end()}}else for(let p of v){{W.depthStencilAttachment.depthClearValue=x[p];let l=a.beginRenderPass(W);l.setPipeline(C[p]),l.setBindGroup(0,Y[p]),l.setVertexBuffer(0,B),l.setViewport(n.width*p/2,0,n.width/2,n.height,0,1),l.draw(12,5,0,0),l.end()}{N[p].colorAttachments[0].view=r;let f=a.beginRenderPass(N[p]);f.setPipeline(_),f.setBindGroup(0,q),f.setViewport(n.width*p/2,0,n.width/2,n.height,0,1),f.draw(6),f.end()}}m.queue.submit([a.finish()]),requestAnimationFrame(e)})},y=()=>(0,o.Tl)({name:"Reversed Z",description:"This example shows the use of reversed z technique for better utilization of depth buffer precision.\n The left column uses regular method, while the right one uses reversed z technique.\n Both are using depth32float as their depth buffer format. A set of red and green planes are positioned very close to each other.\n Higher sets are placed further from camera (and are scaled for better visual purpose).\n To use reversed z to render your scene, you will need depth store value to be 0.0, depth compare function to be greater,\n and remap depth range by multiplying an additional matrix to your projection matrix.\n Related reading:\n https://developer.nvidia.com/content/depth-precision-visualized\n https://thxforthefish.com/posts/reverse_z/\n ",gui:!0,init:w,sources:[{name:m.substring(21),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { mat4, vec3 } from 'wgpu-matrix';\n\nimport vertexWGSL from './vertex.wgsl';\nimport fragmentWGSL from './fragment.wgsl';\nimport vertexDepthPrePassWGSL from './vertexDepthPrePass.wgsl';\nimport vertexTextureQuadWGSL from './vertexTextureQuad.wgsl';\nimport fragmentTextureQuadWGSL from './fragmentTextureQuad.wgsl';\nimport vertexPrecisionErrorPassWGSL from './vertexPrecisionErrorPass.wgsl';\nimport fragmentPrecisionErrorPassWGSL from './fragmentPrecisionErrorPass.wgsl';\n\n// Two planes close to each other for depth precision test\nconst geometryVertexSize = 4 * 8; // Byte size of one geometry vertex.\nconst geometryPositionOffset = 0;\nconst geometryColorOffset = 4 * 4; // Byte offset of geometry vertex color attribute.\nconst geometryDrawCount = 6 * 2;\n\nconst d = 0.0001; // half distance between two planes\nconst o = 0.5; // half x offset to shift planes so they are only partially overlaping\n\n// prettier-ignore\nexport const geometryVertexArray = new Float32Array([\n // float4 position, float4 color\n -1 - o, -1, d, 1, 1, 0, 0, 1,\n 1 - o, -1, d, 1, 1, 0, 0, 1,\n -1 - o, 1, d, 1, 1, 0, 0, 1,\n 1 - o, -1, d, 1, 1, 0, 0, 1,\n 1 - o, 1, d, 1, 1, 0, 0, 1,\n -1 - o, 1, d, 1, 1, 0, 0, 1,\n\n -1 + o, -1, -d, 1, 0, 1, 0, 1,\n 1 + o, -1, -d, 1, 0, 1, 0, 1,\n -1 + o, 1, -d, 1, 0, 1, 0, 1,\n 1 + o, -1, -d, 1, 0, 1, 0, 1,\n 1 + o, 1, -d, 1, 0, 1, 0, 1,\n -1 + o, 1, -d, 1, 0, 1, 0, 1,\n]);\n\nconst xCount = 1;\nconst yCount = 5;\nconst numInstances = xCount * yCount;\nconst matrixFloatCount = 16; // 4x4 matrix\nconst matrixStride = 4 * matrixFloatCount; // 64;\n\nconst depthRangeRemapMatrix = mat4.identity();\ndepthRangeRemapMatrix[10] = -1;\ndepthRangeRemapMatrix[14] = 1;\n\nenum DepthBufferMode {\n Default = 0,\n Reversed,\n}\n\nconst depthBufferModes: DepthBufferMode[] = [\n DepthBufferMode.Default,\n DepthBufferMode.Reversed,\n];\nconst depthCompareFuncs = {\n [DepthBufferMode.Default]: 'less' as GPUCompareFunction,\n [DepthBufferMode.Reversed]: 'greater' as GPUCompareFunction,\n};\nconst depthClearValues = {\n [DepthBufferMode.Default]: 1.0,\n [DepthBufferMode.Reversed]: 0.0,\n};\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const verticesBuffer = device.createBuffer({\n size: geometryVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(geometryVertexArray);\n verticesBuffer.unmap();\n\n const depthBufferFormat = 'depth32float';\n\n const depthTextureBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n ],\n });\n\n // Model, view, projection matrices\n const uniformBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const depthPrePassRenderPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [uniformBindGroupLayout],\n });\n\n // depthPrePass is used to render scene to the depth texture\n // this is not needed if you just want to use reversed z to render a scene\n const depthPrePassRenderPipelineDescriptorBase = {\n layout: depthPrePassRenderPipelineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexDepthPrePassWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: geometryVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: geometryPositionOffset,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: depthBufferFormat,\n },\n } as GPURenderPipelineDescriptor;\n\n // we need the depthCompare to fit the depth buffer mode we are using.\n // this is the same for other passes\n const depthPrePassPipelines: GPURenderPipeline[] = [];\n depthPrePassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Default];\n depthPrePassPipelines[DepthBufferMode.Default] = device.createRenderPipeline(\n depthPrePassRenderPipelineDescriptorBase\n );\n depthPrePassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Reversed];\n depthPrePassPipelines[DepthBufferMode.Reversed] = device.createRenderPipeline(\n depthPrePassRenderPipelineDescriptorBase\n );\n\n // precisionPass is to draw precision error as color of depth value stored in depth buffer\n // compared to that directly calcualated in the shader\n const precisionPassRenderPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [uniformBindGroupLayout, depthTextureBindGroupLayout],\n });\n const precisionPassRenderPipelineDescriptorBase = {\n layout: precisionPassRenderPipelineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexPrecisionErrorPassWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: geometryVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: geometryPositionOffset,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentPrecisionErrorPassWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: depthBufferFormat,\n },\n } as GPURenderPipelineDescriptor;\n const precisionPassPipelines: GPURenderPipeline[] = [];\n precisionPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Default];\n precisionPassPipelines[DepthBufferMode.Default] = device.createRenderPipeline(\n precisionPassRenderPipelineDescriptorBase\n );\n precisionPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Reversed];\n // prettier-ignore\n precisionPassPipelines[DepthBufferMode.Reversed] = device.createRenderPipeline(\n precisionPassRenderPipelineDescriptorBase\n );\n\n // colorPass is the regular render pass to render the scene\n const colorPassRenderPiplineLayout = device.createPipelineLayout({\n bindGroupLayouts: [uniformBindGroupLayout],\n });\n const colorPassRenderPipelineDescriptorBase: GPURenderPipelineDescriptor = {\n layout: colorPassRenderPiplineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: geometryVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: geometryPositionOffset,\n format: 'float32x4',\n },\n {\n // color\n shaderLocation: 1,\n offset: geometryColorOffset,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: depthBufferFormat,\n },\n };\n const colorPassPipelines: GPURenderPipeline[] = [];\n colorPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Default];\n colorPassPipelines[DepthBufferMode.Default] = device.createRenderPipeline(\n colorPassRenderPipelineDescriptorBase\n );\n colorPassRenderPipelineDescriptorBase.depthStencil.depthCompare =\n depthCompareFuncs[DepthBufferMode.Reversed];\n colorPassPipelines[DepthBufferMode.Reversed] = device.createRenderPipeline(\n colorPassRenderPipelineDescriptorBase\n );\n\n // textureQuadPass is draw a full screen quad of depth texture\n // to see the difference of depth value using reversed z compared to default depth buffer usage\n // 0.0 will be the furthest and 1.0 will be the closest\n const textureQuadPassPiplineLayout = device.createPipelineLayout({\n bindGroupLayouts: [depthTextureBindGroupLayout],\n });\n const textureQuadPassPipline = device.createRenderPipeline({\n layout: textureQuadPassPiplineLayout,\n vertex: {\n module: device.createShaderModule({\n code: vertexTextureQuadWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentTextureQuadWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: depthBufferFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n const depthTextureView = depthTexture.createView();\n\n const defaultDepthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: depthBufferFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const defaultDepthTextureView = defaultDepthTexture.createView();\n\n const depthPrePassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [],\n depthStencilAttachment: {\n view: depthTextureView,\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n // drawPassDescriptor and drawPassLoadDescriptor are used for drawing\n // the scene twice using different depth buffer mode on splitted viewport\n // of the same canvas\n // see the difference of the loadOp of the colorAttachments\n const drawPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.0, g: 0.0, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: defaultDepthTextureView,\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n const drawPassLoadDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // attachment is acquired and set in render loop.\n view: undefined,\n\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: defaultDepthTextureView,\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n const drawPassDescriptors = [drawPassDescriptor, drawPassLoadDescriptor];\n\n const textureQuadPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.0, g: 0.0, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n const textureQuadPassLoadDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n };\n const textureQuadPassDescriptors = [\n textureQuadPassDescriptor,\n textureQuadPassLoadDescriptor,\n ];\n\n const depthTextureBindGroup = device.createBindGroup({\n layout: depthTextureBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: depthTextureView,\n },\n ],\n });\n\n const uniformBufferSize = numInstances * matrixStride;\n\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const cameraMatrixBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const cameraMatrixReversedDepthBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroups = [\n device.createBindGroup({\n layout: uniformBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: cameraMatrixBuffer,\n },\n },\n ],\n }),\n device.createBindGroup({\n layout: uniformBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: cameraMatrixReversedDepthBuffer,\n },\n },\n ],\n }),\n ];\n\n type Mat4 = mat4.default;\n const modelMatrices = new Array(numInstances);\n const mvpMatricesData = new Float32Array(matrixFloatCount * numInstances);\n\n let m = 0;\n for (let x = 0; x < xCount; x++) {\n for (let y = 0; y < yCount; y++) {\n const z = -800 * m;\n const s = 1 + 50 * m;\n\n modelMatrices[m] = mat4.translation(\n vec3.fromValues(\n x - xCount / 2 + 0.5,\n (4.0 - 0.2 * z) * (y - yCount / 2 + 1.0),\n z\n )\n );\n mat4.scale(modelMatrices[m], vec3.fromValues(s, s, s), modelMatrices[m]);\n\n m++;\n }\n }\n\n const viewMatrix = mat4.translation(vec3.fromValues(0, 0, -12));\n\n const aspect = (0.5 * canvas.width) / canvas.height;\n // wgpu-matrix perspective doesn't handle zFar === Infinity now.\n // https://github.com/greggman/wgpu-matrix/issues/9\n const projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 5, 9999);\n\n const viewProjectionMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n // to use 1/z we just multiple depthRangeRemapMatrix to our default camera view projection matrix\n const reversedRangeViewProjectionMatrix = mat4.multiply(\n depthRangeRemapMatrix,\n viewProjectionMatrix\n );\n\n let bufferData = viewProjectionMatrix as Float32Array;\n device.queue.writeBuffer(\n cameraMatrixBuffer,\n 0,\n bufferData.buffer,\n bufferData.byteOffset,\n bufferData.byteLength\n );\n bufferData = reversedRangeViewProjectionMatrix as Float32Array;\n device.queue.writeBuffer(\n cameraMatrixReversedDepthBuffer,\n 0,\n bufferData.buffer,\n bufferData.byteOffset,\n bufferData.byteLength\n );\n\n const tmpMat4 = mat4.create();\n function updateTransformationMatrix() {\n const now = Date.now() / 1000;\n\n for (let i = 0, m = 0; i < numInstances; i++, m += matrixFloatCount) {\n mat4.rotate(\n modelMatrices[i],\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n (Math.PI / 180) * 30,\n tmpMat4\n );\n mvpMatricesData.set(tmpMat4, m);\n }\n }\n\n const settings = {\n mode: 'color',\n };\n gui.add(settings, 'mode', ['color', 'precision-error', 'depth-texture']);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n mvpMatricesData.buffer,\n mvpMatricesData.byteOffset,\n mvpMatricesData.byteLength\n );\n\n const attachment = context.getCurrentTexture().createView();\n const commandEncoder = device.createCommandEncoder();\n if (settings.mode === 'color') {\n for (const m of depthBufferModes) {\n drawPassDescriptors[m].colorAttachments[0].view = attachment;\n drawPassDescriptors[m].depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const colorPass = commandEncoder.beginRenderPass(\n drawPassDescriptors[m]\n );\n colorPass.setPipeline(colorPassPipelines[m]);\n colorPass.setBindGroup(0, uniformBindGroups[m]);\n colorPass.setVertexBuffer(0, verticesBuffer);\n colorPass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n colorPass.draw(geometryDrawCount, numInstances, 0, 0);\n colorPass.end();\n }\n } else if (settings.mode === 'precision-error') {\n for (const m of depthBufferModes) {\n {\n depthPrePassDescriptor.depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const depthPrePass = commandEncoder.beginRenderPass(\n depthPrePassDescriptor\n );\n depthPrePass.setPipeline(depthPrePassPipelines[m]);\n depthPrePass.setBindGroup(0, uniformBindGroups[m]);\n depthPrePass.setVertexBuffer(0, verticesBuffer);\n depthPrePass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n depthPrePass.draw(geometryDrawCount, numInstances, 0, 0);\n depthPrePass.end();\n }\n {\n drawPassDescriptors[m].colorAttachments[0].view = attachment;\n drawPassDescriptors[m].depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const precisionErrorPass = commandEncoder.beginRenderPass(\n drawPassDescriptors[m]\n );\n precisionErrorPass.setPipeline(precisionPassPipelines[m]);\n precisionErrorPass.setBindGroup(0, uniformBindGroups[m]);\n precisionErrorPass.setBindGroup(1, depthTextureBindGroup);\n precisionErrorPass.setVertexBuffer(0, verticesBuffer);\n precisionErrorPass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n precisionErrorPass.draw(geometryDrawCount, numInstances, 0, 0);\n precisionErrorPass.end();\n }\n }\n } else {\n // depth texture quad\n for (const m of depthBufferModes) {\n {\n depthPrePassDescriptor.depthStencilAttachment.depthClearValue =\n depthClearValues[m];\n const depthPrePass = commandEncoder.beginRenderPass(\n depthPrePassDescriptor\n );\n depthPrePass.setPipeline(depthPrePassPipelines[m]);\n depthPrePass.setBindGroup(0, uniformBindGroups[m]);\n depthPrePass.setVertexBuffer(0, verticesBuffer);\n depthPrePass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n depthPrePass.draw(geometryDrawCount, numInstances, 0, 0);\n depthPrePass.end();\n }\n {\n textureQuadPassDescriptors[m].colorAttachments[0].view = attachment;\n const depthTextureQuadPass = commandEncoder.beginRenderPass(\n textureQuadPassDescriptors[m]\n );\n depthTextureQuadPass.setPipeline(textureQuadPassPipline);\n depthTextureQuadPass.setBindGroup(0, depthTextureBindGroup);\n depthTextureQuadPass.setViewport(\n (canvas.width * m) / 2,\n 0,\n canvas.width / 2,\n canvas.height,\n 0,\n 1\n );\n depthTextureQuadPass.draw(6);\n depthTextureQuadPass.end();\n }\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ReversedZ: () => JSX.Element = () =>\n makeSample({\n name: 'Reversed Z',\n description: `This example shows the use of reversed z technique for better utilization of depth buffer precision.\n The left column uses regular method, while the right one uses reversed z technique.\n Both are using depth32float as their depth buffer format. A set of red and green planes are positioned very close to each other.\n Higher sets are placed further from camera (and are scaled for better visual purpose).\n To use reversed z to render your scene, you will need depth store value to be 0.0, depth compare function to be greater,\n and remap depth range by multiplying an additional matrix to your projection matrix.\n Related reading:\n https://developer.nvidia.com/content/depth-precision-visualized\n https://thxforthefish.com/posts/reverse_z/\n `,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './vertex.wgsl',\n contents: vertexWGSL,\n editable: true,\n },\n {\n name: './fragment.wgsl',\n contents: fragmentWGSL,\n editable: true,\n },\n {\n name: './vertexDepthPrePass.wgsl',\n contents: vertexDepthPrePassWGSL,\n editable: true,\n },\n {\n name: './vertexTextureQuad.wgsl',\n contents: vertexTextureQuadWGSL,\n editable: true,\n },\n {\n name: './fragmentTextureQuad.wgsl',\n contents: fragmentTextureQuadWGSL,\n editable: true,\n },\n {\n name: './vertexPrecisionErrorPass.wgsl',\n contents: vertexPrecisionErrorPassWGSL,\n editable: true,\n },\n {\n name: './fragmentPrecisionErrorPass.wgsl',\n contents: fragmentPrecisionErrorPassWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ReversedZ;\n"},{name:"./vertex.wgsl",contents:s,editable:!0},{name:"./fragment.wgsl",contents:d,editable:!0},{name:"./vertexDepthPrePass.wgsl",contents:u,editable:!0},{name:"./vertexTextureQuad.wgsl",contents:c,editable:!0},{name:"./fragmentTextureQuad.wgsl",contents:p,editable:!0},{name:"./vertexPrecisionErrorPass.wgsl",contents:l,editable:!0},{name:"./fragmentPrecisionErrorPass.wgsl",contents:f,editable:!0}],filename:m});var b=y},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/607.26ab16bb54e128d4.js b/_next/static/chunks/607.26ab16bb54e128d4.js deleted file mode 100644 index fb2e35b6..00000000 --- a/_next/static/chunks/607.26ab16bb54e128d4.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[607],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return u},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let d=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),u=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),g=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,h]=(0,s.useState)(null),[f,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?x(g[1]):x(a[0].name),d&&l.current)for(l.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&u.current&&(m.dom.style.position="absolute",m.showPanel(1),u.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:d,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:u}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":f==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":f==e.name},n))]})]})},u=e=>(0,r.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},6607:function(e,n,t){"use strict";var r="src/sample/helloTriangle/main.ts";t.r(n);var a=t(5671),i=t(1974),o=t(2690);let s=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),a=await r.requestDevice();if(!t.active)return;let s=n.getContext("webgpu"),l=window.devicePixelRatio||1;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let c=navigator.gpu.getPreferredCanvasFormat();s.configure({device:a,format:c,alphaMode:"premultiplied"});let d=a.createRenderPipeline({layout:"auto",vertex:{module:a.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:a.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:c}]},primitive:{topology:"triangle-list"}});requestAnimationFrame(function e(){if(!t.active)return;let n=a.createCommandEncoder(),r=s.getCurrentTexture().createView(),i=n.beginRenderPass({colorAttachments:[{view:r,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});i.setPipeline(d),i.draw(3),i.end(),a.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Hello Triangle",description:"Shows rendering a basic triangle.",init:s,sources:[{name:r.substring(25),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst HelloTriangle: () => JSX.Element = () =>\n makeSample({\n name: 'Hello Triangle',\n description: 'Shows rendering a basic triangle.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default HelloTriangle;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/607.8f22ffbebb313b92.js b/_next/static/chunks/607.8f22ffbebb313b92.js new file mode 100644 index 00000000..c51311fb --- /dev/null +++ b/_next/static/chunks/607.8f22ffbebb313b92.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[607],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return u},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let d=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),u=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),g=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,h]=(0,s.useState)(null),[f,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?x(g[1]):x(a[0].name),d&&l.current)for(l.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&u.current&&(m.dom.style.position="absolute",m.showPanel(1),u.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:d,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:u}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":f==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":f==e.name},n))]})]})},u=e=>(0,r.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},6607:function(e,n,t){"use strict";var r="src/sample/helloTriangle/main.ts";t.r(n);var a=t(5671),i=t(1974),o=t(2690);let s=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),a=await r.requestDevice();if(!t.active)return;let s=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let c=navigator.gpu.getPreferredCanvasFormat();s.configure({device:a,format:c,alphaMode:"premultiplied"});let d=a.createRenderPipeline({layout:"auto",vertex:{module:a.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:a.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:c}]},primitive:{topology:"triangle-list"}});requestAnimationFrame(function e(){if(!t.active)return;let n=a.createCommandEncoder(),r=s.getCurrentTexture().createView(),i=n.beginRenderPass({colorAttachments:[{view:r,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});i.setPipeline(d),i.draw(3),i.end(),a.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Hello Triangle",description:"Shows rendering a basic triangle.",init:s,sources:[{name:r.substring(25),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst HelloTriangle: () => JSX.Element = () =>\n makeSample({\n name: 'Hello Triangle',\n description: 'Shows rendering a basic triangle.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default HelloTriangle;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/613.0bfe8fe854dbcde4.js b/_next/static/chunks/613.0bfe8fe854dbcde4.js new file mode 100644 index 00000000..153c27ba --- /dev/null +++ b/_next/static/chunks/613.0bfe8fe854dbcde4.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[613],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return m},hu:function(){return f}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),m=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,o.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[x,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();f&&m.current&&(f.dom.style.position="absolute",f.showPanel(1),m.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:l,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){v(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},m=e=>(0,r.jsx)(l,{...e});function f(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},613:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return m}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_2d;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV) * fragPosition;\n}\n",c="src/sample/texturedCube/main.ts";let u=async e=>{let n,{canvas:a,pageState:c}=e,u=await navigator.gpu.requestAdapter(),l=await u.requestDevice();if(!c.active)return;let m=a.getContext("webgpu"),f=window.devicePixelRatio;a.width=a.clientWidth*f,a.height=a.clientHeight*f;let d=navigator.gpu.getPreferredCanvasFormat();m.configure({device:l,format:d,alphaMode:"premultiplied"});let p=l.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(p.getMappedRange()).set(i.zS),p.unmap();let g=l.createRenderPipeline({layout:"auto",vertex:{module:l.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:l.createShaderModule({code:s}),entryPoint:"main",targets:[{format:d}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),h=l.createTexture({size:[a.width,a.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),x=l.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let v=await fetch(new t.U(t(5685)).toString()),b=await createImageBitmap(await v.blob());n=l.createTexture({size:[b.width,b.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),l.queue.copyExternalImageToTexture({source:b},{texture:n},[b.width,b.height])}let w=l.createSampler({magFilter:"linear",minFilter:"linear"}),T=l.createBindGroup({layout:g.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:x}},{binding:1,resource:w},{binding:2,resource:n.createView()}]}),P={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:h.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},y=a.width/a.height,C=r._E.perspective(2*Math.PI/5,y,1,100),S=r._E.create();requestAnimationFrame(function e(){if(!c.active)return;let n=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotate(e,r.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),r._E.multiply(C,e,S),S}();l.queue.writeBuffer(x,0,n.buffer,n.byteOffset,n.byteLength),P.colorAttachments[0].view=m.getCurrentTexture().createView();let t=l.createCommandEncoder(),a=t.beginRenderPass(P);a.setPipeline(g),a.setBindGroup(0,T),a.setVertexBuffer(0,p),a.draw(i.MO),a.end(),l.queue.submit([t.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Textured Cube",description:"This example shows how to bind and sample textures.",init:u,sources:[{name:c.substring(24),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleTextureMixColorWGSL from './sampleTextureMixColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleTextureMixColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the image and upload it into a GPUTexture.\n let cubeTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/Di-3d.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n cubeTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubeTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst TexturedCube: () => JSX.Element = () =>\n makeSample({\n name: 'Textured Cube',\n description: 'This example shows how to bind and sample textures.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleTextureMixColor.frag.wgsl',\n contents: sampleTextureMixColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default TexturedCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleTextureMixColor.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var m=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},5685:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/Di-3d.ba319100a0ec2120.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/613.293d61cb60f10626.js b/_next/static/chunks/613.293d61cb60f10626.js deleted file mode 100644 index 21ff2fa2..00000000 --- a/_next/static/chunks/613.293d61cb60f10626.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[613],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return m},hu:function(){return f}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),m=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,o.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[x,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();f&&m.current&&(f.dom.style.position="absolute",f.showPanel(1),m.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:l,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){v(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},m=e=>(0,r.jsx)(l,{...e});function f(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},613:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return m}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_2d;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV) * fragPosition;\n}\n",c="src/sample/texturedCube/main.ts";let u=async e=>{let n,{canvas:a,pageState:c}=e,u=await navigator.gpu.requestAdapter(),l=await u.requestDevice();if(!c.active)return;let m=a.getContext("webgpu"),f=window.devicePixelRatio||1;a.width=a.clientWidth*f,a.height=a.clientHeight*f;let d=navigator.gpu.getPreferredCanvasFormat();m.configure({device:l,format:d,alphaMode:"premultiplied"});let p=l.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(p.getMappedRange()).set(i.zS),p.unmap();let g=l.createRenderPipeline({layout:"auto",vertex:{module:l.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:l.createShaderModule({code:s}),entryPoint:"main",targets:[{format:d}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),h=l.createTexture({size:[a.width,a.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),x=l.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let v=await fetch(new t.U(t(5685)).toString()),b=await createImageBitmap(await v.blob());n=l.createTexture({size:[b.width,b.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),l.queue.copyExternalImageToTexture({source:b},{texture:n},[b.width,b.height])}let w=l.createSampler({magFilter:"linear",minFilter:"linear"}),T=l.createBindGroup({layout:g.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:x}},{binding:1,resource:w},{binding:2,resource:n.createView()}]}),P={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:h.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},y=a.width/a.height,C=r._E.perspective(2*Math.PI/5,y,1,100),S=r._E.create();requestAnimationFrame(function e(){if(!c.active)return;let n=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotate(e,r.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),r._E.multiply(C,e,S),S}();l.queue.writeBuffer(x,0,n.buffer,n.byteOffset,n.byteLength),P.colorAttachments[0].view=m.getCurrentTexture().createView();let t=l.createCommandEncoder(),a=t.beginRenderPass(P);a.setPipeline(g),a.setBindGroup(0,T),a.setVertexBuffer(0,p),a.draw(i.MO),a.end(),l.queue.submit([t.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Textured Cube",description:"This example shows how to bind and sample textures.",init:u,sources:[{name:c.substring(24),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleTextureMixColorWGSL from './sampleTextureMixColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleTextureMixColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the image and upload it into a GPUTexture.\n let cubeTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/Di-3d.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n cubeTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubeTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst TexturedCube: () => JSX.Element = () =>\n makeSample({\n name: 'Textured Cube',\n description: 'This example shows how to bind and sample textures.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleTextureMixColor.frag.wgsl',\n contents: sampleTextureMixColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default TexturedCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleTextureMixColor.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var m=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},5685:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/Di-3d.ba319100a0ec2120.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/621.0c908b759f0bd83b.js b/_next/static/chunks/621.0c908b759f0bd83b.js deleted file mode 100644 index 9bf11f21..00000000 --- a/_next/static/chunks/621.0c908b759f0bd83b.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[621],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,i.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,v]=(0,s.useState)(null),[x,g]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?g(p[1]):g(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();m&&f.current&&(m.dom.style.position="absolute",m.showPanel(1),f.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:l,stats:m});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){g(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return o},MO:function(){return i},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,o=32,i=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},8621:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),o=t(4655),i="struct Uniforms {\n modelViewProjectionMatrix : array, 16>,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix[instanceIdx] * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0));\n return output;\n}\n",s=t(1945),c="src/sample/instancedCube/main.ts";let u=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),c=await a.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio||1;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:f,alphaMode:"premultiplied"});let m=c.createBuffer({size:o.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(o.zS),m.unmap();let d=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:i}),entryPoint:"main",buffers:[{arrayStride:o.O$,attributes:[{shaderLocation:0,offset:o.v8,format:"float32x4"},{shaderLocation:1,offset:o.Ax,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:s.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=c.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:1024,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=c.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),x=n.width/n.height,g=r._E.perspective(2*Math.PI/5,x,1,100),b=Array(16),y=new Float32Array(256),w=0;for(let C=0;C<4;C++)for(let P=0;P<4;P++)b[w]=r._E.translation(r.R3.fromValues(4*(C-2+.5),4*(P-2+.5),0)),w++;let M=r._E.translation(r.R3.fromValues(0,0,-12)),S=r._E.create(),_={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}};requestAnimationFrame(function e(){if(!t.active)return;!function(){let e=Date.now()/1e3,n=0,t=0;for(let a=0;a<4;a++)for(let o=0;o<4;o++)r._E.rotate(b[t],r.R3.fromValues(Math.sin((a+.5)*e),Math.cos((o+.5)*e),0),1,S),r._E.multiply(M,S,S),r._E.multiply(g,S,S),y.set(S,n),t++,n+=16}(),c.queue.writeBuffer(h,0,y.buffer,y.byteOffset,y.byteLength),_.colorAttachments[0].view=u.getCurrentTexture().createView();let n=c.createCommandEncoder(),a=n.beginRenderPass(_);a.setPipeline(d),a.setBindGroup(0,v),a.setVertexBuffer(0,m),a.draw(o.MO,16,0,0),a.end(),c.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Instanced Cube",description:"This example shows the use of instancing.",init:u,sources:[{name:c.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport instancedVertWGSL from './instanced.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: instancedVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const xCount = 4;\n const yCount = 4;\n const numInstances = xCount * yCount;\n const matrixFloatCount = 16; // 4x4 matrix\n const matrixSize = 4 * matrixFloatCount;\n const uniformBufferSize = numInstances * matrixSize;\n\n // Allocate a buffer large enough to hold transforms for every\n // instance.\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n\n type Mat4 = mat4.default;\n const modelMatrices = new Array(numInstances);\n const mvpMatricesData = new Float32Array(matrixFloatCount * numInstances);\n\n const step = 4.0;\n\n // Initialize the matrix data for every instance.\n let m = 0;\n for (let x = 0; x < xCount; x++) {\n for (let y = 0; y < yCount; y++) {\n modelMatrices[m] = mat4.translation(\n vec3.fromValues(\n step * (x - xCount / 2 + 0.5),\n step * (y - yCount / 2 + 0.5),\n 0\n )\n );\n m++;\n }\n }\n\n const viewMatrix = mat4.translation(vec3.fromValues(0, 0, -12));\n\n const tmpMat4 = mat4.create();\n\n // Update the transformation matrix data for each instance.\n function updateTransformationMatrix() {\n const now = Date.now() / 1000;\n\n let m = 0,\n i = 0;\n for (let x = 0; x < xCount; x++) {\n for (let y = 0; y < yCount; y++) {\n mat4.rotate(\n modelMatrices[i],\n vec3.fromValues(\n Math.sin((x + 0.5) * now),\n Math.cos((y + 0.5) * now),\n 0\n ),\n 1,\n tmpMat4\n );\n\n mat4.multiply(viewMatrix, tmpMat4, tmpMat4);\n mat4.multiply(projectionMatrix, tmpMat4, tmpMat4);\n\n mvpMatricesData.set(tmpMat4, m);\n\n i++;\n m += matrixFloatCount;\n }\n }\n }\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n // Update the matrix data.\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n mvpMatricesData.buffer,\n mvpMatricesData.byteOffset,\n mvpMatricesData.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount, numInstances, 0, 0);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst InstancedCube: () => JSX.Element = () =>\n makeSample({\n name: 'Instanced Cube',\n description: 'This example shows the use of instancing.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/instanced.vert.wgsl',\n contents: instancedVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default InstancedCube;\n"},{name:"../../shaders/instanced.vert.wgsl",contents:i,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:s.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var f=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/621.d0b061a54d79a4bf.js b/_next/static/chunks/621.d0b061a54d79a4bf.js new file mode 100644 index 00000000..eac677da --- /dev/null +++ b/_next/static/chunks/621.d0b061a54d79a4bf.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[621],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,i.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,v]=(0,s.useState)(null),[x,g]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?g(p[1]):g(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();m&&f.current&&(m.dom.style.position="absolute",m.showPanel(1),f.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:l,stats:m});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){g(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return o},MO:function(){return i},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,o=32,i=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},8621:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),o=t(4655),i="struct Uniforms {\n modelViewProjectionMatrix : array, 16>,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix[instanceIdx] * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0));\n return output;\n}\n",s=t(1945),c="src/sample/instancedCube/main.ts";let u=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),c=await a.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:f,alphaMode:"premultiplied"});let m=c.createBuffer({size:o.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(o.zS),m.unmap();let d=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:i}),entryPoint:"main",buffers:[{arrayStride:o.O$,attributes:[{shaderLocation:0,offset:o.v8,format:"float32x4"},{shaderLocation:1,offset:o.Ax,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:s.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=c.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:1024,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=c.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),x=n.width/n.height,g=r._E.perspective(2*Math.PI/5,x,1,100),b=Array(16),y=new Float32Array(256),w=0;for(let C=0;C<4;C++)for(let P=0;P<4;P++)b[w]=r._E.translation(r.R3.fromValues(4*(C-2+.5),4*(P-2+.5),0)),w++;let M=r._E.translation(r.R3.fromValues(0,0,-12)),S=r._E.create(),_={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}};requestAnimationFrame(function e(){if(!t.active)return;!function(){let e=Date.now()/1e3,n=0,t=0;for(let a=0;a<4;a++)for(let o=0;o<4;o++)r._E.rotate(b[t],r.R3.fromValues(Math.sin((a+.5)*e),Math.cos((o+.5)*e),0),1,S),r._E.multiply(M,S,S),r._E.multiply(g,S,S),y.set(S,n),t++,n+=16}(),c.queue.writeBuffer(h,0,y.buffer,y.byteOffset,y.byteLength),_.colorAttachments[0].view=u.getCurrentTexture().createView();let n=c.createCommandEncoder(),a=n.beginRenderPass(_);a.setPipeline(d),a.setBindGroup(0,v),a.setVertexBuffer(0,m),a.draw(o.MO,16,0,0),a.end(),c.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Instanced Cube",description:"This example shows the use of instancing.",init:u,sources:[{name:c.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport instancedVertWGSL from './instanced.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: instancedVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const xCount = 4;\n const yCount = 4;\n const numInstances = xCount * yCount;\n const matrixFloatCount = 16; // 4x4 matrix\n const matrixSize = 4 * matrixFloatCount;\n const uniformBufferSize = numInstances * matrixSize;\n\n // Allocate a buffer large enough to hold transforms for every\n // instance.\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n\n type Mat4 = mat4.default;\n const modelMatrices = new Array(numInstances);\n const mvpMatricesData = new Float32Array(matrixFloatCount * numInstances);\n\n const step = 4.0;\n\n // Initialize the matrix data for every instance.\n let m = 0;\n for (let x = 0; x < xCount; x++) {\n for (let y = 0; y < yCount; y++) {\n modelMatrices[m] = mat4.translation(\n vec3.fromValues(\n step * (x - xCount / 2 + 0.5),\n step * (y - yCount / 2 + 0.5),\n 0\n )\n );\n m++;\n }\n }\n\n const viewMatrix = mat4.translation(vec3.fromValues(0, 0, -12));\n\n const tmpMat4 = mat4.create();\n\n // Update the transformation matrix data for each instance.\n function updateTransformationMatrix() {\n const now = Date.now() / 1000;\n\n let m = 0,\n i = 0;\n for (let x = 0; x < xCount; x++) {\n for (let y = 0; y < yCount; y++) {\n mat4.rotate(\n modelMatrices[i],\n vec3.fromValues(\n Math.sin((x + 0.5) * now),\n Math.cos((y + 0.5) * now),\n 0\n ),\n 1,\n tmpMat4\n );\n\n mat4.multiply(viewMatrix, tmpMat4, tmpMat4);\n mat4.multiply(projectionMatrix, tmpMat4, tmpMat4);\n\n mvpMatricesData.set(tmpMat4, m);\n\n i++;\n m += matrixFloatCount;\n }\n }\n }\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n // Update the matrix data.\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n mvpMatricesData.buffer,\n mvpMatricesData.byteOffset,\n mvpMatricesData.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount, numInstances, 0, 0);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst InstancedCube: () => JSX.Element = () =>\n makeSample({\n name: 'Instanced Cube',\n description: 'This example shows the use of instancing.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/instanced.vert.wgsl',\n contents: instancedVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default InstancedCube;\n"},{name:"../../shaders/instanced.vert.wgsl",contents:i,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:s.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var f=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/677.6d4152a3263d941e.js b/_next/static/chunks/677.6d4152a3263d941e.js new file mode 100644 index 00000000..ad5987a8 --- /dev/null +++ b/_next/static/chunks/677.6d4152a3263d941e.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[677],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),v=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,f]=(0,s.useState)(null),[x,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(v?h(v[1]):h(a[0].name),c&&l.current)for(l.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:c,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),f(e)})}catch(s){console.error(s),f(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){h(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function m(e,n){if(!e)throw Error(n)}},6677:function(e,n,t){"use strict";var r="src/sample/videoUploading/main.ts";t.r(n);var a=t(5671),i=t(134),o=t(7618);let s=async e=>{let{canvas:n,pageState:r,gui:a}=e,s=document.createElement("video");s.loop=!0,s.autoplay=!0,s.muted=!0,s.src=new t.U(t(9082)).toString(),await s.play();let l=await navigator.gpu.requestAdapter(),u=await l.requestDevice();if(!r.active)return;let c=n.getContext("webgpu"),d=window.devicePixelRatio;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let m=navigator.gpu.getPreferredCanvasFormat();c.configure({device:u,format:m,alphaMode:"premultiplied"});let p=u.createRenderPipeline({layout:"auto",vertex:{module:u.createShaderModule({code:i.Z}),entryPoint:"vert_main"},fragment:{module:u.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"}}),v=u.createSampler({magFilter:"linear",minFilter:"linear"}),g={requestFrame:"requestAnimationFrame"};function f(){if(!r.active)return;let e=u.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:1,resource:v},{binding:2,resource:u.importExternalTexture({source:s})}]}),n=u.createCommandEncoder(),t=c.getCurrentTexture().createView(),a=n.beginRenderPass({colorAttachments:[{view:t,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});a.setPipeline(p),a.setBindGroup(0,e),a.draw(6),a.end(),u.queue.submit([n.finish()]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)}a.add(g,"requestFrame",["requestAnimationFrame","requestVideoFrameCallback"]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)},l=()=>(0,a.Tl)({name:"Video Uploading",description:"This example shows how to upload video frame to WebGPU.",gui:!0,init:s,sources:[{name:r.substring(26),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\nimport sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n // Set video element\n const video = document.createElement('video');\n video.loop = true;\n video.autoplay = true;\n video.muted = true;\n video.src = new URL(\n '../../../assets/video/pano.webm',\n import.meta.url\n ).toString();\n await video.play();\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleExternalTextureWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const settings = {\n requestFrame: 'requestAnimationFrame',\n };\n\n gui.add(settings, 'requestFrame', [\n 'requestAnimationFrame',\n 'requestVideoFrameCallback',\n ]);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: device.importExternalTexture({\n source: video,\n }),\n },\n ],\n });\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n }\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n};\n\nconst VideoUploading: () => JSX.Element = () =>\n makeSample({\n name: 'Video Uploading',\n description: 'This example shows how to upload video frame to WebGPU.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n {\n name: '../../shaders/sampleExternalTexture.wgsl',\n contents: sampleExternalTextureWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default VideoUploading;\n"},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/sampleExternalTexture.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"},7618:function(e,n){"use strict";n.Z="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_external;\n\n@fragment\nfn main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSampleBaseClampToEdge(myTexture, mySampler, fragUV);\n}\n"},9082:function(e,n,t){"use strict";e.exports=t.p+"static/assets/video/pano.5b0db72b3dd7f1b9.webm"}}]); \ No newline at end of file diff --git a/_next/static/chunks/677.8a78fd518ba6a07f.js b/_next/static/chunks/677.8a78fd518ba6a07f.js deleted file mode 100644 index 2fe7bd21..00000000 --- a/_next/static/chunks/677.8a78fd518ba6a07f.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[677],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),v=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,f]=(0,s.useState)(null),[x,h]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(v?h(v[1]):h(a[0].name),c&&l.current)for(l.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:c,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),f(e)})}catch(s){console.error(s),f(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){h(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function m(e,n){if(!e)throw Error(n)}},6677:function(e,n,t){"use strict";var r="src/sample/videoUploading/main.ts";t.r(n);var a=t(5671),i=t(134),o=t(7618);let s=async e=>{let{canvas:n,pageState:r,gui:a}=e,s=document.createElement("video");s.loop=!0,s.autoplay=!0,s.muted=!0,s.src=new t.U(t(9082)).toString(),await s.play();let l=await navigator.gpu.requestAdapter(),u=await l.requestDevice();if(!r.active)return;let c=n.getContext("webgpu"),d=window.devicePixelRatio||1;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let m=navigator.gpu.getPreferredCanvasFormat();c.configure({device:u,format:m,alphaMode:"premultiplied"});let p=u.createRenderPipeline({layout:"auto",vertex:{module:u.createShaderModule({code:i.Z}),entryPoint:"vert_main"},fragment:{module:u.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"}}),v=u.createSampler({magFilter:"linear",minFilter:"linear"}),g={requestFrame:"requestAnimationFrame"};function f(){if(!r.active)return;let e=u.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:1,resource:v},{binding:2,resource:u.importExternalTexture({source:s})}]}),n=u.createCommandEncoder(),t=c.getCurrentTexture().createView(),a=n.beginRenderPass({colorAttachments:[{view:t,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});a.setPipeline(p),a.setBindGroup(0,e),a.draw(6),a.end(),u.queue.submit([n.finish()]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)}a.add(g,"requestFrame",["requestAnimationFrame","requestVideoFrameCallback"]),"requestVideoFrameCallback"==g.requestFrame?s.requestVideoFrameCallback(f):requestAnimationFrame(f)},l=()=>(0,a.Tl)({name:"Video Uploading",description:"This example shows how to upload video frame to WebGPU.",gui:!0,init:s,sources:[{name:r.substring(26),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\nimport sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n // Set video element\n const video = document.createElement('video');\n video.loop = true;\n video.autoplay = true;\n video.muted = true;\n video.src = new URL(\n '../../../assets/video/pano.webm',\n import.meta.url\n ).toString();\n await video.play();\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleExternalTextureWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const settings = {\n requestFrame: 'requestAnimationFrame',\n };\n\n gui.add(settings, 'requestFrame', [\n 'requestAnimationFrame',\n 'requestVideoFrameCallback',\n ]);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: device.importExternalTexture({\n source: video,\n }),\n },\n ],\n });\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n }\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n};\n\nconst VideoUploading: () => JSX.Element = () =>\n makeSample({\n name: 'Video Uploading',\n description: 'This example shows how to upload video frame to WebGPU.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n {\n name: '../../shaders/sampleExternalTexture.wgsl',\n contents: sampleExternalTextureWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default VideoUploading;\n"},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/sampleExternalTexture.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"},7618:function(e,n){"use strict";n.Z="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_external;\n\n@fragment\nfn main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSampleBaseClampToEdge(myTexture, mySampler, fragUV);\n}\n"},9082:function(e,n,t){"use strict";e.exports=t.p+"static/assets/video/pano.5b0db72b3dd7f1b9.webm"}}]); \ No newline at end of file diff --git a/_next/static/chunks/704.87cab28fa178c3b9.js b/_next/static/chunks/704.87cab28fa178c3b9.js deleted file mode 100644 index c8fdc492..00000000 --- a/_next/static/chunks/704.87cab28fa178c3b9.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[704],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return c}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),f=t.n(u);t(7319);let l=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),g=(0,o.useRouter)(),m=g.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[p,h]=(0,s.useState)(null),[v,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?x(m[1]):x(i[0].name),l&&u.current)for(u.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();c&&d.current&&(c.dom.style.position="absolute",c.showPanel(1),d.current.appendChild(c.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:l,stats:c});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),p?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(p)})]}):null]}),(0,r.jsxs)("div",{className:f().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:f().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){x(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:f().sourceFileContainer,"data-active":v==e.name},n))]})]})},d=e=>(0,r.jsx)(l,{...e});function c(e,n){if(!e)throw Error(n)}},6888:function(e,n,t){"use strict";t.d(n,{W:function(){return a}});var r=t(6906),i=t(9385);let a={positions:r.m,triangles:r.g,normals:[],uvs:[]};a.normals=(0,i.b)(a.positions,a.triangles),a.uvs=(0,i.q)(a.positions,"xy"),a.triangles.push([a.positions.length,a.positions.length+2,a.positions.length+1],[a.positions.length,a.positions.length+1,a.positions.length+3]),a.positions.push([-100,20,-100],[100,20,100],[-100,20,100],[100,20,-100]),a.normals.push([0,1,0],[0,1,0],[0,1,0],[0,1,0]),a.uvs.push([0,0],[1,1],[0,1],[1,0])},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return i},q:function(){return o}});var r=t(6416);function i(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[i,a,o]=n,s=e[i],u=e[a],f=e[o],l=r.R3.subtract(u,s),d=r.R3.subtract(f,s);r.R3.normalize(l,l),r.R3.normalize(d,d);let c=r.R3.cross(l,d);r.R3.add(t[i],c,t[i]),r.R3.add(t[a],c,t[a]),r.R3.add(t[o],c,t[o])}),t.forEach(e=>{r.R3.normalize(e,e)}),t}let a={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=a[n],r=e.map(()=>[0,0]),i=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{r[n][0]=e[t[0]],r[n][1]=e[t[1]],i[0]=Math.min(e[t[0]],i[0]),i[1]=Math.min(e[t[1]],i[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),r.forEach(e=>{e[0]=(e[0]-i[0])/(o[0]-i[0]),e[1]=(e[1]-i[1])/(o[1]-i[1])}),r}},9704:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return v}});var r=t(5671),i=t(6416),a=t(6888),o="struct LightData {\n position : vec4,\n color : vec3,\n radius : f32,\n}\nstruct LightsBuffer {\n lights: array,\n}\n@group(0) @binding(0) var lightsBuffer: LightsBuffer;\n\nstruct Config {\n numLights : u32,\n}\n@group(0) @binding(1) var config: Config;\n\nstruct LightExtent {\n min : vec4,\n max : vec4,\n}\n@group(0) @binding(2) var lightExtent: LightExtent;\n\n@compute @workgroup_size(64, 1, 1)\nfn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) {\n var index = GlobalInvocationID.x;\n if (index >= config.numLights) {\n return;\n }\n\n lightsBuffer.lights[index].position.y = lightsBuffer.lights[index].position.y - 0.5 - 0.003 * (f32(index) - 64.0 * floor(f32(index) / 64.0));\n\n if (lightsBuffer.lights[index].position.y < lightExtent.min.y) {\n lightsBuffer.lights[index].position.y = lightExtent.max.y;\n }\n}\n",s="struct Uniforms {\n modelMatrix : mat4x4,\n normalModelMatrix : mat4x4,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n invViewProjectionMatrix : mat4x4,\n}\n@group(0) @binding(0) var uniforms : Uniforms;\n@group(0) @binding(1) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragNormal: vec3, // normal in world space\n @location(1) fragUV: vec2,\n}\n\n@vertex\nfn main(\n @location(0) position : vec3,\n @location(1) normal : vec3,\n @location(2) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n let worldPosition = (uniforms.modelMatrix * vec4(position, 1.0)).xyz;\n output.Position = camera.viewProjectionMatrix * vec4(worldPosition, 1.0);\n output.fragNormal = normalize((uniforms.normalModelMatrix * vec4(normal, 1.0)).xyz);\n output.fragUV = uv;\n return output;\n}\n",u="struct GBufferOutput {\n @location(0) normal : vec4,\n\n // Textures: diffuse color, specular color, smoothness, emissive etc. could go here\n @location(1) albedo : vec4,\n}\n\n@fragment\nfn main(\n @location(0) fragNormal: vec3,\n @location(1) fragUV : vec2\n) -> GBufferOutput {\n // faking some kind of checkerboard texture\n let uv = floor(30.0 * fragUV);\n let c = 0.2 + 0.5 * ((uv.x + uv.y) - 2.0 * floor((uv.x + uv.y) / 2.0));\n\n var output : GBufferOutput;\n output.normal = vec4(fragNormal, 1.0);\n output.albedo = vec4(c, c, c, 1.0);\n\n return output;\n}\n",f="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n const pos = array(\n vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0),\n vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0),\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n",l="\n@group(0) @binding(0) var gBufferNormal: texture_2d;\n@group(0) @binding(1) var gBufferAlbedo: texture_2d;\n@group(0) @binding(2) var gBufferDepth: texture_depth_2d;\n\noverride canvasSizeWidth: f32;\noverride canvasSizeHeight: f32;\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n var result : vec4;\n let c = coord.xy / vec2(canvasSizeWidth, canvasSizeHeight);\n if (c.x < 0.33333) {\n let rawDepth = textureLoad(\n gBufferDepth,\n vec2(floor(coord.xy)),\n 0\n );\n // remap depth into something a bit more visible\n let depth = (1.0 - rawDepth) * 50.0;\n result = vec4(depth);\n } else if (c.x < 0.66667) {\n result = textureLoad(\n gBufferNormal,\n vec2(floor(coord.xy)),\n 0\n );\n result.x = (result.x + 1.0) * 0.5;\n result.y = (result.y + 1.0) * 0.5;\n result.z = (result.z + 1.0) * 0.5;\n } else {\n result = textureLoad(\n gBufferAlbedo,\n vec2(floor(coord.xy)),\n 0\n );\n }\n return result;\n}\n",d="\n@group(0) @binding(0) var gBufferNormal: texture_2d;\n@group(0) @binding(1) var gBufferAlbedo: texture_2d;\n@group(0) @binding(2) var gBufferDepth: texture_depth_2d;\n\nstruct LightData {\n position : vec4,\n color : vec3,\n radius : f32,\n}\nstruct LightsBuffer {\n lights: array,\n}\n@group(1) @binding(0) var lightsBuffer: LightsBuffer;\n\nstruct Config {\n numLights : u32,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n invViewProjectionMatrix : mat4x4,\n}\n@group(1) @binding(1) var config: Config;\n@group(1) @binding(2) var camera: Camera;\n\nfn world_from_screen_coord(coord : vec2, depth_sample: f32) -> vec3 {\n // reconstruct world-space position from the screen coordinate.\n let posClip = vec4(coord.x * 2.0 - 1.0, (1.0 - coord.y) * 2.0 - 1.0, depth_sample, 1.0);\n let posWorldW = camera.invViewProjectionMatrix * posClip;\n let posWorld = posWorldW.xyz / posWorldW.www;\n return posWorld;\n}\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n var result : vec3;\n\n let depth = textureLoad(\n gBufferDepth,\n vec2(floor(coord.xy)),\n 0\n );\n\n // Don't light the sky.\n if (depth >= 1.0) {\n discard;\n }\n\n let bufferSize = textureDimensions(gBufferDepth);\n let coordUV = coord.xy / vec2(bufferSize);\n let position = world_from_screen_coord(coordUV, depth);\n\n let normal = textureLoad(\n gBufferNormal,\n vec2(floor(coord.xy)),\n 0\n ).xyz;\n\n let albedo = textureLoad(\n gBufferAlbedo,\n vec2(floor(coord.xy)),\n 0\n ).rgb;\n\n for (var i = 0u; i < config.numLights; i++) {\n let L = lightsBuffer.lights[i].position.xyz - position;\n let distance = length(L);\n if (distance > lightsBuffer.lights[i].radius) {\n continue;\n }\n let lambert = max(dot(normal, normalize(L)), 0.0);\n result += vec3(\n lambert * pow(1.0 - distance / lightsBuffer.lights[i].radius, 2.0) * lightsBuffer.lights[i].color * albedo\n );\n }\n\n // some manual ambient\n result += vec3(0.2);\n\n return vec4(result, 1.0);\n}\n",c="src/sample/deferredRendering/main.ts";let g=i.R3.fromValues(-50,-30,-50),m=i.R3.fromValues(50,50,50),p=async e=>{let{canvas:n,pageState:t,gui:r}=e,c=await navigator.gpu.requestAdapter(),p=await c.requestDevice();if(!t.active)return;let h=n.getContext("webgpu"),v=window.devicePixelRatio||1;n.width=n.clientWidth*v,n.height=n.clientHeight*v;let x=n.width/n.height,b=navigator.gpu.getPreferredCanvasFormat();h.configure({device:p,format:b,alphaMode:"premultiplied"});let B=p.createBuffer({size:8*a.W.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});{let P=new Float32Array(B.getMappedRange());for(let y=0;y{let e=p.createBuffer({size:Uint32Array.BYTES_PER_ELEMENT,mappedAtCreation:!0,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});return new Uint32Array(e.getMappedRange())[0]=j.numLights,e.unmap(),e})();r.add(j,"mode",["rendering","gBuffers view"]),r.add(j,"numLights",1,1024).step(1).onChange(()=>{p.queue.writeBuffer(z,0,new Uint32Array([j.numLights]))});let I=p.createBuffer({size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),W=p.createBuffer({size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),k=p.createBindGroup({layout:V.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:I}},{binding:1,resource:{buffer:W}}]}),q=p.createBindGroup({layout:A,entries:[{binding:0,resource:S[0]},{binding:1,resource:S[1]},{binding:2,resource:S[2]}]}),Y=i.R3.sub(m,g),H=8192*Float32Array.BYTES_PER_ELEMENT,Q=p.createBuffer({size:H,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),X=new Float32Array(Q.getMappedRange()),J=i.vh.create(),Z=0;for(let K=0;K<1024;K++){Z=8*K;for(let $=0;$<3;$++)J[$]=Math.random()*Y[$]+g[$];J[3]=1,X.set(J,Z),J[0]=2*Math.random(),J[1]=2*Math.random(),J[2]=2*Math.random(),J[3]=20,X.set(J,Z+4)}Q.unmap();let ee=p.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),en=new Float32Array(8);en.set(g,0),en.set(m,4),p.queue.writeBuffer(ee,0,en.buffer,en.byteOffset,en.byteLength);let et=p.createComputePipeline({layout:"auto",compute:{module:p.createShaderModule({code:o}),entryPoint:"main"}}),er=p.createBindGroup({layout:D,entries:[{binding:0,resource:{buffer:Q}},{binding:1,resource:{buffer:z}},{binding:2,resource:{buffer:W}}]}),ei=p.createBindGroup({layout:et.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:Q}},{binding:1,resource:{buffer:z}},{binding:2,resource:{buffer:ee}}]}),ea=i.R3.fromValues(0,50,-100),eo=i.R3.fromValues(0,1,0),es=i.R3.fromValues(0,0,0),eu=i._E.perspective(2*Math.PI/5,x,1,2e3),ef=i._E.inverse(i._E.lookAt(ea,es,eo)),el=i._E.multiply(eu,ef),ed=i._E.translation([0,-45,0]);p.queue.writeBuffer(I,0,ed.buffer,ed.byteOffset,ed.byteLength);let ec=i._E.invert(ed);i._E.transpose(ec,ec),p.queue.writeBuffer(I,64,ec.buffer,ec.byteOffset,ec.byteLength),requestAnimationFrame(function e(){if(!t.active)return;let n=function(){let e=i.R3.fromValues(0,50,-100),n=Math.PI*(Date.now()/5e3),t=i._E.rotateY(i._E.translation(es),n);i.R3.transformMat4(e,t,e);let r=i.R3.transformMat4(e,t),a=i._E.lookAt(r,es,eo);return i._E.multiply(eu,a,el),el}();p.queue.writeBuffer(W,0,n.buffer,n.byteOffset,n.byteLength);let r=i._E.invert(n);p.queue.writeBuffer(W,64,r.buffer,r.byteOffset,r.byteLength);let a=p.createCommandEncoder();{let o=a.beginRenderPass(F);o.setPipeline(V),o.setBindGroup(0,k),o.setVertexBuffer(0,B),o.setIndexBuffer(E,"uint16"),o.drawIndexed(w),o.end()}{let s=a.beginComputePass();s.setPipeline(et),s.setBindGroup(0,ei),s.dispatchWorkgroups(Math.ceil(16)),s.end()}if("gBuffers view"===j.mode){O.colorAttachments[0].view=h.getCurrentTexture().createView();let u=a.beginRenderPass(O);u.setPipeline(C),u.setBindGroup(0,q),u.draw(6),u.end()}else{O.colorAttachments[0].view=h.getCurrentTexture().createView();let f=a.beginRenderPass(O);f.setPipeline(N),f.setBindGroup(0,q),f.setBindGroup(1,er),f.draw(6),f.end()}p.queue.submit([a.finish()]),requestAnimationFrame(e)})},h=()=>(0,r.Tl)({name:"Deferred Rendering",description:"This example shows how to do deferred rendering with webgpu.\n Render geometry info to multiple targets in the gBuffers in the first pass.\n In this sample we have 2 gBuffers for normals and albedo, along with a depth texture.\n And then do the lighting in a second pass with per fragment data read from gBuffers so it's independent of scene complexity.\n World-space positions are reconstructed from the depth texture and camera matrix.\n We also update light position in a compute shader, where further operations like tile/cluster culling could happen.\n The debug view shows the depth buffer on the left (flipped and scaled a bit to make it more visible), the normal G buffer\n in the middle, and the albedo G-buffer on the right side of the screen.\n ",gui:!0,init:p,sources:[{name:c.substring(29),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { mat4, vec3, vec4 } from 'wgpu-matrix';\nimport { mesh } from '../../meshes/stanfordDragon';\n\nimport lightUpdate from './lightUpdate.wgsl';\nimport vertexWriteGBuffers from './vertexWriteGBuffers.wgsl';\nimport fragmentWriteGBuffers from './fragmentWriteGBuffers.wgsl';\nimport vertexTextureQuad from './vertexTextureQuad.wgsl';\nimport fragmentGBuffersDebugView from './fragmentGBuffersDebugView.wgsl';\nimport fragmentDeferredRendering from './fragmentDeferredRendering.wgsl';\n\nconst kMaxNumLights = 1024;\nconst lightExtentMin = vec3.fromValues(-50, -30, -50);\nconst lightExtentMax = vec3.fromValues(50, 50, 50);\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const aspect = canvas.width / canvas.height;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create the model vertex buffer.\n const kVertexStride = 8;\n const vertexBuffer = device.createBuffer({\n // position: vec3, normal: vec3, uv: vec2\n size:\n mesh.positions.length * kVertexStride * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], kVertexStride * i);\n mapping.set(mesh.normals[i], kVertexStride * i + 3);\n mapping.set(mesh.uvs[i], kVertexStride * i + 6);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer.\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // GBuffer texture render targets\n const gBufferTexture2DFloat16 = device.createTexture({\n size: [canvas.width, canvas.height],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'rgba16float',\n });\n const gBufferTextureAlbedo = device.createTexture({\n size: [canvas.width, canvas.height],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'bgra8unorm',\n });\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n\n const gBufferTextureViews = [\n gBufferTexture2DFloat16.createView(),\n gBufferTextureAlbedo.createView(),\n depthTexture.createView(),\n ];\n\n const vertexBuffers: Iterable = [\n {\n arrayStride: Float32Array.BYTES_PER_ELEMENT * 8,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: Float32Array.BYTES_PER_ELEMENT * 3,\n format: 'float32x3',\n },\n {\n // uv\n shaderLocation: 2,\n offset: Float32Array.BYTES_PER_ELEMENT * 6,\n format: 'float32x2',\n },\n ],\n },\n ];\n\n const primitive: GPUPrimitiveState = {\n topology: 'triangle-list',\n cullMode: 'back',\n };\n\n const writeGBuffersPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: vertexWriteGBuffers,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWriteGBuffers,\n }),\n entryPoint: 'main',\n targets: [\n // normal\n { format: 'rgba16float' },\n // albedo\n { format: 'bgra8unorm' },\n ],\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n primitive,\n });\n\n const gBufferTexturesBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'unfilterable-float',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'unfilterable-float',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n ],\n });\n\n const lightsBufferBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const gBuffersDebugViewPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [gBufferTexturesBindGroupLayout],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexTextureQuad,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentGBuffersDebugView,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n constants: {\n canvasSizeWidth: canvas.width,\n canvasSizeHeight: canvas.height,\n },\n },\n primitive,\n });\n\n const deferredRenderPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [\n gBufferTexturesBindGroupLayout,\n lightsBufferBindGroupLayout,\n ],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexTextureQuad,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentDeferredRendering,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive,\n });\n\n const writeGBufferPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: gBufferTextureViews[0],\n\n clearValue: { r: 0.0, g: 0.0, b: 1.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n {\n view: gBufferTextureViews[1],\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const textureQuadPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const settings = {\n mode: 'rendering',\n numLights: 128,\n };\n const configUniformBuffer = (() => {\n const buffer = device.createBuffer({\n size: Uint32Array.BYTES_PER_ELEMENT,\n mappedAtCreation: true,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n new Uint32Array(buffer.getMappedRange())[0] = settings.numLights;\n buffer.unmap();\n return buffer;\n })();\n\n gui.add(settings, 'mode', ['rendering', 'gBuffers view']);\n gui\n .add(settings, 'numLights', 1, kMaxNumLights)\n .step(1)\n .onChange(() => {\n device.queue.writeBuffer(\n configUniformBuffer,\n 0,\n new Uint32Array([settings.numLights])\n );\n });\n\n const modelUniformBuffer = device.createBuffer({\n size: 4 * 16 * 2, // two 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const cameraUniformBuffer = device.createBuffer({\n size: 4 * 16 * 2, // two 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneUniformBindGroup = device.createBindGroup({\n layout: writeGBuffersPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: modelUniformBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: cameraUniformBuffer,\n },\n },\n ],\n });\n\n const gBufferTexturesBindGroup = device.createBindGroup({\n layout: gBufferTexturesBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: gBufferTextureViews[0],\n },\n {\n binding: 1,\n resource: gBufferTextureViews[1],\n },\n {\n binding: 2,\n resource: gBufferTextureViews[2],\n },\n ],\n });\n\n // Lights data are uploaded in a storage buffer\n // which could be updated/culled/etc. with a compute shader\n const extent = vec3.sub(lightExtentMax, lightExtentMin);\n const lightDataStride = 8;\n const bufferSizeInByte =\n Float32Array.BYTES_PER_ELEMENT * lightDataStride * kMaxNumLights;\n const lightsBuffer = device.createBuffer({\n size: bufferSizeInByte,\n usage: GPUBufferUsage.STORAGE,\n mappedAtCreation: true,\n });\n\n // We randomaly populate lights randomly in a box range\n // And simply move them along y-axis per frame to show they are\n // dynamic lightings\n const lightData = new Float32Array(lightsBuffer.getMappedRange());\n const tmpVec4 = vec4.create();\n let offset = 0;\n for (let i = 0; i < kMaxNumLights; i++) {\n offset = lightDataStride * i;\n // position\n for (let i = 0; i < 3; i++) {\n tmpVec4[i] = Math.random() * extent[i] + lightExtentMin[i];\n }\n tmpVec4[3] = 1;\n lightData.set(tmpVec4, offset);\n // color\n tmpVec4[0] = Math.random() * 2;\n tmpVec4[1] = Math.random() * 2;\n tmpVec4[2] = Math.random() * 2;\n // radius\n tmpVec4[3] = 20.0;\n lightData.set(tmpVec4, offset + 4);\n }\n lightsBuffer.unmap();\n\n const lightExtentBuffer = device.createBuffer({\n size: 4 * 8,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const lightExtentData = new Float32Array(8);\n lightExtentData.set(lightExtentMin, 0);\n lightExtentData.set(lightExtentMax, 4);\n device.queue.writeBuffer(\n lightExtentBuffer,\n 0,\n lightExtentData.buffer,\n lightExtentData.byteOffset,\n lightExtentData.byteLength\n );\n\n const lightUpdateComputePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: lightUpdate,\n }),\n entryPoint: 'main',\n },\n });\n const lightsBufferBindGroup = device.createBindGroup({\n layout: lightsBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: lightsBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: configUniformBuffer,\n },\n },\n {\n binding: 2,\n resource: {\n buffer: cameraUniformBuffer,\n },\n },\n ],\n });\n const lightsBufferComputeBindGroup = device.createBindGroup({\n layout: lightUpdateComputePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: lightsBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: configUniformBuffer,\n },\n },\n {\n binding: 2,\n resource: {\n buffer: lightExtentBuffer,\n },\n },\n ],\n });\n //--------------------\n\n // Scene matrices\n const eyePosition = vec3.fromValues(0, 50, -100);\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const viewMatrix = mat4.inverse(mat4.lookAt(eyePosition, origin, upVector));\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n\n // Move the model so it's centered.\n const modelMatrix = mat4.translation([0, -45, 0]);\n\n const modelData = modelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 0,\n modelData.buffer,\n modelData.byteOffset,\n modelData.byteLength\n );\n const invertTransposeModelMatrix = mat4.invert(modelMatrix);\n mat4.transpose(invertTransposeModelMatrix, invertTransposeModelMatrix);\n const normalModelData = invertTransposeModelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 64,\n normalModelData.buffer,\n normalModelData.byteOffset,\n normalModelData.byteLength\n );\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const eyePosition = vec3.fromValues(0, 50, -100);\n\n const rad = Math.PI * (Date.now() / 5000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n const rotatedEyePosition = vec3.transformMat4(eyePosition, rotation);\n\n const viewMatrix = mat4.lookAt(rotatedEyePosition, origin, upVector);\n\n mat4.multiply(projectionMatrix, viewMatrix, viewProjMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const cameraViewProj = getCameraViewProjMatrix();\n device.queue.writeBuffer(\n cameraUniformBuffer,\n 0,\n cameraViewProj.buffer,\n cameraViewProj.byteOffset,\n cameraViewProj.byteLength\n );\n const cameraInvViewProj = mat4.invert(cameraViewProj) as Float32Array;\n device.queue.writeBuffer(\n cameraUniformBuffer,\n 64,\n cameraInvViewProj.buffer,\n cameraInvViewProj.byteOffset,\n cameraInvViewProj.byteLength\n );\n\n const commandEncoder = device.createCommandEncoder();\n {\n // Write position, normal, albedo etc. data to gBuffers\n const gBufferPass = commandEncoder.beginRenderPass(\n writeGBufferPassDescriptor\n );\n gBufferPass.setPipeline(writeGBuffersPipeline);\n gBufferPass.setBindGroup(0, sceneUniformBindGroup);\n gBufferPass.setVertexBuffer(0, vertexBuffer);\n gBufferPass.setIndexBuffer(indexBuffer, 'uint16');\n gBufferPass.drawIndexed(indexCount);\n gBufferPass.end();\n }\n {\n // Update lights position\n const lightPass = commandEncoder.beginComputePass();\n lightPass.setPipeline(lightUpdateComputePipeline);\n lightPass.setBindGroup(0, lightsBufferComputeBindGroup);\n lightPass.dispatchWorkgroups(Math.ceil(kMaxNumLights / 64));\n lightPass.end();\n }\n {\n if (settings.mode === 'gBuffers view') {\n // GBuffers debug view\n // Left: depth\n // Middle: normal\n // Right: albedo (use uv to mimic a checkerboard texture)\n textureQuadPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n const debugViewPass = commandEncoder.beginRenderPass(\n textureQuadPassDescriptor\n );\n debugViewPass.setPipeline(gBuffersDebugViewPipeline);\n debugViewPass.setBindGroup(0, gBufferTexturesBindGroup);\n debugViewPass.draw(6);\n debugViewPass.end();\n } else {\n // Deferred rendering\n textureQuadPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n const deferredRenderingPass = commandEncoder.beginRenderPass(\n textureQuadPassDescriptor\n );\n deferredRenderingPass.setPipeline(deferredRenderPipeline);\n deferredRenderingPass.setBindGroup(0, gBufferTexturesBindGroup);\n deferredRenderingPass.setBindGroup(1, lightsBufferBindGroup);\n deferredRenderingPass.draw(6);\n deferredRenderingPass.end();\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst DeferredRendering: () => JSX.Element = () =>\n makeSample({\n name: 'Deferred Rendering',\n description: `This example shows how to do deferred rendering with webgpu.\n Render geometry info to multiple targets in the gBuffers in the first pass.\n In this sample we have 2 gBuffers for normals and albedo, along with a depth texture.\n And then do the lighting in a second pass with per fragment data read from gBuffers so it's independent of scene complexity.\n World-space positions are reconstructed from the depth texture and camera matrix.\n We also update light position in a compute shader, where further operations like tile/cluster culling could happen.\n The debug view shows the depth buffer on the left (flipped and scaled a bit to make it more visible), the normal G buffer\n in the middle, and the albedo G-buffer on the right side of the screen.\n `,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: 'vertexWriteGBuffers.wgsl',\n contents: vertexWriteGBuffers,\n editable: true,\n },\n {\n name: 'fragmentWriteGBuffers.wgsl',\n contents: fragmentWriteGBuffers,\n editable: true,\n },\n {\n name: 'vertexTextureQuad.wgsl',\n contents: vertexTextureQuad,\n editable: true,\n },\n {\n name: 'fragmentGBuffersDebugView.wgsl',\n contents: fragmentGBuffersDebugView,\n editable: true,\n },\n {\n name: 'fragmentDeferredRendering.wgsl',\n contents: fragmentDeferredRendering,\n editable: true,\n },\n {\n name: 'lightUpdate.wgsl',\n contents: lightUpdate,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default DeferredRendering;\n"},{name:"vertexWriteGBuffers.wgsl",contents:s,editable:!0},{name:"fragmentWriteGBuffers.wgsl",contents:u,editable:!0},{name:"vertexTextureQuad.wgsl",contents:f,editable:!0},{name:"fragmentGBuffersDebugView.wgsl",contents:l,editable:!0},{name:"fragmentDeferredRendering.wgsl",contents:d,editable:!0},{name:"lightUpdate.wgsl",contents:o,editable:!0}],filename:c});var v=h},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/704.cd24c3a6bb1f49fc.js b/_next/static/chunks/704.cd24c3a6bb1f49fc.js new file mode 100644 index 00000000..ecd32e0b --- /dev/null +++ b/_next/static/chunks/704.cd24c3a6bb1f49fc.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[704],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return c}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),f=t.n(u);t(7319);let l=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),g=(0,o.useRouter)(),m=g.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[p,h]=(0,s.useState)(null),[v,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(m?x(m[1]):x(i[0].name),l&&u.current)for(u.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();c&&d.current&&(c.dom.style.position="absolute",c.showPanel(1),d.current.appendChild(c.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:l,stats:c});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),p?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(p)})]}):null]}),(0,r.jsxs)("div",{className:f().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:f().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){x(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:f().sourceFileContainer,"data-active":v==e.name},n))]})]})},d=e=>(0,r.jsx)(l,{...e});function c(e,n){if(!e)throw Error(n)}},6888:function(e,n,t){"use strict";t.d(n,{W:function(){return a}});var r=t(6906),i=t(9385);let a={positions:r.m,triangles:r.g,normals:[],uvs:[]};a.normals=(0,i.b)(a.positions,a.triangles),a.uvs=(0,i.q)(a.positions,"xy"),a.triangles.push([a.positions.length,a.positions.length+2,a.positions.length+1],[a.positions.length,a.positions.length+1,a.positions.length+3]),a.positions.push([-100,20,-100],[100,20,100],[-100,20,100],[100,20,-100]),a.normals.push([0,1,0],[0,1,0],[0,1,0],[0,1,0]),a.uvs.push([0,0],[1,1],[0,1],[1,0])},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return i},q:function(){return o}});var r=t(6416);function i(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[i,a,o]=n,s=e[i],u=e[a],f=e[o],l=r.R3.subtract(u,s),d=r.R3.subtract(f,s);r.R3.normalize(l,l),r.R3.normalize(d,d);let c=r.R3.cross(l,d);r.R3.add(t[i],c,t[i]),r.R3.add(t[a],c,t[a]),r.R3.add(t[o],c,t[o])}),t.forEach(e=>{r.R3.normalize(e,e)}),t}let a={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=a[n],r=e.map(()=>[0,0]),i=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{r[n][0]=e[t[0]],r[n][1]=e[t[1]],i[0]=Math.min(e[t[0]],i[0]),i[1]=Math.min(e[t[1]],i[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),r.forEach(e=>{e[0]=(e[0]-i[0])/(o[0]-i[0]),e[1]=(e[1]-i[1])/(o[1]-i[1])}),r}},9704:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return v}});var r=t(5671),i=t(6416),a=t(6888),o="struct LightData {\n position : vec4,\n color : vec3,\n radius : f32,\n}\nstruct LightsBuffer {\n lights: array,\n}\n@group(0) @binding(0) var lightsBuffer: LightsBuffer;\n\nstruct Config {\n numLights : u32,\n}\n@group(0) @binding(1) var config: Config;\n\nstruct LightExtent {\n min : vec4,\n max : vec4,\n}\n@group(0) @binding(2) var lightExtent: LightExtent;\n\n@compute @workgroup_size(64, 1, 1)\nfn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) {\n var index = GlobalInvocationID.x;\n if (index >= config.numLights) {\n return;\n }\n\n lightsBuffer.lights[index].position.y = lightsBuffer.lights[index].position.y - 0.5 - 0.003 * (f32(index) - 64.0 * floor(f32(index) / 64.0));\n\n if (lightsBuffer.lights[index].position.y < lightExtent.min.y) {\n lightsBuffer.lights[index].position.y = lightExtent.max.y;\n }\n}\n",s="struct Uniforms {\n modelMatrix : mat4x4,\n normalModelMatrix : mat4x4,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n invViewProjectionMatrix : mat4x4,\n}\n@group(0) @binding(0) var uniforms : Uniforms;\n@group(0) @binding(1) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragNormal: vec3, // normal in world space\n @location(1) fragUV: vec2,\n}\n\n@vertex\nfn main(\n @location(0) position : vec3,\n @location(1) normal : vec3,\n @location(2) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n let worldPosition = (uniforms.modelMatrix * vec4(position, 1.0)).xyz;\n output.Position = camera.viewProjectionMatrix * vec4(worldPosition, 1.0);\n output.fragNormal = normalize((uniforms.normalModelMatrix * vec4(normal, 1.0)).xyz);\n output.fragUV = uv;\n return output;\n}\n",u="struct GBufferOutput {\n @location(0) normal : vec4,\n\n // Textures: diffuse color, specular color, smoothness, emissive etc. could go here\n @location(1) albedo : vec4,\n}\n\n@fragment\nfn main(\n @location(0) fragNormal: vec3,\n @location(1) fragUV : vec2\n) -> GBufferOutput {\n // faking some kind of checkerboard texture\n let uv = floor(30.0 * fragUV);\n let c = 0.2 + 0.5 * ((uv.x + uv.y) - 2.0 * floor((uv.x + uv.y) / 2.0));\n\n var output : GBufferOutput;\n output.normal = vec4(fragNormal, 1.0);\n output.albedo = vec4(c, c, c, 1.0);\n\n return output;\n}\n",f="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n const pos = array(\n vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0),\n vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0),\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n",l="\n@group(0) @binding(0) var gBufferNormal: texture_2d;\n@group(0) @binding(1) var gBufferAlbedo: texture_2d;\n@group(0) @binding(2) var gBufferDepth: texture_depth_2d;\n\noverride canvasSizeWidth: f32;\noverride canvasSizeHeight: f32;\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n var result : vec4;\n let c = coord.xy / vec2(canvasSizeWidth, canvasSizeHeight);\n if (c.x < 0.33333) {\n let rawDepth = textureLoad(\n gBufferDepth,\n vec2(floor(coord.xy)),\n 0\n );\n // remap depth into something a bit more visible\n let depth = (1.0 - rawDepth) * 50.0;\n result = vec4(depth);\n } else if (c.x < 0.66667) {\n result = textureLoad(\n gBufferNormal,\n vec2(floor(coord.xy)),\n 0\n );\n result.x = (result.x + 1.0) * 0.5;\n result.y = (result.y + 1.0) * 0.5;\n result.z = (result.z + 1.0) * 0.5;\n } else {\n result = textureLoad(\n gBufferAlbedo,\n vec2(floor(coord.xy)),\n 0\n );\n }\n return result;\n}\n",d="\n@group(0) @binding(0) var gBufferNormal: texture_2d;\n@group(0) @binding(1) var gBufferAlbedo: texture_2d;\n@group(0) @binding(2) var gBufferDepth: texture_depth_2d;\n\nstruct LightData {\n position : vec4,\n color : vec3,\n radius : f32,\n}\nstruct LightsBuffer {\n lights: array,\n}\n@group(1) @binding(0) var lightsBuffer: LightsBuffer;\n\nstruct Config {\n numLights : u32,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n invViewProjectionMatrix : mat4x4,\n}\n@group(1) @binding(1) var config: Config;\n@group(1) @binding(2) var camera: Camera;\n\nfn world_from_screen_coord(coord : vec2, depth_sample: f32) -> vec3 {\n // reconstruct world-space position from the screen coordinate.\n let posClip = vec4(coord.x * 2.0 - 1.0, (1.0 - coord.y) * 2.0 - 1.0, depth_sample, 1.0);\n let posWorldW = camera.invViewProjectionMatrix * posClip;\n let posWorld = posWorldW.xyz / posWorldW.www;\n return posWorld;\n}\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n var result : vec3;\n\n let depth = textureLoad(\n gBufferDepth,\n vec2(floor(coord.xy)),\n 0\n );\n\n // Don't light the sky.\n if (depth >= 1.0) {\n discard;\n }\n\n let bufferSize = textureDimensions(gBufferDepth);\n let coordUV = coord.xy / vec2(bufferSize);\n let position = world_from_screen_coord(coordUV, depth);\n\n let normal = textureLoad(\n gBufferNormal,\n vec2(floor(coord.xy)),\n 0\n ).xyz;\n\n let albedo = textureLoad(\n gBufferAlbedo,\n vec2(floor(coord.xy)),\n 0\n ).rgb;\n\n for (var i = 0u; i < config.numLights; i++) {\n let L = lightsBuffer.lights[i].position.xyz - position;\n let distance = length(L);\n if (distance > lightsBuffer.lights[i].radius) {\n continue;\n }\n let lambert = max(dot(normal, normalize(L)), 0.0);\n result += vec3(\n lambert * pow(1.0 - distance / lightsBuffer.lights[i].radius, 2.0) * lightsBuffer.lights[i].color * albedo\n );\n }\n\n // some manual ambient\n result += vec3(0.2);\n\n return vec4(result, 1.0);\n}\n",c="src/sample/deferredRendering/main.ts";let g=i.R3.fromValues(-50,-30,-50),m=i.R3.fromValues(50,50,50),p=async e=>{let{canvas:n,pageState:t,gui:r}=e,c=await navigator.gpu.requestAdapter(),p=await c.requestDevice();if(!t.active)return;let h=n.getContext("webgpu"),v=window.devicePixelRatio;n.width=n.clientWidth*v,n.height=n.clientHeight*v;let x=n.width/n.height,b=navigator.gpu.getPreferredCanvasFormat();h.configure({device:p,format:b,alphaMode:"premultiplied"});let B=p.createBuffer({size:8*a.W.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});{let P=new Float32Array(B.getMappedRange());for(let y=0;y{let e=p.createBuffer({size:Uint32Array.BYTES_PER_ELEMENT,mappedAtCreation:!0,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});return new Uint32Array(e.getMappedRange())[0]=j.numLights,e.unmap(),e})();r.add(j,"mode",["rendering","gBuffers view"]),r.add(j,"numLights",1,1024).step(1).onChange(()=>{p.queue.writeBuffer(z,0,new Uint32Array([j.numLights]))});let I=p.createBuffer({size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),W=p.createBuffer({size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),k=p.createBindGroup({layout:V.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:I}},{binding:1,resource:{buffer:W}}]}),q=p.createBindGroup({layout:A,entries:[{binding:0,resource:S[0]},{binding:1,resource:S[1]},{binding:2,resource:S[2]}]}),Y=i.R3.sub(m,g),H=8192*Float32Array.BYTES_PER_ELEMENT,Q=p.createBuffer({size:H,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),X=new Float32Array(Q.getMappedRange()),J=i.vh.create(),Z=0;for(let K=0;K<1024;K++){Z=8*K;for(let $=0;$<3;$++)J[$]=Math.random()*Y[$]+g[$];J[3]=1,X.set(J,Z),J[0]=2*Math.random(),J[1]=2*Math.random(),J[2]=2*Math.random(),J[3]=20,X.set(J,Z+4)}Q.unmap();let ee=p.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),en=new Float32Array(8);en.set(g,0),en.set(m,4),p.queue.writeBuffer(ee,0,en.buffer,en.byteOffset,en.byteLength);let et=p.createComputePipeline({layout:"auto",compute:{module:p.createShaderModule({code:o}),entryPoint:"main"}}),er=p.createBindGroup({layout:D,entries:[{binding:0,resource:{buffer:Q}},{binding:1,resource:{buffer:z}},{binding:2,resource:{buffer:W}}]}),ei=p.createBindGroup({layout:et.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:Q}},{binding:1,resource:{buffer:z}},{binding:2,resource:{buffer:ee}}]}),ea=i.R3.fromValues(0,50,-100),eo=i.R3.fromValues(0,1,0),es=i.R3.fromValues(0,0,0),eu=i._E.perspective(2*Math.PI/5,x,1,2e3),ef=i._E.inverse(i._E.lookAt(ea,es,eo)),el=i._E.multiply(eu,ef),ed=i._E.translation([0,-45,0]);p.queue.writeBuffer(I,0,ed.buffer,ed.byteOffset,ed.byteLength);let ec=i._E.invert(ed);i._E.transpose(ec,ec),p.queue.writeBuffer(I,64,ec.buffer,ec.byteOffset,ec.byteLength),requestAnimationFrame(function e(){if(!t.active)return;let n=function(){let e=i.R3.fromValues(0,50,-100),n=Math.PI*(Date.now()/5e3),t=i._E.rotateY(i._E.translation(es),n);i.R3.transformMat4(e,t,e);let r=i.R3.transformMat4(e,t),a=i._E.lookAt(r,es,eo);return i._E.multiply(eu,a,el),el}();p.queue.writeBuffer(W,0,n.buffer,n.byteOffset,n.byteLength);let r=i._E.invert(n);p.queue.writeBuffer(W,64,r.buffer,r.byteOffset,r.byteLength);let a=p.createCommandEncoder();{let o=a.beginRenderPass(F);o.setPipeline(V),o.setBindGroup(0,k),o.setVertexBuffer(0,B),o.setIndexBuffer(E,"uint16"),o.drawIndexed(w),o.end()}{let s=a.beginComputePass();s.setPipeline(et),s.setBindGroup(0,ei),s.dispatchWorkgroups(Math.ceil(16)),s.end()}if("gBuffers view"===j.mode){O.colorAttachments[0].view=h.getCurrentTexture().createView();let u=a.beginRenderPass(O);u.setPipeline(C),u.setBindGroup(0,q),u.draw(6),u.end()}else{O.colorAttachments[0].view=h.getCurrentTexture().createView();let f=a.beginRenderPass(O);f.setPipeline(N),f.setBindGroup(0,q),f.setBindGroup(1,er),f.draw(6),f.end()}p.queue.submit([a.finish()]),requestAnimationFrame(e)})},h=()=>(0,r.Tl)({name:"Deferred Rendering",description:"This example shows how to do deferred rendering with webgpu.\n Render geometry info to multiple targets in the gBuffers in the first pass.\n In this sample we have 2 gBuffers for normals and albedo, along with a depth texture.\n And then do the lighting in a second pass with per fragment data read from gBuffers so it's independent of scene complexity.\n World-space positions are reconstructed from the depth texture and camera matrix.\n We also update light position in a compute shader, where further operations like tile/cluster culling could happen.\n The debug view shows the depth buffer on the left (flipped and scaled a bit to make it more visible), the normal G buffer\n in the middle, and the albedo G-buffer on the right side of the screen.\n ",gui:!0,init:p,sources:[{name:c.substring(29),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { mat4, vec3, vec4 } from 'wgpu-matrix';\nimport { mesh } from '../../meshes/stanfordDragon';\n\nimport lightUpdate from './lightUpdate.wgsl';\nimport vertexWriteGBuffers from './vertexWriteGBuffers.wgsl';\nimport fragmentWriteGBuffers from './fragmentWriteGBuffers.wgsl';\nimport vertexTextureQuad from './vertexTextureQuad.wgsl';\nimport fragmentGBuffersDebugView from './fragmentGBuffersDebugView.wgsl';\nimport fragmentDeferredRendering from './fragmentDeferredRendering.wgsl';\n\nconst kMaxNumLights = 1024;\nconst lightExtentMin = vec3.fromValues(-50, -30, -50);\nconst lightExtentMax = vec3.fromValues(50, 50, 50);\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const aspect = canvas.width / canvas.height;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create the model vertex buffer.\n const kVertexStride = 8;\n const vertexBuffer = device.createBuffer({\n // position: vec3, normal: vec3, uv: vec2\n size:\n mesh.positions.length * kVertexStride * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], kVertexStride * i);\n mapping.set(mesh.normals[i], kVertexStride * i + 3);\n mapping.set(mesh.uvs[i], kVertexStride * i + 6);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer.\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // GBuffer texture render targets\n const gBufferTexture2DFloat16 = device.createTexture({\n size: [canvas.width, canvas.height],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'rgba16float',\n });\n const gBufferTextureAlbedo = device.createTexture({\n size: [canvas.width, canvas.height],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'bgra8unorm',\n });\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n\n const gBufferTextureViews = [\n gBufferTexture2DFloat16.createView(),\n gBufferTextureAlbedo.createView(),\n depthTexture.createView(),\n ];\n\n const vertexBuffers: Iterable = [\n {\n arrayStride: Float32Array.BYTES_PER_ELEMENT * 8,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: Float32Array.BYTES_PER_ELEMENT * 3,\n format: 'float32x3',\n },\n {\n // uv\n shaderLocation: 2,\n offset: Float32Array.BYTES_PER_ELEMENT * 6,\n format: 'float32x2',\n },\n ],\n },\n ];\n\n const primitive: GPUPrimitiveState = {\n topology: 'triangle-list',\n cullMode: 'back',\n };\n\n const writeGBuffersPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: vertexWriteGBuffers,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWriteGBuffers,\n }),\n entryPoint: 'main',\n targets: [\n // normal\n { format: 'rgba16float' },\n // albedo\n { format: 'bgra8unorm' },\n ],\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n primitive,\n });\n\n const gBufferTexturesBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'unfilterable-float',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'unfilterable-float',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n ],\n });\n\n const lightsBufferBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const gBuffersDebugViewPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [gBufferTexturesBindGroupLayout],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexTextureQuad,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentGBuffersDebugView,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n constants: {\n canvasSizeWidth: canvas.width,\n canvasSizeHeight: canvas.height,\n },\n },\n primitive,\n });\n\n const deferredRenderPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [\n gBufferTexturesBindGroupLayout,\n lightsBufferBindGroupLayout,\n ],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexTextureQuad,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentDeferredRendering,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive,\n });\n\n const writeGBufferPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: gBufferTextureViews[0],\n\n clearValue: { r: 0.0, g: 0.0, b: 1.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n {\n view: gBufferTextureViews[1],\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const textureQuadPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const settings = {\n mode: 'rendering',\n numLights: 128,\n };\n const configUniformBuffer = (() => {\n const buffer = device.createBuffer({\n size: Uint32Array.BYTES_PER_ELEMENT,\n mappedAtCreation: true,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n new Uint32Array(buffer.getMappedRange())[0] = settings.numLights;\n buffer.unmap();\n return buffer;\n })();\n\n gui.add(settings, 'mode', ['rendering', 'gBuffers view']);\n gui\n .add(settings, 'numLights', 1, kMaxNumLights)\n .step(1)\n .onChange(() => {\n device.queue.writeBuffer(\n configUniformBuffer,\n 0,\n new Uint32Array([settings.numLights])\n );\n });\n\n const modelUniformBuffer = device.createBuffer({\n size: 4 * 16 * 2, // two 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const cameraUniformBuffer = device.createBuffer({\n size: 4 * 16 * 2, // two 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneUniformBindGroup = device.createBindGroup({\n layout: writeGBuffersPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: modelUniformBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: cameraUniformBuffer,\n },\n },\n ],\n });\n\n const gBufferTexturesBindGroup = device.createBindGroup({\n layout: gBufferTexturesBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: gBufferTextureViews[0],\n },\n {\n binding: 1,\n resource: gBufferTextureViews[1],\n },\n {\n binding: 2,\n resource: gBufferTextureViews[2],\n },\n ],\n });\n\n // Lights data are uploaded in a storage buffer\n // which could be updated/culled/etc. with a compute shader\n const extent = vec3.sub(lightExtentMax, lightExtentMin);\n const lightDataStride = 8;\n const bufferSizeInByte =\n Float32Array.BYTES_PER_ELEMENT * lightDataStride * kMaxNumLights;\n const lightsBuffer = device.createBuffer({\n size: bufferSizeInByte,\n usage: GPUBufferUsage.STORAGE,\n mappedAtCreation: true,\n });\n\n // We randomaly populate lights randomly in a box range\n // And simply move them along y-axis per frame to show they are\n // dynamic lightings\n const lightData = new Float32Array(lightsBuffer.getMappedRange());\n const tmpVec4 = vec4.create();\n let offset = 0;\n for (let i = 0; i < kMaxNumLights; i++) {\n offset = lightDataStride * i;\n // position\n for (let i = 0; i < 3; i++) {\n tmpVec4[i] = Math.random() * extent[i] + lightExtentMin[i];\n }\n tmpVec4[3] = 1;\n lightData.set(tmpVec4, offset);\n // color\n tmpVec4[0] = Math.random() * 2;\n tmpVec4[1] = Math.random() * 2;\n tmpVec4[2] = Math.random() * 2;\n // radius\n tmpVec4[3] = 20.0;\n lightData.set(tmpVec4, offset + 4);\n }\n lightsBuffer.unmap();\n\n const lightExtentBuffer = device.createBuffer({\n size: 4 * 8,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const lightExtentData = new Float32Array(8);\n lightExtentData.set(lightExtentMin, 0);\n lightExtentData.set(lightExtentMax, 4);\n device.queue.writeBuffer(\n lightExtentBuffer,\n 0,\n lightExtentData.buffer,\n lightExtentData.byteOffset,\n lightExtentData.byteLength\n );\n\n const lightUpdateComputePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: lightUpdate,\n }),\n entryPoint: 'main',\n },\n });\n const lightsBufferBindGroup = device.createBindGroup({\n layout: lightsBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: lightsBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: configUniformBuffer,\n },\n },\n {\n binding: 2,\n resource: {\n buffer: cameraUniformBuffer,\n },\n },\n ],\n });\n const lightsBufferComputeBindGroup = device.createBindGroup({\n layout: lightUpdateComputePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: lightsBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: configUniformBuffer,\n },\n },\n {\n binding: 2,\n resource: {\n buffer: lightExtentBuffer,\n },\n },\n ],\n });\n //--------------------\n\n // Scene matrices\n const eyePosition = vec3.fromValues(0, 50, -100);\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const viewMatrix = mat4.inverse(mat4.lookAt(eyePosition, origin, upVector));\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n\n // Move the model so it's centered.\n const modelMatrix = mat4.translation([0, -45, 0]);\n\n const modelData = modelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 0,\n modelData.buffer,\n modelData.byteOffset,\n modelData.byteLength\n );\n const invertTransposeModelMatrix = mat4.invert(modelMatrix);\n mat4.transpose(invertTransposeModelMatrix, invertTransposeModelMatrix);\n const normalModelData = invertTransposeModelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 64,\n normalModelData.buffer,\n normalModelData.byteOffset,\n normalModelData.byteLength\n );\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const eyePosition = vec3.fromValues(0, 50, -100);\n\n const rad = Math.PI * (Date.now() / 5000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n const rotatedEyePosition = vec3.transformMat4(eyePosition, rotation);\n\n const viewMatrix = mat4.lookAt(rotatedEyePosition, origin, upVector);\n\n mat4.multiply(projectionMatrix, viewMatrix, viewProjMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const cameraViewProj = getCameraViewProjMatrix();\n device.queue.writeBuffer(\n cameraUniformBuffer,\n 0,\n cameraViewProj.buffer,\n cameraViewProj.byteOffset,\n cameraViewProj.byteLength\n );\n const cameraInvViewProj = mat4.invert(cameraViewProj) as Float32Array;\n device.queue.writeBuffer(\n cameraUniformBuffer,\n 64,\n cameraInvViewProj.buffer,\n cameraInvViewProj.byteOffset,\n cameraInvViewProj.byteLength\n );\n\n const commandEncoder = device.createCommandEncoder();\n {\n // Write position, normal, albedo etc. data to gBuffers\n const gBufferPass = commandEncoder.beginRenderPass(\n writeGBufferPassDescriptor\n );\n gBufferPass.setPipeline(writeGBuffersPipeline);\n gBufferPass.setBindGroup(0, sceneUniformBindGroup);\n gBufferPass.setVertexBuffer(0, vertexBuffer);\n gBufferPass.setIndexBuffer(indexBuffer, 'uint16');\n gBufferPass.drawIndexed(indexCount);\n gBufferPass.end();\n }\n {\n // Update lights position\n const lightPass = commandEncoder.beginComputePass();\n lightPass.setPipeline(lightUpdateComputePipeline);\n lightPass.setBindGroup(0, lightsBufferComputeBindGroup);\n lightPass.dispatchWorkgroups(Math.ceil(kMaxNumLights / 64));\n lightPass.end();\n }\n {\n if (settings.mode === 'gBuffers view') {\n // GBuffers debug view\n // Left: depth\n // Middle: normal\n // Right: albedo (use uv to mimic a checkerboard texture)\n textureQuadPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n const debugViewPass = commandEncoder.beginRenderPass(\n textureQuadPassDescriptor\n );\n debugViewPass.setPipeline(gBuffersDebugViewPipeline);\n debugViewPass.setBindGroup(0, gBufferTexturesBindGroup);\n debugViewPass.draw(6);\n debugViewPass.end();\n } else {\n // Deferred rendering\n textureQuadPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n const deferredRenderingPass = commandEncoder.beginRenderPass(\n textureQuadPassDescriptor\n );\n deferredRenderingPass.setPipeline(deferredRenderPipeline);\n deferredRenderingPass.setBindGroup(0, gBufferTexturesBindGroup);\n deferredRenderingPass.setBindGroup(1, lightsBufferBindGroup);\n deferredRenderingPass.draw(6);\n deferredRenderingPass.end();\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst DeferredRendering: () => JSX.Element = () =>\n makeSample({\n name: 'Deferred Rendering',\n description: `This example shows how to do deferred rendering with webgpu.\n Render geometry info to multiple targets in the gBuffers in the first pass.\n In this sample we have 2 gBuffers for normals and albedo, along with a depth texture.\n And then do the lighting in a second pass with per fragment data read from gBuffers so it's independent of scene complexity.\n World-space positions are reconstructed from the depth texture and camera matrix.\n We also update light position in a compute shader, where further operations like tile/cluster culling could happen.\n The debug view shows the depth buffer on the left (flipped and scaled a bit to make it more visible), the normal G buffer\n in the middle, and the albedo G-buffer on the right side of the screen.\n `,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: 'vertexWriteGBuffers.wgsl',\n contents: vertexWriteGBuffers,\n editable: true,\n },\n {\n name: 'fragmentWriteGBuffers.wgsl',\n contents: fragmentWriteGBuffers,\n editable: true,\n },\n {\n name: 'vertexTextureQuad.wgsl',\n contents: vertexTextureQuad,\n editable: true,\n },\n {\n name: 'fragmentGBuffersDebugView.wgsl',\n contents: fragmentGBuffersDebugView,\n editable: true,\n },\n {\n name: 'fragmentDeferredRendering.wgsl',\n contents: fragmentDeferredRendering,\n editable: true,\n },\n {\n name: 'lightUpdate.wgsl',\n contents: lightUpdate,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default DeferredRendering;\n"},{name:"vertexWriteGBuffers.wgsl",contents:s,editable:!0},{name:"fragmentWriteGBuffers.wgsl",contents:u,editable:!0},{name:"vertexTextureQuad.wgsl",contents:f,editable:!0},{name:"fragmentGBuffersDebugView.wgsl",contents:l,editable:!0},{name:"fragmentDeferredRendering.wgsl",contents:d,editable:!0},{name:"lightUpdate.wgsl",contents:o,editable:!0}],filename:c});var v=h},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/710.7a80af5a79364718.js b/_next/static/chunks/710.7a80af5a79364718.js deleted file mode 100644 index 96081183..00000000 --- a/_next/static/chunks/710.7a80af5a79364718.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[710],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,o.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,v]=(0,s.useState)(null),[g,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?x(p[1]):x(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();m&&f.current&&(m.dom.style.position="absolute",m.showPanel(1),f.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:l,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":g==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},5710:function(e,n,t){"use strict";var r="src/sample/twoCubes/main.ts";t.r(n);var a=t(6416),i=t(5671),o=t(4655),s=t(3569),c=t(1945);let u=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),i=await r.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio||1;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:i,format:f,alphaMode:"premultiplied"});let m=i.createBuffer({size:o.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(o.zS),m.unmap();let d=i.createRenderPipeline({layout:"auto",vertex:{module:i.createShaderModule({code:s.Z}),entryPoint:"main",buffers:[{arrayStride:o.O$,attributes:[{shaderLocation:0,offset:o.v8,format:"float32x4"},{shaderLocation:1,offset:o.Ax,format:"float32x2"}]}]},fragment:{module:i.createShaderModule({code:c.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=i.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=i.createBuffer({size:320,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=i.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h,offset:0,size:64}}]}),g=i.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h,offset:256,size:64}}]}),x={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},b=n.width/n.height,w=a._E.perspective(2*Math.PI/5,b,1,100),P=a._E.translation(a.R3.create(-2,0,0)),y=a._E.translation(a.R3.create(2,0,0)),M=a._E.create(),V=a._E.create(),C=a._E.translation(a.R3.fromValues(0,0,-7)),S=a._E.create(),E=a._E.create();requestAnimationFrame(function e(){if(!t.active)return;!function(){let e=Date.now()/1e3;a._E.rotate(P,a.R3.fromValues(Math.sin(e),Math.cos(e),0),1,S),a._E.rotate(y,a.R3.fromValues(Math.cos(e),Math.sin(e),0),1,E),a._E.multiply(C,S,M),a._E.multiply(w,M,M),a._E.multiply(C,E,V),a._E.multiply(w,V,V)}(),i.queue.writeBuffer(h,0,M.buffer,M.byteOffset,M.byteLength),i.queue.writeBuffer(h,256,V.buffer,V.byteOffset,V.byteLength),x.colorAttachments[0].view=u.getCurrentTexture().createView();let n=i.createCommandEncoder(),r=n.beginRenderPass(x);r.setPipeline(d),r.setVertexBuffer(0,m),r.setBindGroup(0,v),r.draw(o.MO),r.setBindGroup(0,g),r.draw(o.MO),r.end(),i.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,i.Tl)({name:"Two Cubes",description:"This example shows some of the alignment requirements involved when updating and binding multiple slices of a uniform buffer. It renders two rotating cubes which have transform matrices at different offsets in a uniform buffer.",init:u,sources:[{name:r.substring(20),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const matrixSize = 4 * 16; // 4x4 matrix\n const offset = 256; // uniformBindGroup offset must be 256-byte aligned\n const uniformBufferSize = offset + matrixSize;\n\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup1 = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: matrixSize,\n },\n },\n ],\n });\n\n const uniformBindGroup2 = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: offset,\n size: matrixSize,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n\n const modelMatrix1 = mat4.translation(vec3.create(-2, 0, 0));\n const modelMatrix2 = mat4.translation(vec3.create(2, 0, 0));\n const modelViewProjectionMatrix1 = mat4.create() as Float32Array;\n const modelViewProjectionMatrix2 = mat4.create() as Float32Array;\n const viewMatrix = mat4.translation(vec3.fromValues(0, 0, -7));\n\n const tmpMat41 = mat4.create();\n const tmpMat42 = mat4.create();\n\n function updateTransformationMatrix() {\n const now = Date.now() / 1000;\n\n mat4.rotate(\n modelMatrix1,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n tmpMat41\n );\n mat4.rotate(\n modelMatrix2,\n vec3.fromValues(Math.cos(now), Math.sin(now), 0),\n 1,\n tmpMat42\n );\n\n mat4.multiply(viewMatrix, tmpMat41, modelViewProjectionMatrix1);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix1,\n modelViewProjectionMatrix1\n );\n mat4.multiply(viewMatrix, tmpMat42, modelViewProjectionMatrix2);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix2,\n modelViewProjectionMatrix2\n );\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjectionMatrix1.buffer,\n modelViewProjectionMatrix1.byteOffset,\n modelViewProjectionMatrix1.byteLength\n );\n device.queue.writeBuffer(\n uniformBuffer,\n offset,\n modelViewProjectionMatrix2.buffer,\n modelViewProjectionMatrix2.byteOffset,\n modelViewProjectionMatrix2.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n\n // Bind the bind group (with the transformation matrix) for\n // each cube, and draw.\n passEncoder.setBindGroup(0, uniformBindGroup1);\n passEncoder.draw(cubeVertexCount);\n\n passEncoder.setBindGroup(0, uniformBindGroup2);\n passEncoder.draw(cubeVertexCount);\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst TwoCubes: () => JSX.Element = () =>\n makeSample({\n name: 'Two Cubes',\n description:\n 'This example shows some of the alignment requirements \\\n involved when updating and binding multiple slices of a \\\n uniform buffer. It renders two rotating cubes which have transform \\\n matrices at different offsets in a uniform buffer.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default TwoCubes;\n"},{name:"../../shaders/basic.vert.wgsl",contents:s.Z,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:c.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/710.82ef92be4b0e5415.js b/_next/static/chunks/710.82ef92be4b0e5415.js new file mode 100644 index 00000000..3f843b63 --- /dev/null +++ b/_next/static/chunks/710.82ef92be4b0e5415.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[710],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),d=(0,o.useRouter)(),p=d.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,v]=(0,s.useState)(null),[g,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?x(p[1]):x(a[0].name),l&&c.current)for(c.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();m&&f.current&&(m.dom.style.position="absolute",m.showPanel(1),f.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:l,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){x(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":g==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},5710:function(e,n,t){"use strict";var r="src/sample/twoCubes/main.ts";t.r(n);var a=t(6416),i=t(5671),o=t(4655),s=t(3569),c=t(1945);let u=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),i=await r.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:i,format:f,alphaMode:"premultiplied"});let m=i.createBuffer({size:o.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(o.zS),m.unmap();let d=i.createRenderPipeline({layout:"auto",vertex:{module:i.createShaderModule({code:s.Z}),entryPoint:"main",buffers:[{arrayStride:o.O$,attributes:[{shaderLocation:0,offset:o.v8,format:"float32x4"},{shaderLocation:1,offset:o.Ax,format:"float32x2"}]}]},fragment:{module:i.createShaderModule({code:c.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=i.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=i.createBuffer({size:320,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=i.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h,offset:0,size:64}}]}),g=i.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h,offset:256,size:64}}]}),x={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},b=n.width/n.height,w=a._E.perspective(2*Math.PI/5,b,1,100),P=a._E.translation(a.R3.create(-2,0,0)),y=a._E.translation(a.R3.create(2,0,0)),M=a._E.create(),V=a._E.create(),C=a._E.translation(a.R3.fromValues(0,0,-7)),S=a._E.create(),E=a._E.create();requestAnimationFrame(function e(){if(!t.active)return;!function(){let e=Date.now()/1e3;a._E.rotate(P,a.R3.fromValues(Math.sin(e),Math.cos(e),0),1,S),a._E.rotate(y,a.R3.fromValues(Math.cos(e),Math.sin(e),0),1,E),a._E.multiply(C,S,M),a._E.multiply(w,M,M),a._E.multiply(C,E,V),a._E.multiply(w,V,V)}(),i.queue.writeBuffer(h,0,M.buffer,M.byteOffset,M.byteLength),i.queue.writeBuffer(h,256,V.buffer,V.byteOffset,V.byteLength),x.colorAttachments[0].view=u.getCurrentTexture().createView();let n=i.createCommandEncoder(),r=n.beginRenderPass(x);r.setPipeline(d),r.setVertexBuffer(0,m),r.setBindGroup(0,v),r.draw(o.MO),r.setBindGroup(0,g),r.draw(o.MO),r.end(),i.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,i.Tl)({name:"Two Cubes",description:"This example shows some of the alignment requirements involved when updating and binding multiple slices of a uniform buffer. It renders two rotating cubes which have transform matrices at different offsets in a uniform buffer.",init:u,sources:[{name:r.substring(20),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const matrixSize = 4 * 16; // 4x4 matrix\n const offset = 256; // uniformBindGroup offset must be 256-byte aligned\n const uniformBufferSize = offset + matrixSize;\n\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup1 = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: matrixSize,\n },\n },\n ],\n });\n\n const uniformBindGroup2 = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: offset,\n size: matrixSize,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n\n const modelMatrix1 = mat4.translation(vec3.create(-2, 0, 0));\n const modelMatrix2 = mat4.translation(vec3.create(2, 0, 0));\n const modelViewProjectionMatrix1 = mat4.create() as Float32Array;\n const modelViewProjectionMatrix2 = mat4.create() as Float32Array;\n const viewMatrix = mat4.translation(vec3.fromValues(0, 0, -7));\n\n const tmpMat41 = mat4.create();\n const tmpMat42 = mat4.create();\n\n function updateTransformationMatrix() {\n const now = Date.now() / 1000;\n\n mat4.rotate(\n modelMatrix1,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n tmpMat41\n );\n mat4.rotate(\n modelMatrix2,\n vec3.fromValues(Math.cos(now), Math.sin(now), 0),\n 1,\n tmpMat42\n );\n\n mat4.multiply(viewMatrix, tmpMat41, modelViewProjectionMatrix1);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix1,\n modelViewProjectionMatrix1\n );\n mat4.multiply(viewMatrix, tmpMat42, modelViewProjectionMatrix2);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix2,\n modelViewProjectionMatrix2\n );\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjectionMatrix1.buffer,\n modelViewProjectionMatrix1.byteOffset,\n modelViewProjectionMatrix1.byteLength\n );\n device.queue.writeBuffer(\n uniformBuffer,\n offset,\n modelViewProjectionMatrix2.buffer,\n modelViewProjectionMatrix2.byteOffset,\n modelViewProjectionMatrix2.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n\n // Bind the bind group (with the transformation matrix) for\n // each cube, and draw.\n passEncoder.setBindGroup(0, uniformBindGroup1);\n passEncoder.draw(cubeVertexCount);\n\n passEncoder.setBindGroup(0, uniformBindGroup2);\n passEncoder.draw(cubeVertexCount);\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst TwoCubes: () => JSX.Element = () =>\n makeSample({\n name: 'Two Cubes',\n description:\n 'This example shows some of the alignment requirements \\\n involved when updating and binding multiple slices of a \\\n uniform buffer. It renders two rotating cubes which have transform \\\n matrices at different offsets in a uniform buffer.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default TwoCubes;\n"},{name:"../../shaders/basic.vert.wgsl",contents:s.Z,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:c.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/73.3a2232e411bea453.js b/_next/static/chunks/73.3a2232e411bea453.js new file mode 100644 index 00000000..26bafb0e --- /dev/null +++ b/_next/static/chunks/73.3a2232e411bea453.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[73],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var i=t(5893),r=t(9008),a=t.n(r),o=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),r=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let a=t(4631);n=a(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,i.jsx)("div",{...t,children:(0,i.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),l=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),p=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[b,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(r[0].name),c&&l.current)for(l.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();d&&f.current&&(d.dom.style.position="absolute",d.showPanel(1),f.current.appendChild(d.dom));let t={active:!0},i=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:c,stats:d});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return i},[]),(0,i.jsxs)("main",{children:[(0,i.jsxs)(a(),{children:[(0,i.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,i.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,i.jsx)("meta",{name:"description",content:e.description}),(0,i.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)("h1",{children:e.name}),(0,i.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,i.jsx)("p",{children:e.description}),g?(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,i.jsx)("p",{children:"".concat(g)})]}):null]}),(0,i.jsxs)("div",{className:u().canvasContainer,children:[(0,i.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,i.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,i.jsx)("canvas",{ref:n})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)("nav",{className:u().sourceFileNav,children:(0,i.jsx)("ul",{children:r.map((e,n)=>(0,i.jsx)("li",{children:(0,i.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){v(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,i.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":b==e.name},n))]})]})},f=e=>(0,i.jsx)(c,{...e});function d(e,n){if(!e)throw Error(n)}},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return r},q:function(){return o}});var i=t(6416);function r(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[r,a,o]=n,s=e[r],l=e[a],u=e[o],c=i.R3.subtract(l,s),f=i.R3.subtract(u,s);i.R3.normalize(c,c),i.R3.normalize(f,f);let d=i.R3.cross(c,f);i.R3.add(t[r],d,t[r]),i.R3.add(t[a],d,t[a]),i.R3.add(t[o],d,t[o])}),t.forEach(e=>{i.R3.normalize(e,e)}),t}let a={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=a[n],i=e.map(()=>[0,0]),r=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{i[n][0]=e[t[0]],i[n][1]=e[t[1]],r[0]=Math.min(e[t[0]],r[0]),r[1]=Math.min(e[t[1]],r[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),i.forEach(e=>{e[0]=(e[0]-r[0])/(o[0]-r[0]),e[1]=(e[1]-r[1])/(o[1]-r[1])}),i}},3073:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return p}});var i=t(6416),r=t(5671),a=t(8748),o=t(9385);let s={positions:a.m,triangles:a.g,normals:[]};s.normals=(0,o.b)(s.positions,s.triangles);var l="struct Uniforms {\n modelViewProjectionMatrix: mat4x4,\n};\n\n@binding(0) @group(0) var uniforms: Uniforms;\n\nstruct VertexOutput {\n @builtin(position) position: vec4,\n @location(0) @interpolate(flat) instance: u32\n};\n\n@vertex\nfn main_vs(@location(0) position: vec4, @builtin(instance_index) instance: u32) -> VertexOutput {\n var output: VertexOutput;\n\n // distribute instances into a staggered 4x4 grid\n const gridWidth = 125.0;\n const cellSize = gridWidth / 4.0;\n let row = instance / 2u;\n let col = instance % 2u;\n\n let xOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 * cellSize * f32(col) + f32(row % 2u != 0u) * cellSize;\n let zOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 + f32(row) * cellSize;\n\n let offsetPos = vec4(position.x + xOffset, position.y, position.z + zOffset, position.w);\n\n output.position = uniforms.modelViewProjectionMatrix * offsetPos;\n output.instance = instance;\n return output;\n}\n\n@fragment\nfn main_fs(@location(0) @interpolate(flat) instance: u32) -> @location(0) vec4 {\n const colors = array,6>(\n vec3(1.0, 0.0, 0.0),\n vec3(0.0, 1.0, 0.0),\n vec3(0.0, 0.0, 1.0),\n vec3(1.0, 0.0, 1.0),\n vec3(1.0, 1.0, 0.0),\n vec3(0.0, 1.0, 1.0),\n );\n\n return vec4(colors[instance % 6u], 1.0);\n}",u="struct Uniforms {\n modelViewProjectionMatrix: mat4x4,\n maxStorableFragments: u32,\n targetWidth: u32,\n};\n\nstruct SliceInfo {\n sliceStartY: i32\n};\n\nstruct Heads {\n numFragments: atomic,\n data: array>\n};\n\nstruct LinkedListElement {\n color: vec4,\n depth: f32,\n next: u32\n};\n\nstruct LinkedList {\n data: array\n};\n\n@binding(0) @group(0) var uniforms: Uniforms;\n@binding(1) @group(0) var heads: Heads;\n@binding(2) @group(0) var linkedList: LinkedList;\n@binding(3) @group(0) var opaqueDepthTexture: texture_depth_2d;\n@binding(4) @group(0) var sliceInfo: SliceInfo;\n\nstruct VertexOutput {\n @builtin(position) position: vec4,\n @location(0) @interpolate(flat) instance: u32\n};\n\n@vertex\nfn main_vs(@location(0) position: vec4, @builtin(instance_index) instance: u32) -> VertexOutput {\n var output: VertexOutput;\n\n // distribute instances into a staggered 4x4 grid\n const gridWidth = 125.0;\n const cellSize = gridWidth / 4.0;\n let row = instance / 2u;\n let col = instance % 2u;\n\n let xOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 * cellSize * f32(col) + f32(row % 2u == 0u) * cellSize;\n let zOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 + f32(row) * cellSize;\n\n let offsetPos = vec4(position.x + xOffset, position.y, position.z + zOffset, position.w);\n\n output.position = uniforms.modelViewProjectionMatrix * offsetPos;\n output.instance = instance;\n\n return output;\n}\n\n@fragment\nfn main_fs(@builtin(position) position: vec4, @location(0) @interpolate(flat) instance: u32) {\n const colors = array,6>(\n vec3(1.0, 0.0, 0.0),\n vec3(0.0, 1.0, 0.0),\n vec3(0.0, 0.0, 1.0),\n vec3(1.0, 0.0, 1.0),\n vec3(1.0, 1.0, 0.0),\n vec3(0.0, 1.0, 1.0),\n );\n\n let fragCoords = vec2(position.xy);\n let opaqueDepth = textureLoad(opaqueDepthTexture, fragCoords, 0);\n\n // reject fragments behind opaque objects\n if position.z >= opaqueDepth {\n discard;\n }\n\n // The index in the heads buffer corresponding to the head data for the fragment at\n // the current location.\n let headsIndex = u32(fragCoords.y - sliceInfo.sliceStartY) * uniforms.targetWidth + u32(fragCoords.x);\n\n // The index in the linkedList buffer at which to store the new fragment\n let fragIndex = atomicAdd(&heads.numFragments, 1u);\n\n // If we run out of space to store the fragments, we just lose them\n if fragIndex < uniforms.maxStorableFragments {\n let lastHead = atomicExchange(&heads.data[headsIndex], fragIndex);\n linkedList.data[fragIndex].depth = position.z;\n linkedList.data[fragIndex].next = lastHead;\n linkedList.data[fragIndex].color = vec4(colors[(instance + 3u) % 6u], 0.3);\n }\n}",c="struct Uniforms {\n modelViewProjectionMatrix: mat4x4,\n maxStorableFragments: u32,\n targetWidth: u32,\n};\n\nstruct SliceInfo {\n sliceStartY: i32\n};\n\nstruct Heads {\n numFragments: u32,\n data: array\n};\n\nstruct LinkedListElement {\n color: vec4,\n depth: f32,\n next: u32\n};\n\nstruct LinkedList {\n data: array\n};\n\n@binding(0) @group(0) var uniforms: Uniforms;\n@binding(1) @group(0) var heads: Heads;\n@binding(2) @group(0) var linkedList: LinkedList;\n@binding(3) @group(0) var sliceInfo: SliceInfo;\n\n// Output a full screen quad\n@vertex\nfn main_vs(@builtin(vertex_index) vertIndex: u32) -> @builtin(position) vec4 {\n const position = array, 6>(\n vec2(-1.0, -1.0),\n vec2(1.0, -1.0),\n vec2(1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(1.0, 1.0),\n vec2(-1.0, 1.0),\n );\n \n return vec4(position[vertIndex], 0.0, 1.0);\n}\n\n@fragment\nfn main_fs(@builtin(position) position: vec4) -> @location(0) vec4 {\n let fragCoords = vec2(position.xy);\n let headsIndex = u32(fragCoords.y - sliceInfo.sliceStartY) * uniforms.targetWidth + u32(fragCoords.x);\n\n // The maximum layers we can process for any pixel\n const maxLayers = 24u;\n\n var layers: array;\n\n var numLayers = 0u;\n var elementIndex = heads.data[headsIndex];\n\n // copy the list elements into an array up to the maximum amount of layers\n while elementIndex != 0xFFFFFFFFu && numLayers < maxLayers {\n layers[numLayers] = linkedList.data[elementIndex];\n numLayers++;\n elementIndex = linkedList.data[elementIndex].next;\n }\n\n if numLayers == 0u {\n discard;\n }\n \n // sort the fragments by depth\n for (var i = 1u; i < numLayers; i++) {\n let toInsert = layers[i];\n var j = i;\n\n while j > 0u && toInsert.depth > layers[j - 1u].depth {\n layers[j] = layers[j - 1u];\n j--;\n }\n\n layers[j] = toInsert;\n }\n\n // pre-multiply alpha for the first layer\n var color = vec4(layers[0].color.a * layers[0].color.rgb, layers[0].color.a);\n\n // blend the remaining layers\n for (var i = 1u; i < numLayers; i++) {\n let mixed = mix(color.rgb, layers[i].color.rgb, layers[i].color.aaa);\n color = vec4(mixed, color.a);\n }\n\n return color;\n}",f="src/sample/a-buffer/main.ts";let d=async e=>{let{canvas:n,pageState:t,gui:r}=e,a=await navigator.gpu.requestAdapter(),o=await a.requestDevice();if(!t.active)return;let f=n.getContext("webgpu"),d=navigator.gpu.getPreferredCanvasFormat();f.configure({device:o,format:d,alphaMode:"premultiplied"});let m=new URLSearchParams(window.location.search),p={memoryStrategy:m.get("memoryStrategy")||"multipass"},g=o.createBuffer({size:3*s.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0,label:"vertexBuffer"});{let h=new Float32Array(g.getMappedRange());for(let b=0;b{let e=window.devicePixelRatio;"clamp-pixel-ratio"===p.memoryStrategy&&(e=Math.min(window.devicePixelRatio,3)),n.width=n.clientWidth*e,n.height=n.clientHeight*e;let t=o.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,label:"depthTexture"}),r=t.createView({label:"depthTextureView"}),a=5*Float32Array.BYTES_PER_ELEMENT+1*Uint32Array.BYTES_PER_ELEMENT,l=4*n.width*a,u=Math.floor(o.limits.maxStorageBufferBindingSize/l),c=Math.ceil(n.height/u),d=Math.ceil(n.height/c),m=o.createBuffer({size:d*l,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"linkedListBuffer"}),h=o.createBuffer({size:c*o.limits.minUniformBufferOffsetAlignment,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0,label:"sliceInfoBuffer"});{let b=new Int32Array(h.getMappedRange()),v=o.limits.minUniformBufferOffsetAlignment/Int32Array.BYTES_PER_ELEMENT;for(let E=0;E{C=z()};r.add(p,"memoryStrategy",["multipass","clamp-pixel-ratio"]).onFinishChange(N),requestAnimationFrame(function e(){t.active&&(C(),requestAnimationFrame(e))})},m=()=>(0,r.Tl)({name:"A-Buffer",description:"Demonstrates order independent transparency using a per-pixel \n linked-list of translucent fragments. Provides a choice for \n limiting memory usage (when required).",gui:!0,init:d,sources:[{name:f.substring(20),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport { mesh } from '../../meshes/teapot';\n\nimport opaqueWGSL from './opaque.wgsl';\nimport translucentWGSL from './translucent.wgsl';\nimport compositeWGSL from './composite.wgsl';\n\nfunction roundUp(n: number, k: number): number {\n return Math.ceil(n / k) * k;\n}\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const params = new URLSearchParams(window.location.search);\n\n const settings = {\n memoryStrategy: params.get('memoryStrategy') || 'multipass',\n };\n\n // Create the model vertex buffer\n const vertexBuffer = device.createBuffer({\n size: 3 * mesh.positions.length * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n label: 'vertexBuffer',\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], 3 * i);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n label: 'indexBuffer',\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // Uniforms contains:\n // * modelViewProjectionMatrix: mat4x4\n // * maxStorableFragments: u32\n // * targetWidth: u32\n const uniformsSize = roundUp(\n 16 * Float32Array.BYTES_PER_ELEMENT + 2 * Uint32Array.BYTES_PER_ELEMENT,\n 16\n );\n\n const uniformBuffer = device.createBuffer({\n size: uniformsSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n label: 'uniformBuffer',\n });\n\n const opaqueModule = device.createShaderModule({\n code: opaqueWGSL,\n label: 'opaqueModule',\n });\n\n const opaquePipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: opaqueModule,\n entryPoint: 'main_vs',\n buffers: [\n {\n arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,\n attributes: [\n {\n // position\n format: 'float32x3',\n offset: 0,\n shaderLocation: 0,\n },\n ],\n },\n ],\n },\n fragment: {\n module: opaqueModule,\n entryPoint: 'main_fs',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n label: 'opaquePipeline',\n });\n\n const opaquePassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined,\n clearValue: { r: 0, g: 0, b: 0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: undefined,\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n label: 'opaquePassDescriptor',\n };\n\n const opaqueBindGroup = device.createBindGroup({\n layout: opaquePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n size: 16 * Float32Array.BYTES_PER_ELEMENT,\n label: 'modelViewProjection',\n },\n },\n ],\n label: 'opaquePipeline',\n });\n\n const translucentModule = device.createShaderModule({\n code: translucentWGSL,\n label: 'translucentModule',\n });\n\n const translucentBindGroupLayout = device.createBindGroupLayout({\n label: 'translucentBindGroupLayout',\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 3,\n visibility: GPUShaderStage.FRAGMENT,\n texture: { sampleType: 'depth' },\n },\n {\n binding: 4,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n hasDynamicOffset: true,\n },\n },\n ],\n });\n\n const translucentPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [translucentBindGroupLayout],\n label: 'translucentPipelineLayout',\n }),\n vertex: {\n module: translucentModule,\n entryPoint: 'main_vs',\n buffers: [\n {\n arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,\n attributes: [\n {\n format: 'float32x3',\n offset: 0,\n shaderLocation: 0,\n },\n ],\n },\n ],\n },\n fragment: {\n module: translucentModule,\n entryPoint: 'main_fs',\n targets: [\n {\n format: presentationFormat,\n writeMask: 0x0,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n label: 'translucentPipeline',\n });\n\n const translucentPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n loadOp: 'load',\n storeOp: 'store',\n view: undefined,\n },\n ],\n label: 'translucentPassDescriptor',\n };\n\n const compositeModule = device.createShaderModule({\n code: compositeWGSL,\n label: 'compositeModule',\n });\n\n const compositeBindGroupLayout = device.createBindGroupLayout({\n label: 'compositeBindGroupLayout',\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 3,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n hasDynamicOffset: true,\n },\n },\n ],\n });\n\n const compositePipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [compositeBindGroupLayout],\n label: 'compositePipelineLayout',\n }),\n vertex: {\n module: compositeModule,\n entryPoint: 'main_vs',\n },\n fragment: {\n module: compositeModule,\n entryPoint: 'main_fs',\n targets: [\n {\n format: presentationFormat,\n blend: {\n color: {\n srcFactor: 'one',\n operation: 'add',\n dstFactor: 'one-minus-src-alpha',\n },\n alpha: {},\n },\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n label: 'compositePipeline',\n });\n\n const compositePassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined,\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n label: 'compositePassDescriptor',\n };\n\n const configure = () => {\n let devicePixelRatio = window.devicePixelRatio;\n\n // The default maximum storage buffer binding size is 128Mib. The amount\n // of memory we need to store transparent fragments depends on the size\n // of the canvas and the average number of layers per fragment we want to\n // support. When the devicePixelRatio is 1, we know that 128Mib is enough\n // to store 4 layers per pixel at 600x600. However, when the device pixel\n // ratio is high enough we will exceed this limit.\n //\n // We provide 2 choices of mitigations to this issue:\n // 1) Clamp the device pixel ratio to a value which we know will not break\n // the limit. The tradeoff here is that the canvas resolution will not\n // match the native resolution and therefore may have a reduction in\n // quality.\n // 2) Break the frame into a series of horizontal slices using the scissor\n // functionality and process a single slice at a time. This limits memory\n // usage because we only need enough memory to process the dimensions\n // of the slice. The tradeoff is the performance reduction due to multiple\n // passes.\n if (settings.memoryStrategy === 'clamp-pixel-ratio') {\n devicePixelRatio = Math.min(window.devicePixelRatio, 3);\n }\n\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage:\n GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n label: 'depthTexture',\n });\n\n const depthTextureView = depthTexture.createView({\n label: 'depthTextureView',\n });\n\n // Determines how much memory is allocated to store linked-list elements\n const averageLayersPerFragment = 4;\n\n // Each element stores\n // * color : vec4\n // * depth : f32\n // * index of next element in the list : u32\n const linkedListElementSize =\n 5 * Float32Array.BYTES_PER_ELEMENT + 1 * Uint32Array.BYTES_PER_ELEMENT;\n\n // We want to keep the linked-list buffer size under the maxStorageBufferBindingSize.\n // Split the frame into enough slices to meet that constraint.\n const bytesPerline =\n canvas.width * averageLayersPerFragment * linkedListElementSize;\n const maxLinesSupported = Math.floor(\n device.limits.maxStorageBufferBindingSize / bytesPerline\n );\n const numSlices = Math.ceil(canvas.height / maxLinesSupported);\n const sliceHeight = Math.ceil(canvas.height / numSlices);\n const linkedListBufferSize = sliceHeight * bytesPerline;\n\n const linkedListBuffer = device.createBuffer({\n size: linkedListBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n label: 'linkedListBuffer',\n });\n\n // To slice up the frame we need to pass the starting fragment y position of the slice.\n // We do this using a uniform buffer with a dynamic offset.\n const sliceInfoBuffer = device.createBuffer({\n size: numSlices * device.limits.minUniformBufferOffsetAlignment,\n usage: GPUBufferUsage.UNIFORM,\n mappedAtCreation: true,\n label: 'sliceInfoBuffer',\n });\n {\n const mapping = new Int32Array(sliceInfoBuffer.getMappedRange());\n\n // This assumes minUniformBufferOffsetAlignment is a multiple of 4\n const stride =\n device.limits.minUniformBufferOffsetAlignment /\n Int32Array.BYTES_PER_ELEMENT;\n for (let i = 0; i < numSlices; ++i) {\n mapping[i * stride] = i * sliceHeight;\n }\n sliceInfoBuffer.unmap();\n }\n\n // `Heads` struct contains the start index of the linked-list of translucent fragments\n // for a given pixel.\n // * numFragments : u32\n // * data : array\n const headsBuffer = device.createBuffer({\n size: (1 + canvas.width * sliceHeight) * Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n label: 'headsBuffer',\n });\n\n const headsInitBuffer = device.createBuffer({\n size: (1 + canvas.width * sliceHeight) * Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.COPY_SRC,\n mappedAtCreation: true,\n label: 'headsInitBuffer',\n });\n {\n const buffer = new Uint32Array(headsInitBuffer.getMappedRange());\n\n for (let i = 0; i < buffer.length; ++i) {\n buffer[i] = 0xffffffff;\n }\n\n headsInitBuffer.unmap();\n }\n\n const translucentBindGroup = device.createBindGroup({\n layout: translucentBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n label: 'uniforms',\n },\n },\n {\n binding: 1,\n resource: {\n buffer: headsBuffer,\n label: 'headsBuffer',\n },\n },\n {\n binding: 2,\n resource: {\n buffer: linkedListBuffer,\n label: 'linkedListBuffer',\n },\n },\n {\n binding: 3,\n resource: depthTextureView,\n },\n {\n binding: 4,\n resource: {\n buffer: sliceInfoBuffer,\n size: device.limits.minUniformBufferOffsetAlignment,\n label: 'sliceInfoBuffer',\n },\n },\n ],\n label: 'translucentBindGroup',\n });\n\n const compositeBindGroup = device.createBindGroup({\n layout: compositePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n label: 'uniforms',\n },\n },\n {\n binding: 1,\n resource: {\n buffer: headsBuffer,\n label: 'headsBuffer',\n },\n },\n {\n binding: 2,\n resource: {\n buffer: linkedListBuffer,\n label: 'linkedListBuffer',\n },\n },\n {\n binding: 3,\n resource: {\n buffer: sliceInfoBuffer,\n size: device.limits.minUniformBufferOffsetAlignment,\n label: 'sliceInfoBuffer',\n },\n },\n ],\n });\n\n opaquePassDescriptor.depthStencilAttachment.view = depthTextureView;\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const aspect = canvas.width / canvas.height;\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n const eyePosition = vec3.fromValues(0, 5, -100);\n\n const rad = Math.PI * (Date.now() / 5000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n return function doDraw() {\n // update the uniform buffer\n {\n const buffer = new ArrayBuffer(uniformBuffer.size);\n\n new Float32Array(buffer).set(getCameraViewProjMatrix());\n new Uint32Array(buffer, 16 * Float32Array.BYTES_PER_ELEMENT).set([\n averageLayersPerFragment * canvas.width * sliceHeight,\n canvas.width,\n ]);\n\n device.queue.writeBuffer(uniformBuffer, 0, buffer);\n }\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n // Draw the opaque objects\n opaquePassDescriptor.colorAttachments[0].view = textureView;\n const opaquePassEncoder =\n commandEncoder.beginRenderPass(opaquePassDescriptor);\n opaquePassEncoder.setPipeline(opaquePipeline);\n opaquePassEncoder.setBindGroup(0, opaqueBindGroup);\n opaquePassEncoder.setVertexBuffer(0, vertexBuffer);\n opaquePassEncoder.setIndexBuffer(indexBuffer, 'uint16');\n opaquePassEncoder.drawIndexed(mesh.triangles.length * 3, 8);\n opaquePassEncoder.end();\n\n for (let slice = 0; slice < numSlices; ++slice) {\n // initialize the heads buffer\n commandEncoder.copyBufferToBuffer(\n headsInitBuffer,\n 0,\n headsBuffer,\n 0,\n headsInitBuffer.size\n );\n\n const scissorX = 0;\n const scissorY = slice * sliceHeight;\n const scissorWidth = canvas.width;\n const scissorHeight =\n Math.min((slice + 1) * sliceHeight, canvas.height) -\n slice * sliceHeight;\n\n // Draw the translucent objects\n translucentPassDescriptor.colorAttachments[0].view = textureView;\n const translucentPassEncoder = commandEncoder.beginRenderPass(\n translucentPassDescriptor\n );\n\n // Set the scissor to only process a horizontal slice of the frame\n translucentPassEncoder.setScissorRect(\n scissorX,\n scissorY,\n scissorWidth,\n scissorHeight\n );\n\n translucentPassEncoder.setPipeline(translucentPipeline);\n translucentPassEncoder.setBindGroup(0, translucentBindGroup, [\n slice * device.limits.minUniformBufferOffsetAlignment,\n ]);\n translucentPassEncoder.setVertexBuffer(0, vertexBuffer);\n translucentPassEncoder.setIndexBuffer(indexBuffer, 'uint16');\n translucentPassEncoder.drawIndexed(mesh.triangles.length * 3, 8);\n translucentPassEncoder.end();\n\n // Composite the opaque and translucent objects\n compositePassDescriptor.colorAttachments[0].view = textureView;\n const compositePassEncoder = commandEncoder.beginRenderPass(\n compositePassDescriptor\n );\n\n // Set the scissor to only process a horizontal slice of the frame\n compositePassEncoder.setScissorRect(\n scissorX,\n scissorY,\n scissorWidth,\n scissorHeight\n );\n\n compositePassEncoder.setPipeline(compositePipeline);\n compositePassEncoder.setBindGroup(0, compositeBindGroup, [\n slice * device.limits.minUniformBufferOffsetAlignment,\n ]);\n compositePassEncoder.draw(6);\n compositePassEncoder.end();\n }\n\n device.queue.submit([commandEncoder.finish()]);\n };\n };\n\n let doDraw = configure();\n\n const updateSettings = () => {\n doDraw = configure();\n };\n\n gui\n .add(settings, 'memoryStrategy', ['multipass', 'clamp-pixel-ratio'])\n .onFinishChange(updateSettings);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n doDraw();\n\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst ABuffer: () => JSX.Element = () =>\n makeSample({\n name: 'A-Buffer',\n description: `Demonstrates order independent transparency using a per-pixel \n linked-list of translucent fragments. Provides a choice for \n limiting memory usage (when required).`,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: 'opaque.wsgl',\n contents: opaqueWGSL,\n },\n {\n name: 'translucent.wsgl',\n contents: translucentWGSL,\n },\n {\n name: 'composite.wsgl',\n contents: compositeWGSL,\n },\n ],\n filename: __filename,\n });\n\nexport default ABuffer;\n"},{name:"opaque.wsgl",contents:l},{name:"translucent.wsgl",contents:u},{name:"composite.wsgl",contents:c}],filename:f});var p=m},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},8748:function(e,n){n.m=[[5.929688,4.125,0],[5.387188,4.125,2.7475],[5.2971,4.494141,2.70917],[5.832031,4.494141,0],[5.401602,4.617188,2.753633],[5.945313,4.617188,0],[5.614209,4.494141,2.844092],[6.175781,4.494141,0],[5.848437,4.125,2.94375],[6.429688,4.125,0],[3.899688,4.125,4.97],[3.830352,4.494141,4.900664],[3.910782,4.617188,4.981094],[4.074414,4.494141,5.144727],[4.254687,4.125,5.325],[1.677188,4.125,6.4575],[1.638858,4.494141,6.367412],[1.68332,4.617188,6.471914],[1.77378,4.494141,6.684522],[1.873438,4.125,6.91875],[-1.070312,4.125,7],[-1.070312,4.494141,6.902344],[-1.070312,4.617188,7.015625],[-1.070312,4.494141,7.246094],[-1.070312,4.125,7.5],[-1.070312,4.125,7],[-4.007656,4.125,6.4575],[-3.859572,4.494141,6.367412],[-1.070312,4.494141,6.902344],[-3.847676,4.617188,6.471914],[-1.070312,4.617188,7.015625],[-3.917371,4.494141,6.684522],[-1.070312,4.494141,7.246094],[-4.014062,4.125,6.91875],[-1.070312,4.125,7.5],[-6.209063,4.125,4.97],[-6.042168,4.494141,4.900664],[-6.0725,4.617188,4.981094],[-6.217675,4.494141,5.144727],[-6.395312,4.125,5.325],[-7.591093,4.125,2.7475],[-7.464421,4.494141,2.70917],[-7.550137,4.617188,2.753633],[-7.755822,4.494141,2.844092],[-7.989062,4.125,2.94375],[-8.070313,4.125,0],[-7.972656,4.494141,0],[-8.085938,4.617188,0],[-8.316406,4.494141,0],[-8.570313,4.125,0],[-8.070313,4.125,0],[-7.527812,4.125,-2.7475],[-7.437724,4.494141,-2.70917],[-7.972656,4.494141,0],[-7.542227,4.617188,-2.753633],[-8.085938,4.617188,0],[-7.754834,4.494141,-2.844092],[-8.316406,4.494141,0],[-7.989062,4.125,-2.94375],[-8.570313,4.125,0],[-6.040312,4.125,-4.97],[-5.970977,4.494141,-4.900664],[-6.051406,4.617188,-4.981094],[-6.215039,4.494141,-5.144727],[-6.395312,4.125,-5.325],[-3.817812,4.125,-6.4575],[-3.779482,4.494141,-6.367412],[-3.823945,4.617188,-6.471914],[-3.914404,4.494141,-6.684522],[-4.014062,4.125,-6.91875],[-1.070312,4.125,-7],[-1.070312,4.494141,-6.902344],[-1.070312,4.617188,-7.015625],[-1.070312,4.494141,-7.246094],[-1.070312,4.125,-7.5],[-1.070312,4.125,-7],[1.677188,4.125,-6.4575],[1.638858,4.494141,-6.367412],[-1.070312,4.494141,-6.902344],[1.68332,4.617188,-6.471914],[-1.070312,4.617188,-7.015625],[1.77378,4.494141,-6.684522],[-1.070312,4.494141,-7.246094],[1.873438,4.125,-6.91875],[-1.070312,4.125,-7.5],[3.899688,4.125,-4.97],[3.830352,4.494141,-4.900664],[3.910782,4.617188,-4.981094],[4.074414,4.494141,-5.144727],[4.254687,4.125,-5.325],[5.387188,4.125,-2.7475],[5.2971,4.494141,-2.70917],[5.401602,4.617188,-2.753633],[5.614209,4.494141,-2.844092],[5.848437,4.125,-2.94375],[5.929688,4.125,0],[5.832031,4.494141,0],[5.945313,4.617188,0],[6.175781,4.494141,0],[6.429688,4.125,0],[6.429688,4.125,0],[5.848437,4.125,2.94375],[6.695264,2.162109,3.304053],[7.347656,2.162109,0],[7.433985,.234375,3.61836],[8.148438,.234375,0],[7.956494,-1.623047,3.840674],[8.714844,-1.623047,0],[8.154688,-3.375,3.925],[8.929688,-3.375,0],[4.254687,4.125,5.325],[4.906446,2.162109,5.976758],[5.475,.234375,6.545312],[5.877149,-1.623047,6.947461],[6.029688,-3.375,7.1],[1.873438,4.125,6.91875],[2.23374,2.162109,7.765576],[2.548047,.234375,8.504297],[2.770362,-1.623047,9.026807],[2.854688,-3.375,9.225],[-1.070312,4.125,7.5],[-1.070312,2.162109,8.417969],[-1.070312,.234375,9.21875],[-1.070312,-1.623047,9.785156],[-1.070312,-3.375,10],[-1.070312,4.125,7.5],[-4.014062,4.125,6.91875],[-4.374365,2.162109,7.765576],[-1.070312,2.162109,8.417969],[-4.688672,.234375,8.504297],[-1.070312,.234375,9.21875],[-4.910986,-1.623047,9.026807],[-1.070312,-1.623047,9.785156],[-4.995313,-3.375,9.225],[-1.070312,-3.375,10],[-6.395312,4.125,5.325],[-7.047071,2.162109,5.976758],[-7.615624,.234375,6.545312],[-8.017773,-1.623047,6.947461],[-8.170312,-3.375,7.1],[-7.989062,4.125,2.94375],[-8.835889,2.162109,3.304053],[-9.57461,.234375,3.61836],[-10.097119,-1.623047,3.840674],[-10.295313,-3.375,3.925],[-8.570313,4.125,0],[-9.488281,2.162109,0],[-10.289063,.234375,0],[-10.855469,-1.623047,0],[-11.070313,-3.375,0],[-8.570313,4.125,0],[-7.989062,4.125,-2.94375],[-8.835889,2.162109,-3.304053],[-9.488281,2.162109,0],[-9.57461,.234375,-3.61836],[-10.289063,.234375,0],[-10.097119,-1.623047,-3.840674],[-10.855469,-1.623047,0],[-10.295313,-3.375,-3.925],[-11.070313,-3.375,0],[-6.395312,4.125,-5.325],[-7.047071,2.162109,-5.976758],[-7.615624,.234375,-6.545312],[-8.017773,-1.623047,-6.947461],[-8.170312,-3.375,-7.1],[-4.014062,4.125,-6.91875],[-4.374365,2.162109,-7.765576],[-4.688672,.234375,-8.504297],[-4.910986,-1.623047,-9.026807],[-4.995313,-3.375,-9.225],[-1.070312,4.125,-7.5],[-1.070312,2.162109,-8.417969],[-1.070312,.234375,-9.21875],[-1.070312,-1.623047,-9.785156],[-1.070312,-3.375,-10],[-1.070312,4.125,-7.5],[1.873438,4.125,-6.91875],[2.23374,2.162109,-7.765576],[-1.070312,2.162109,-8.417969],[2.548047,.234375,-8.504297],[-1.070312,.234375,-9.21875],[2.770362,-1.623047,-9.026807],[-1.070312,-1.623047,-9.785156],[2.854688,-3.375,-9.225],[-1.070312,-3.375,-10],[4.254687,4.125,-5.325],[4.906446,2.162109,-5.976758],[5.475,.234375,-6.545312],[5.877149,-1.623047,-6.947461],[6.029688,-3.375,-7.1],[5.848437,4.125,-2.94375],[6.695264,2.162109,-3.304053],[7.433985,.234375,-3.61836],[7.956494,-1.623047,-3.840674],[8.154688,-3.375,-3.925],[6.429688,4.125,0],[7.347656,2.162109,0],[8.148438,.234375,0],[8.714844,-1.623047,0],[8.929688,-3.375,0],[8.929688,-3.375,0],[8.154688,-3.375,3.925],[7.794336,-4.857422,3.77168],[8.539063,-4.857422,0],[7.001562,-5.953125,3.434375],[7.679688,-5.953125,0],[6.208789,-6.697266,3.09707],[6.820313,-6.697266,0],[5.848437,-7.125,2.94375],[6.429688,-7.125,0],[6.029688,-3.375,7.1],[5.752343,-4.857422,6.822656],[5.142187,-5.953125,6.2125],[4.532031,-6.697266,5.602344],[4.254687,-7.125,5.325],[2.854688,-3.375,9.225],[2.701367,-4.857422,8.864649],[2.364063,-5.953125,8.071875],[2.026758,-6.697266,7.279101],[1.873438,-7.125,6.91875],[-1.070312,-3.375,10],[-1.070312,-4.857422,9.609375],[-1.070312,-5.953125,8.75],[-1.070312,-6.697266,7.890625],[-1.070312,-7.125,7.5],[-1.070312,-3.375,10],[-4.995313,-3.375,9.225],[-4.841992,-4.857422,8.864649],[-1.070312,-4.857422,9.609375],[-4.504687,-5.953125,8.071875],[-1.070312,-5.953125,8.75],[-4.167383,-6.697266,7.279101],[-1.070312,-6.697266,7.890625],[-4.014062,-7.125,6.91875],[-1.070312,-7.125,7.5],[-8.170312,-3.375,7.1],[-7.892968,-4.857422,6.822656],[-7.282812,-5.953125,6.2125],[-6.672656,-6.697266,5.602344],[-6.395312,-7.125,5.325],[-10.295313,-3.375,3.925],[-9.934961,-4.857422,3.77168],[-9.142187,-5.953125,3.434375],[-8.349414,-6.697266,3.09707],[-7.989062,-7.125,2.94375],[-11.070313,-3.375,0],[-10.679688,-4.857422,0],[-9.820313,-5.953125,0],[-8.960938,-6.697266,0],[-8.570313,-7.125,0],[-11.070313,-3.375,0],[-10.295313,-3.375,-3.925],[-9.934961,-4.857422,-3.77168],[-10.679688,-4.857422,0],[-9.142187,-5.953125,-3.434375],[-9.820313,-5.953125,0],[-8.349414,-6.697266,-3.09707],[-8.960938,-6.697266,0],[-7.989062,-7.125,-2.94375],[-8.570313,-7.125,0],[-8.170312,-3.375,-7.1],[-7.892968,-4.857422,-6.822656],[-7.282812,-5.953125,-6.2125],[-6.672656,-6.697266,-5.602344],[-6.395312,-7.125,-5.325],[-4.995313,-3.375,-9.225],[-4.841992,-4.857422,-8.864649],[-4.504687,-5.953125,-8.071875],[-4.167383,-6.697266,-7.279101],[-4.014062,-7.125,-6.91875],[-1.070312,-3.375,-10],[-1.070312,-4.857422,-9.609375],[-1.070312,-5.953125,-8.75],[-1.070312,-6.697266,-7.890625],[-1.070312,-7.125,-7.5],[-1.070312,-3.375,-10],[2.854688,-3.375,-9.225],[2.701367,-4.857422,-8.864649],[-1.070312,-4.857422,-9.609375],[2.364063,-5.953125,-8.071875],[-1.070312,-5.953125,-8.75],[2.026758,-6.697266,-7.279101],[-1.070312,-6.697266,-7.890625],[1.873438,-7.125,-6.91875],[-1.070312,-7.125,-7.5],[6.029688,-3.375,-7.1],[5.752343,-4.857422,-6.822656],[5.142187,-5.953125,-6.2125],[4.532031,-6.697266,-5.602344],[4.254687,-7.125,-5.325],[8.154688,-3.375,-3.925],[7.794336,-4.857422,-3.77168],[7.001562,-5.953125,-3.434375],[6.208789,-6.697266,-3.09707],[5.848437,-7.125,-2.94375],[8.929688,-3.375,0],[8.539063,-4.857422,0],[7.679688,-5.953125,0],[6.820313,-6.697266,0],[6.429688,-7.125,0],[6.429688,-7.125,0],[5.848437,-7.125,2.94375],[5.691685,-7.400391,2.877056],[6.259766,-7.400391,0],[4.853868,-7.640625,2.520586],[5.351563,-7.640625,0],[2.783648,-7.810547,1.639761],[3.107422,-7.810547,0],[-1.070312,-7.875,0],[4.254687,-7.125,5.325],[4.134043,-7.400391,5.204355],[3.489219,-7.640625,4.559531],[1.895879,-7.810547,2.966191],[-1.070312,-7.875,0],[1.873438,-7.125,6.91875],[1.806743,-7.400391,6.761997],[1.450274,-7.640625,5.92418],[.569448,-7.810547,3.85396],[-1.070312,-7.875,0],[-1.070312,-7.125,7.5],[-1.070312,-7.400391,7.330078],[-1.070312,-7.640625,6.421875],[-1.070312,-7.810547,4.177734],[-1.070312,-7.875,0],[-1.070312,-7.125,7.5],[-4.014062,-7.125,6.91875],[-3.947368,-7.400391,6.761997],[-1.070312,-7.400391,7.330078],[-3.590898,-7.640625,5.92418],[-1.070312,-7.640625,6.421875],[-2.710073,-7.810547,3.85396],[-1.070312,-7.810547,4.177734],[-1.070312,-7.875,0],[-6.395312,-7.125,5.325],[-6.274668,-7.400391,5.204355],[-5.629844,-7.640625,4.559531],[-4.036504,-7.810547,2.966191],[-1.070312,-7.875,0],[-7.989062,-7.125,2.94375],[-7.832309,-7.400391,2.877056],[-6.994492,-7.640625,2.520586],[-4.924272,-7.810547,1.639761],[-1.070312,-7.875,0],[-8.570313,-7.125,0],[-8.400391,-7.400391,0],[-7.492188,-7.640625,0],[-5.248047,-7.810547,0],[-1.070312,-7.875,0],[-8.570313,-7.125,0],[-7.989062,-7.125,-2.94375],[-7.832309,-7.400391,-2.877056],[-8.400391,-7.400391,0],[-6.994492,-7.640625,-2.520586],[-7.492188,-7.640625,0],[-4.924272,-7.810547,-1.639761],[-5.248047,-7.810547,0],[-1.070312,-7.875,0],[-6.395312,-7.125,-5.325],[-6.274668,-7.400391,-5.204355],[-5.629844,-7.640625,-4.559531],[-4.036504,-7.810547,-2.966191],[-1.070312,-7.875,0],[-4.014062,-7.125,-6.91875],[-3.947368,-7.400391,-6.761997],[-3.590898,-7.640625,-5.92418],[-2.710073,-7.810547,-3.85396],[-1.070312,-7.875,0],[-1.070312,-7.125,-7.5],[-1.070312,-7.400391,-7.330078],[-1.070312,-7.640625,-6.421875],[-1.070312,-7.810547,-4.177734],[-1.070312,-7.875,0],[-1.070312,-7.125,-7.5],[1.873438,-7.125,-6.91875],[1.806743,-7.400391,-6.761997],[-1.070312,-7.400391,-7.330078],[1.450274,-7.640625,-5.92418],[-1.070312,-7.640625,-6.421875],[.569448,-7.810547,-3.85396],[-1.070312,-7.810547,-4.177734],[-1.070312,-7.875,0],[4.254687,-7.125,-5.325],[4.134043,-7.400391,-5.204355],[3.489219,-7.640625,-4.559531],[1.895879,-7.810547,-2.966191],[-1.070312,-7.875,0],[5.848437,-7.125,-2.94375],[5.691685,-7.400391,-2.877056],[4.853868,-7.640625,-2.520586],[2.783648,-7.810547,-1.639761],[-1.070312,-7.875,0],[6.429688,-7.125,0],[6.259766,-7.400391,0],[5.351563,-7.640625,0],[3.107422,-7.810547,0],[-1.070312,-7.875,0],[-9.070313,2.25,0],[-8.992188,2.425781,.84375],[-11.47583,2.405457,.84375],[-11.40625,2.232422,0],[-13.298828,2.263184,.84375],[-13.132813,2.109375,0],[-14.421631,1.877014,.84375],[-14.203125,1.775391,0],[-14.804688,1.125,.84375],[-14.570313,1.125,0],[-8.820313,2.8125,1.125],[-11.628906,2.786134,1.125],[-13.664063,2.601563,1.125],[-14.902344,2.100586,1.125],[-15.320313,1.125,1.125],[-8.648438,3.199219,.84375],[-11.781982,3.166809,.84375],[-14.029297,2.939941,.84375],[-15.383057,2.324158,.84375],[-15.835938,1.125,.84375],[-8.570313,3.375,0],[-11.851563,3.339844,0],[-14.195313,3.09375,0],[-15.601563,2.425781,0],[-16.070313,1.125,0],[-8.570313,3.375,0],[-8.648438,3.199219,-.84375],[-11.781982,3.166809,-.84375],[-11.851563,3.339844,0],[-14.029297,2.939941,-.84375],[-14.195313,3.09375,0],[-15.383057,2.324158,-.84375],[-15.601563,2.425781,0],[-15.835938,1.125,-.84375],[-16.070313,1.125,0],[-8.820313,2.8125,-1.125],[-11.628906,2.786134,-1.125],[-13.664063,2.601563,-1.125],[-14.902344,2.100586,-1.125],[-15.320313,1.125,-1.125],[-8.992188,2.425781,-.84375],[-11.47583,2.405457,-.84375],[-13.298828,2.263184,-.84375],[-14.421631,1.877014,-.84375],[-14.804688,1.125,-.84375],[-9.070313,2.25,0],[-11.40625,2.232422,0],[-13.132813,2.109375,0],[-14.203125,1.775391,0],[-14.570313,1.125,0],[-14.570313,1.125,0],[-14.804688,1.125,.84375],[-14.588013,.00705,.84375],[-14.375,.105469,0],[-13.90918,-1.275146,.84375],[-13.757813,-1.125,0],[-12.724976,-2.540863,.84375],[-12.671875,-2.355469,0],[-10.992188,-3.609375,.84375],[-11.070313,-3.375,0],[-15.320313,1.125,1.125],[-15.056641,-.209473,1.125],[-14.242188,-1.605469,1.125],[-12.841797,-2.94873,1.125],[-10.820313,-4.125,1.125],[-15.835938,1.125,.84375],[-15.525269,-.425995,.84375],[-14.575195,-1.935791,.84375],[-12.958618,-3.356598,.84375],[-10.648438,-4.640625,.84375],[-16.070313,1.125,0],[-15.738281,-.524414,0],[-14.726563,-2.085938,0],[-13.011719,-3.541992,0],[-10.570313,-4.875,0],[-16.070313,1.125,0],[-15.835938,1.125,-.84375],[-15.525269,-.425995,-.84375],[-15.738281,-.524414,0],[-14.575195,-1.935791,-.84375],[-14.726563,-2.085938,0],[-12.958618,-3.356598,-.84375],[-13.011719,-3.541992,0],[-10.648438,-4.640625,-.84375],[-10.570313,-4.875,0],[-15.320313,1.125,-1.125],[-15.056641,-.209473,-1.125],[-14.242188,-1.605469,-1.125],[-12.841797,-2.94873,-1.125],[-10.820313,-4.125,-1.125],[-14.804688,1.125,-.84375],[-14.588013,.00705,-.84375],[-13.90918,-1.275146,-.84375],[-12.724976,-2.540863,-.84375],[-10.992188,-3.609375,-.84375],[-14.570313,1.125,0],[-14.375,.105469,0],[-13.757813,-1.125,0],[-12.671875,-2.355469,0],[-11.070313,-3.375,0],[7.429688,-.75,0],[7.429688,-1.394531,1.85625],[10.01123,-.677124,1.676074],[9.828125,-.199219,0],[11.101563,.84668,1.279688],[10.867188,1.125,0],[11.723145,2.629761,.883301],[11.4375,2.730469,0],[12.898438,4.125,.703125],[12.429688,4.125,0],[7.429688,-2.8125,2.475],[10.414063,-1.728516,2.234766],[11.617188,.234375,1.70625],[12.351563,2.408203,1.177734],[13.929688,4.125,.9375],[7.429688,-4.230469,1.85625],[10.816895,-2.779907,1.676074],[12.132813,-.37793,1.279688],[12.97998,2.186646,.883301],[14.960938,4.125,.703125],[7.429688,-4.875,0],[11,-3.257813,0],[12.367188,-.65625,0],[13.265625,2.085938,0],[15.429688,4.125,0],[7.429688,-4.875,0],[7.429688,-4.230469,-1.85625],[10.816895,-2.779907,-1.676074],[11,-3.257813,0],[12.132813,-.37793,-1.279688],[12.367188,-.65625,0],[12.97998,2.186646,-.883301],[13.265625,2.085938,0],[14.960938,4.125,-.703125],[15.429688,4.125,0],[7.429688,-2.8125,-2.475],[10.414063,-1.728516,-2.234766],[11.617188,.234375,-1.70625],[12.351563,2.408203,-1.177734],[13.929688,4.125,-.9375],[7.429688,-1.394531,-1.85625],[10.01123,-.677124,-1.676074],[11.101563,.84668,-1.279688],[11.723145,2.629761,-.883301],[12.898438,4.125,-.703125],[7.429688,-.75,0],[9.828125,-.199219,0],[10.867188,1.125,0],[11.4375,2.730469,0],[12.429688,4.125,0],[12.429688,4.125,0],[12.898438,4.125,.703125],[13.291077,4.346237,.65918],[12.789063,4.335938,0],[13.525879,4.422729,.5625],[13.054688,4.40625,0],[13.532898,4.350357,.46582],[13.132813,4.335938,0],[13.242188,4.125,.421875],[12.929688,4.125,0],[13.929688,4.125,.9375],[14.395508,4.368896,.878906],[14.5625,4.458984,.75],[14.413086,4.38208,.621094],[13.929688,4.125,.5625],[14.960938,4.125,.703125],[15.499939,4.391556,.65918],[15.599121,4.495239,.5625],[15.293274,4.413804,.46582],[14.617188,4.125,.421875],[15.429688,4.125,0],[16.001953,4.401855,0],[16.070313,4.511719,0],[15.693359,4.428224,0],[14.929688,4.125,0],[15.429688,4.125,0],[14.960938,4.125,-.703125],[15.499939,4.391556,-.65918],[16.001953,4.401855,0],[15.599121,4.495239,-.5625],[16.070313,4.511719,0],[15.293274,4.413804,-.46582],[15.693359,4.428224,0],[14.617188,4.125,-.421875],[14.929688,4.125,0],[13.929688,4.125,-.9375],[14.395508,4.368896,-.878906],[14.5625,4.458984,-.75],[14.413086,4.38208,-.621094],[13.929688,4.125,-.5625],[12.898438,4.125,-.703125],[13.291077,4.346237,-.65918],[13.525879,4.422729,-.5625],[13.532898,4.350357,-.46582],[13.242188,4.125,-.421875],[12.429688,4.125,0],[12.789063,4.335938,0],[13.054688,4.40625,0],[13.132813,4.335938,0],[12.929688,4.125,0],[.501414,7.628906,.670256],[.632813,7.628906,0],[-1.070312,7.875,0],[.429278,7.03125,.639395],[.554688,7.03125,0],[-.162029,6.292969,.38696],[-.085937,6.292969,0],[-.147812,5.625,.3925],[-.070312,5.625,0],[.140489,7.628906,1.210801],[-1.070312,7.875,0],[.084844,7.03125,1.155156],[-.370879,6.292969,.699434],[-.360312,5.625,.71],[-.400056,7.628906,1.571726],[-1.070312,7.875,0],[-.430918,7.03125,1.49959],[-.683352,6.292969,.908284],[-.677812,5.625,.9225],[-1.070312,7.628906,1.703125],[-1.070312,7.875,0],[-1.070312,7.03125,1.625],[-1.070312,6.292969,.984375],[-1.070312,5.625,1],[-1.740569,7.628906,1.571726],[-1.070312,7.628906,1.703125],[-1.070312,7.875,0],[-1.709707,7.03125,1.49959],[-1.070312,7.03125,1.625],[-1.457273,6.292969,.908284],[-1.070312,6.292969,.984375],[-1.462812,5.625,.9225],[-1.070312,5.625,1],[-2.281113,7.628906,1.210801],[-1.070312,7.875,0],[-2.225469,7.03125,1.155156],[-1.769746,6.292969,.699434],[-1.780312,5.625,.71],[-2.642038,7.628906,.670256],[-1.070312,7.875,0],[-2.569902,7.03125,.639395],[-1.978596,6.292969,.38696],[-1.992812,5.625,.3925],[-2.773438,7.628906,0],[-1.070312,7.875,0],[-2.695313,7.03125,0],[-2.054687,6.292969,0],[-2.070312,5.625,0],[-2.642038,7.628906,-.670256],[-2.773438,7.628906,0],[-1.070312,7.875,0],[-2.569902,7.03125,-.639395],[-2.695313,7.03125,0],[-1.978596,6.292969,-.38696],[-2.054687,6.292969,0],[-1.992812,5.625,-.3925],[-2.070312,5.625,0],[-2.281113,7.628906,-1.210801],[-1.070312,7.875,0],[-2.225469,7.03125,-1.155156],[-1.769746,6.292969,-.699434],[-1.780312,5.625,-.71],[-1.740569,7.628906,-1.571726],[-1.070312,7.875,0],[-1.709707,7.03125,-1.49959],[-1.457273,6.292969,-.908284],[-1.462812,5.625,-.9225],[-1.070312,7.628906,-1.703125],[-1.070312,7.875,0],[-1.070312,7.03125,-1.625],[-1.070312,6.292969,-.984375],[-1.070312,5.625,-1],[-.400056,7.628906,-1.571726],[-1.070312,7.628906,-1.703125],[-1.070312,7.875,0],[-.430918,7.03125,-1.49959],[-1.070312,7.03125,-1.625],[-.683352,6.292969,-.908284],[-1.070312,6.292969,-.984375],[-.677812,5.625,-.9225],[-1.070312,5.625,-1],[.140489,7.628906,-1.210801],[-1.070312,7.875,0],[.084844,7.03125,-1.155156],[-.370879,6.292969,-.699434],[-.360312,5.625,-.71],[.501414,7.628906,-.670256],[-1.070312,7.875,0],[.429278,7.03125,-.639395],[-.162029,6.292969,-.38696],[-.147812,5.625,-.3925],[.632813,7.628906,0],[-1.070312,7.875,0],[.554688,7.03125,0],[-.085937,6.292969,0],[-.070312,5.625,0],[-.070312,5.625,0],[-.147812,5.625,.3925],[1.034141,5.179688,.895391],[1.210938,5.179688,0],[2.735,4.875,1.619062],[3.054688,4.875,0],[4.262891,4.570313,2.26914],[4.710938,4.570313,0],[4.925938,4.125,2.55125],[5.429688,4.125,0],[-.360312,5.625,.71],[.549375,5.179688,1.619688],[1.858438,4.875,2.92875],[3.034375,4.570313,4.104687],[3.544688,4.125,4.615],[-.677812,5.625,.9225],[-.174922,5.179688,2.104453],[.54875,4.875,3.805313],[1.198828,4.570313,5.333203],[1.480938,4.125,5.99625],[-1.070312,5.625,1],[-1.070312,5.179688,2.28125],[-1.070312,4.875,4.125],[-1.070312,4.570313,5.78125],[-1.070312,4.125,6.5],[-1.070312,5.625,1],[-1.462812,5.625,.9225],[-1.965703,5.179688,2.104453],[-1.070312,5.179688,2.28125],[-2.689375,4.875,3.805313],[-1.070312,4.875,4.125],[-3.339453,4.570313,5.333203],[-1.070312,4.570313,5.78125],[-3.621562,4.125,5.99625],[-1.070312,4.125,6.5],[-1.780312,5.625,.71],[-2.69,5.179688,1.619688],[-3.999062,4.875,2.92875],[-5.174999,4.570313,4.104687],[-5.685312,4.125,4.615],[-1.992812,5.625,.3925],[-3.174765,5.179688,.895391],[-4.875625,4.875,1.619062],[-6.403516,4.570313,2.26914],[-7.066563,4.125,2.55125],[-2.070312,5.625,0],[-3.351562,5.179688,0],[-5.195313,4.875,0],[-6.851563,4.570313,0],[-7.570313,4.125,0],[-2.070312,5.625,0],[-1.992812,5.625,-.3925],[-3.174765,5.179688,-.895391],[-3.351562,5.179688,0],[-4.875625,4.875,-1.619062],[-5.195313,4.875,0],[-6.403516,4.570313,-2.26914],[-6.851563,4.570313,0],[-7.066563,4.125,-2.55125],[-7.570313,4.125,0],[-1.780312,5.625,-.71],[-2.69,5.179688,-1.619688],[-3.999062,4.875,-2.92875],[-5.174999,4.570313,-4.104687],[-5.685312,4.125,-4.615],[-1.462812,5.625,-.9225],[-1.965703,5.179688,-2.104453],[-2.689375,4.875,-3.805313],[-3.339453,4.570313,-5.333203],[-3.621562,4.125,-5.99625],[-1.070312,5.625,-1],[-1.070312,5.179688,-2.28125],[-1.070312,4.875,-4.125],[-1.070312,4.570313,-5.78125],[-1.070312,4.125,-6.5],[-1.070312,5.625,-1],[-.677812,5.625,-.9225],[-.174922,5.179688,-2.104453],[-1.070312,5.179688,-2.28125],[.54875,4.875,-3.805313],[-1.070312,4.875,-4.125],[1.198828,4.570313,-5.333203],[-1.070312,4.570313,-5.78125],[1.480938,4.125,-5.99625],[-1.070312,4.125,-6.5],[-.360312,5.625,-.71],[.549375,5.179688,-1.619688],[1.858438,4.875,-2.92875],[3.034375,4.570313,-4.104687],[3.544688,4.125,-4.615],[-.147812,5.625,-.3925],[1.034141,5.179688,-.895391],[2.735,4.875,-1.619062],[4.262891,4.570313,-2.26914],[4.925938,4.125,-2.55125],[-.070312,5.625,0],[1.210938,5.179688,0],[3.054688,4.875,0],[4.710938,4.570313,0],[5.429688,4.125,0]],n.g=[[0,1,2],[2,3,0],[3,2,4],[4,5,3],[5,4,6],[6,7,5],[7,6,8],[8,9,7],[1,10,11],[11,2,1],[2,11,12],[12,4,2],[4,12,13],[13,6,4],[6,13,14],[14,8,6],[10,15,16],[16,11,10],[11,16,17],[17,12,11],[12,17,18],[18,13,12],[13,18,19],[19,14,13],[15,20,21],[21,16,15],[16,21,22],[22,17,16],[17,22,23],[23,18,17],[18,23,24],[24,19,18],[25,26,27],[27,28,25],[28,27,29],[29,30,28],[30,29,31],[31,32,30],[32,31,33],[33,34,32],[26,35,36],[36,27,26],[27,36,37],[37,29,27],[29,37,38],[38,31,29],[31,38,39],[39,33,31],[35,40,41],[41,36,35],[36,41,42],[42,37,36],[37,42,43],[43,38,37],[38,43,44],[44,39,38],[40,45,46],[46,41,40],[41,46,47],[47,42,41],[42,47,48],[48,43,42],[43,48,49],[49,44,43],[50,51,52],[52,53,50],[53,52,54],[54,55,53],[55,54,56],[56,57,55],[57,56,58],[58,59,57],[51,60,61],[61,52,51],[52,61,62],[62,54,52],[54,62,63],[63,56,54],[56,63,64],[64,58,56],[60,65,66],[66,61,60],[61,66,67],[67,62,61],[62,67,68],[68,63,62],[63,68,69],[69,64,63],[65,70,71],[71,66,65],[66,71,72],[72,67,66],[67,72,73],[73,68,67],[68,73,74],[74,69,68],[75,76,77],[77,78,75],[78,77,79],[79,80,78],[80,79,81],[81,82,80],[82,81,83],[83,84,82],[76,85,86],[86,77,76],[77,86,87],[87,79,77],[79,87,88],[88,81,79],[81,88,89],[89,83,81],[85,90,91],[91,86,85],[86,91,92],[92,87,86],[87,92,93],[93,88,87],[88,93,94],[94,89,88],[90,95,96],[96,91,90],[91,96,97],[97,92,91],[92,97,98],[98,93,92],[93,98,99],[99,94,93],[100,101,102],[102,103,100],[103,102,104],[104,105,103],[105,104,106],[106,107,105],[107,106,108],[108,109,107],[101,110,111],[111,102,101],[102,111,112],[112,104,102],[104,112,113],[113,106,104],[106,113,114],[114,108,106],[110,115,116],[116,111,110],[111,116,117],[117,112,111],[112,117,118],[118,113,112],[113,118,119],[119,114,113],[115,120,121],[121,116,115],[116,121,122],[122,117,116],[117,122,123],[123,118,117],[118,123,124],[124,119,118],[125,126,127],[127,128,125],[128,127,129],[129,130,128],[130,129,131],[131,132,130],[132,131,133],[133,134,132],[126,135,136],[136,127,126],[127,136,137],[137,129,127],[129,137,138],[138,131,129],[131,138,139],[139,133,131],[135,140,141],[141,136,135],[136,141,142],[142,137,136],[137,142,143],[143,138,137],[138,143,144],[144,139,138],[140,145,146],[146,141,140],[141,146,147],[147,142,141],[142,147,148],[148,143,142],[143,148,149],[149,144,143],[150,151,152],[152,153,150],[153,152,154],[154,155,153],[155,154,156],[156,157,155],[157,156,158],[158,159,157],[151,160,161],[161,152,151],[152,161,162],[162,154,152],[154,162,163],[163,156,154],[156,163,164],[164,158,156],[160,165,166],[166,161,160],[161,166,167],[167,162,161],[162,167,168],[168,163,162],[163,168,169],[169,164,163],[165,170,171],[171,166,165],[166,171,172],[172,167,166],[167,172,173],[173,168,167],[168,173,174],[174,169,168],[175,176,177],[177,178,175],[178,177,179],[179,180,178],[180,179,181],[181,182,180],[182,181,183],[183,184,182],[176,185,186],[186,177,176],[177,186,187],[187,179,177],[179,187,188],[188,181,179],[181,188,189],[189,183,181],[185,190,191],[191,186,185],[186,191,192],[192,187,186],[187,192,193],[193,188,187],[188,193,194],[194,189,188],[190,195,196],[196,191,190],[191,196,197],[197,192,191],[192,197,198],[198,193,192],[193,198,199],[199,194,193],[200,201,202],[202,203,200],[203,202,204],[204,205,203],[205,204,206],[206,207,205],[207,206,208],[208,209,207],[201,210,211],[211,202,201],[202,211,212],[212,204,202],[204,212,213],[213,206,204],[206,213,214],[214,208,206],[210,215,216],[216,211,210],[211,216,217],[217,212,211],[212,217,218],[218,213,212],[213,218,219],[219,214,213],[215,220,221],[221,216,215],[216,221,222],[222,217,216],[217,222,223],[223,218,217],[218,223,224],[224,219,218],[225,226,227],[227,228,225],[228,227,229],[229,230,228],[230,229,231],[231,232,230],[232,231,233],[233,234,232],[226,235,236],[236,227,226],[227,236,237],[237,229,227],[229,237,238],[238,231,229],[231,238,239],[239,233,231],[235,240,241],[241,236,235],[236,241,242],[242,237,236],[237,242,243],[243,238,237],[238,243,244],[244,239,238],[240,245,246],[246,241,240],[241,246,247],[247,242,241],[242,247,248],[248,243,242],[243,248,249],[249,244,243],[250,251,252],[252,253,250],[253,252,254],[254,255,253],[255,254,256],[256,257,255],[257,256,258],[258,259,257],[251,260,261],[261,252,251],[252,261,262],[262,254,252],[254,262,263],[263,256,254],[256,263,264],[264,258,256],[260,265,266],[266,261,260],[261,266,267],[267,262,261],[262,267,268],[268,263,262],[263,268,269],[269,264,263],[265,270,271],[271,266,265],[266,271,272],[272,267,266],[267,272,273],[273,268,267],[268,273,274],[274,269,268],[275,276,277],[277,278,275],[278,277,279],[279,280,278],[280,279,281],[281,282,280],[282,281,283],[283,284,282],[276,285,286],[286,277,276],[277,286,287],[287,279,277],[279,287,288],[288,281,279],[281,288,289],[289,283,281],[285,290,291],[291,286,285],[286,291,292],[292,287,286],[287,292,293],[293,288,287],[288,293,294],[294,289,288],[290,295,296],[296,291,290],[291,296,297],[297,292,291],[292,297,298],[298,293,292],[293,298,299],[299,294,293],[300,301,302],[302,303,300],[303,302,304],[304,305,303],[305,304,306],[306,307,305],[307,306,308],[301,309,310],[310,302,301],[302,310,311],[311,304,302],[304,311,312],[312,306,304],[306,312,313],[309,314,315],[315,310,309],[310,315,316],[316,311,310],[311,316,317],[317,312,311],[312,317,318],[314,319,320],[320,315,314],[315,320,321],[321,316,315],[316,321,322],[322,317,316],[317,322,323],[324,325,326],[326,327,324],[327,326,328],[328,329,327],[329,328,330],[330,331,329],[331,330,332],[325,333,334],[334,326,325],[326,334,335],[335,328,326],[328,335,336],[336,330,328],[330,336,337],[333,338,339],[339,334,333],[334,339,340],[340,335,334],[335,340,341],[341,336,335],[336,341,342],[338,343,344],[344,339,338],[339,344,345],[345,340,339],[340,345,346],[346,341,340],[341,346,347],[348,349,350],[350,351,348],[351,350,352],[352,353,351],[353,352,354],[354,355,353],[355,354,356],[349,357,358],[358,350,349],[350,358,359],[359,352,350],[352,359,360],[360,354,352],[354,360,361],[357,362,363],[363,358,357],[358,363,364],[364,359,358],[359,364,365],[365,360,359],[360,365,366],[362,367,368],[368,363,362],[363,368,369],[369,364,363],[364,369,370],[370,365,364],[365,370,371],[372,373,374],[374,375,372],[375,374,376],[376,377,375],[377,376,378],[378,379,377],[379,378,380],[373,381,382],[382,374,373],[374,382,383],[383,376,374],[376,383,384],[384,378,376],[378,384,385],[381,386,387],[387,382,381],[382,387,388],[388,383,382],[383,388,389],[389,384,383],[384,389,390],[386,391,392],[392,387,386],[387,392,393],[393,388,387],[388,393,394],[394,389,388],[389,394,395],[396,397,398],[398,399,396],[399,398,400],[400,401,399],[401,400,402],[402,403,401],[403,402,404],[404,405,403],[397,406,407],[407,398,397],[398,407,408],[408,400,398],[400,408,409],[409,402,400],[402,409,410],[410,404,402],[406,411,412],[412,407,406],[407,412,413],[413,408,407],[408,413,414],[414,409,408],[409,414,415],[415,410,409],[411,416,417],[417,412,411],[412,417,418],[418,413,412],[413,418,419],[419,414,413],[414,419,420],[420,415,414],[421,422,423],[423,424,421],[424,423,425],[425,426,424],[426,425,427],[427,428,426],[428,427,429],[429,430,428],[422,431,432],[432,423,422],[423,432,433],[433,425,423],[425,433,434],[434,427,425],[427,434,435],[435,429,427],[431,436,437],[437,432,431],[432,437,438],[438,433,432],[433,438,439],[439,434,433],[434,439,440],[440,435,434],[436,441,442],[442,437,436],[437,442,443],[443,438,437],[438,443,444],[444,439,438],[439,444,445],[445,440,439],[446,447,448],[448,449,446],[449,448,450],[450,451,449],[451,450,452],[452,453,451],[453,452,454],[454,455,453],[447,456,457],[457,448,447],[448,457,458],[458,450,448],[450,458,459],[459,452,450],[452,459,460],[460,454,452],[456,461,462],[462,457,456],[457,462,463],[463,458,457],[458,463,464],[464,459,458],[459,464,465],[465,460,459],[461,466,467],[467,462,461],[462,467,468],[468,463,462],[463,468,469],[469,464,463],[464,469,470],[470,465,464],[471,472,473],[473,474,471],[474,473,475],[475,476,474],[476,475,477],[477,478,476],[478,477,479],[479,480,478],[472,481,482],[482,473,472],[473,482,483],[483,475,473],[475,483,484],[484,477,475],[477,484,485],[485,479,477],[481,486,487],[487,482,481],[482,487,488],[488,483,482],[483,488,489],[489,484,483],[484,489,490],[490,485,484],[486,491,492],[492,487,486],[487,492,493],[493,488,487],[488,493,494],[494,489,488],[489,494,495],[495,490,489],[496,497,498],[498,499,496],[499,498,500],[500,501,499],[501,500,502],[502,503,501],[503,502,504],[504,505,503],[497,506,507],[507,498,497],[498,507,508],[508,500,498],[500,508,509],[509,502,500],[502,509,510],[510,504,502],[506,511,512],[512,507,506],[507,512,513],[513,508,507],[508,513,514],[514,509,508],[509,514,515],[515,510,509],[511,516,517],[517,512,511],[512,517,518],[518,513,512],[513,518,519],[519,514,513],[514,519,520],[520,515,514],[521,522,523],[523,524,521],[524,523,525],[525,526,524],[526,525,527],[527,528,526],[528,527,529],[529,530,528],[522,531,532],[532,523,522],[523,532,533],[533,525,523],[525,533,534],[534,527,525],[527,534,535],[535,529,527],[531,536,537],[537,532,531],[532,537,538],[538,533,532],[533,538,539],[539,534,533],[534,539,540],[540,535,534],[536,541,542],[542,537,536],[537,542,543],[543,538,537],[538,543,544],[544,539,538],[539,544,545],[545,540,539],[546,547,548],[548,549,546],[549,548,550],[550,551,549],[551,550,552],[552,553,551],[553,552,554],[554,555,553],[547,556,557],[557,548,547],[548,557,558],[558,550,548],[550,558,559],[559,552,550],[552,559,560],[560,554,552],[556,561,562],[562,557,556],[557,562,563],[563,558,557],[558,563,564],[564,559,558],[559,564,565],[565,560,559],[561,566,567],[567,562,561],[562,567,568],[568,563,562],[563,568,569],[569,564,563],[564,569,570],[570,565,564],[571,572,573],[573,574,571],[574,573,575],[575,576,574],[576,575,577],[577,578,576],[578,577,579],[579,580,578],[572,581,582],[582,573,572],[573,582,583],[583,575,573],[575,583,584],[584,577,575],[577,584,585],[585,579,577],[581,586,587],[587,582,581],[582,587,588],[588,583,582],[583,588,589],[589,584,583],[584,589,590],[590,585,584],[586,591,592],[592,587,586],[587,592,593],[593,588,587],[588,593,594],[594,589,588],[589,594,595],[595,590,589],[596,597,598],[597,596,599],[599,600,597],[600,599,601],[601,602,600],[602,601,603],[603,604,602],[605,596,606],[596,605,607],[607,599,596],[599,607,608],[608,601,599],[601,608,609],[609,603,601],[610,605,611],[605,610,612],[612,607,605],[607,612,613],[613,608,607],[608,613,614],[614,609,608],[615,610,616],[610,615,617],[617,612,610],[612,617,618],[618,613,612],[613,618,619],[619,614,613],[620,621,622],[621,620,623],[623,624,621],[624,623,625],[625,626,624],[626,625,627],[627,628,626],[629,620,630],[620,629,631],[631,623,620],[623,631,632],[632,625,623],[625,632,633],[633,627,625],[634,629,635],[629,634,636],[636,631,629],[631,636,637],[637,632,631],[632,637,638],[638,633,632],[639,634,640],[634,639,641],[641,636,634],[636,641,642],[642,637,636],[637,642,643],[643,638,637],[644,645,646],[645,644,647],[647,648,645],[648,647,649],[649,650,648],[650,649,651],[651,652,650],[653,644,654],[644,653,655],[655,647,644],[647,655,656],[656,649,647],[649,656,657],[657,651,649],[658,653,659],[653,658,660],[660,655,653],[655,660,661],[661,656,655],[656,661,662],[662,657,656],[663,658,664],[658,663,665],[665,660,658],[660,665,666],[666,661,660],[661,666,667],[667,662,661],[668,669,670],[669,668,671],[671,672,669],[672,671,673],[673,674,672],[674,673,675],[675,676,674],[677,668,678],[668,677,679],[679,671,668],[671,679,680],[680,673,671],[673,680,681],[681,675,673],[682,677,683],[677,682,684],[684,679,677],[679,684,685],[685,680,679],[680,685,686],[686,681,680],[687,682,688],[682,687,689],[689,684,682],[684,689,690],[690,685,684],[685,690,691],[691,686,685],[692,693,694],[694,695,692],[695,694,696],[696,697,695],[697,696,698],[698,699,697],[699,698,700],[700,701,699],[693,702,703],[703,694,693],[694,703,704],[704,696,694],[696,704,705],[705,698,696],[698,705,706],[706,700,698],[702,707,708],[708,703,702],[703,708,709],[709,704,703],[704,709,710],[710,705,704],[705,710,711],[711,706,705],[707,712,713],[713,708,707],[708,713,714],[714,709,708],[709,714,715],[715,710,709],[710,715,716],[716,711,710],[717,718,719],[719,720,717],[720,719,721],[721,722,720],[722,721,723],[723,724,722],[724,723,725],[725,726,724],[718,727,728],[728,719,718],[719,728,729],[729,721,719],[721,729,730],[730,723,721],[723,730,731],[731,725,723],[727,732,733],[733,728,727],[728,733,734],[734,729,728],[729,734,735],[735,730,729],[730,735,736],[736,731,730],[732,737,738],[738,733,732],[733,738,739],[739,734,733],[734,739,740],[740,735,734],[735,740,741],[741,736,735],[742,743,744],[744,745,742],[745,744,746],[746,747,745],[747,746,748],[748,749,747],[749,748,750],[750,751,749],[743,752,753],[753,744,743],[744,753,754],[754,746,744],[746,754,755],[755,748,746],[748,755,756],[756,750,748],[752,757,758],[758,753,752],[753,758,759],[759,754,753],[754,759,760],[760,755,754],[755,760,761],[761,756,755],[757,762,763],[763,758,757],[758,763,764],[764,759,758],[759,764,765],[765,760,759],[760,765,766],[766,761,760],[767,768,769],[769,770,767],[770,769,771],[771,772,770],[772,771,773],[773,774,772],[774,773,775],[775,776,774],[768,777,778],[778,769,768],[769,778,779],[779,771,769],[771,779,780],[780,773,771],[773,780,781],[781,775,773],[777,782,783],[783,778,777],[778,783,784],[784,779,778],[779,784,785],[785,780,779],[780,785,786],[786,781,780],[782,787,788],[788,783,782],[783,788,789],[789,784,783],[784,789,790],[790,785,784],[785,790,791],[791,786,785]]}}]); \ No newline at end of file diff --git a/_next/static/chunks/73.c38a93640c1ff80d.js b/_next/static/chunks/73.c38a93640c1ff80d.js deleted file mode 100644 index 433731db..00000000 --- a/_next/static/chunks/73.c38a93640c1ff80d.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[73],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var i=t(5893),r=t(9008),a=t.n(r),o=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),r=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let a=t(4631);n=a(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,i.jsx)("div",{...t,children:(0,i.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),l=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),p=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[b,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(r[0].name),c&&l.current)for(l.current.appendChild(c.domElement);c.__controllers.length>0;)c.__controllers[0].remove();d&&f.current&&(d.dom.style.position="absolute",d.showPanel(1),f.current.appendChild(d.dom));let t={active:!0},i=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:c,stats:d});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(s){console.error(s),h(s)}return i},[]),(0,i.jsxs)("main",{children:[(0,i.jsxs)(a(),{children:[(0,i.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,i.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,i.jsx)("meta",{name:"description",content:e.description}),(0,i.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)("h1",{children:e.name}),(0,i.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,i.jsx)("p",{children:e.description}),g?(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,i.jsx)("p",{children:"".concat(g)})]}):null]}),(0,i.jsxs)("div",{className:u().canvasContainer,children:[(0,i.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,i.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,i.jsx)("canvas",{ref:n})]}),(0,i.jsxs)("div",{children:[(0,i.jsx)("nav",{className:u().sourceFileNav,children:(0,i.jsx)("ul",{children:r.map((e,n)=>(0,i.jsx)("li",{children:(0,i.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){v(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,i.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":b==e.name},n))]})]})},f=e=>(0,i.jsx)(c,{...e});function d(e,n){if(!e)throw Error(n)}},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return r},q:function(){return o}});var i=t(6416);function r(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[r,a,o]=n,s=e[r],l=e[a],u=e[o],c=i.R3.subtract(l,s),f=i.R3.subtract(u,s);i.R3.normalize(c,c),i.R3.normalize(f,f);let d=i.R3.cross(c,f);i.R3.add(t[r],d,t[r]),i.R3.add(t[a],d,t[a]),i.R3.add(t[o],d,t[o])}),t.forEach(e=>{i.R3.normalize(e,e)}),t}let a={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=a[n],i=e.map(()=>[0,0]),r=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{i[n][0]=e[t[0]],i[n][1]=e[t[1]],r[0]=Math.min(e[t[0]],r[0]),r[1]=Math.min(e[t[1]],r[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),i.forEach(e=>{e[0]=(e[0]-r[0])/(o[0]-r[0]),e[1]=(e[1]-r[1])/(o[1]-r[1])}),i}},3073:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return p}});var i=t(6416),r=t(5671),a=t(8748),o=t(9385);let s={positions:a.m,triangles:a.g,normals:[]};s.normals=(0,o.b)(s.positions,s.triangles);var l="struct Uniforms {\n modelViewProjectionMatrix: mat4x4,\n};\n\n@binding(0) @group(0) var uniforms: Uniforms;\n\nstruct VertexOutput {\n @builtin(position) position: vec4,\n @location(0) @interpolate(flat) instance: u32\n};\n\n@vertex\nfn main_vs(@location(0) position: vec4, @builtin(instance_index) instance: u32) -> VertexOutput {\n var output: VertexOutput;\n\n // distribute instances into a staggered 4x4 grid\n const gridWidth = 125.0;\n const cellSize = gridWidth / 4.0;\n let row = instance / 2u;\n let col = instance % 2u;\n\n let xOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 * cellSize * f32(col) + f32(row % 2u != 0u) * cellSize;\n let zOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 + f32(row) * cellSize;\n\n let offsetPos = vec4(position.x + xOffset, position.y, position.z + zOffset, position.w);\n\n output.position = uniforms.modelViewProjectionMatrix * offsetPos;\n output.instance = instance;\n return output;\n}\n\n@fragment\nfn main_fs(@location(0) @interpolate(flat) instance: u32) -> @location(0) vec4 {\n const colors = array,6>(\n vec3(1.0, 0.0, 0.0),\n vec3(0.0, 1.0, 0.0),\n vec3(0.0, 0.0, 1.0),\n vec3(1.0, 0.0, 1.0),\n vec3(1.0, 1.0, 0.0),\n vec3(0.0, 1.0, 1.0),\n );\n\n return vec4(colors[instance % 6u], 1.0);\n}",u="struct Uniforms {\n modelViewProjectionMatrix: mat4x4,\n maxStorableFragments: u32,\n targetWidth: u32,\n};\n\nstruct SliceInfo {\n sliceStartY: i32\n};\n\nstruct Heads {\n numFragments: atomic,\n data: array>\n};\n\nstruct LinkedListElement {\n color: vec4,\n depth: f32,\n next: u32\n};\n\nstruct LinkedList {\n data: array\n};\n\n@binding(0) @group(0) var uniforms: Uniforms;\n@binding(1) @group(0) var heads: Heads;\n@binding(2) @group(0) var linkedList: LinkedList;\n@binding(3) @group(0) var opaqueDepthTexture: texture_depth_2d;\n@binding(4) @group(0) var sliceInfo: SliceInfo;\n\nstruct VertexOutput {\n @builtin(position) position: vec4,\n @location(0) @interpolate(flat) instance: u32\n};\n\n@vertex\nfn main_vs(@location(0) position: vec4, @builtin(instance_index) instance: u32) -> VertexOutput {\n var output: VertexOutput;\n\n // distribute instances into a staggered 4x4 grid\n const gridWidth = 125.0;\n const cellSize = gridWidth / 4.0;\n let row = instance / 2u;\n let col = instance % 2u;\n\n let xOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 * cellSize * f32(col) + f32(row % 2u == 0u) * cellSize;\n let zOffset = -gridWidth / 2.0 + cellSize / 2.0 + 2.0 + f32(row) * cellSize;\n\n let offsetPos = vec4(position.x + xOffset, position.y, position.z + zOffset, position.w);\n\n output.position = uniforms.modelViewProjectionMatrix * offsetPos;\n output.instance = instance;\n\n return output;\n}\n\n@fragment\nfn main_fs(@builtin(position) position: vec4, @location(0) @interpolate(flat) instance: u32) {\n const colors = array,6>(\n vec3(1.0, 0.0, 0.0),\n vec3(0.0, 1.0, 0.0),\n vec3(0.0, 0.0, 1.0),\n vec3(1.0, 0.0, 1.0),\n vec3(1.0, 1.0, 0.0),\n vec3(0.0, 1.0, 1.0),\n );\n\n let fragCoords = vec2(position.xy);\n let opaqueDepth = textureLoad(opaqueDepthTexture, fragCoords, 0);\n\n // reject fragments behind opaque objects\n if position.z >= opaqueDepth {\n discard;\n }\n\n // The index in the heads buffer corresponding to the head data for the fragment at\n // the current location.\n let headsIndex = u32(fragCoords.y - sliceInfo.sliceStartY) * uniforms.targetWidth + u32(fragCoords.x);\n\n // The index in the linkedList buffer at which to store the new fragment\n let fragIndex = atomicAdd(&heads.numFragments, 1u);\n\n // If we run out of space to store the fragments, we just lose them\n if fragIndex < uniforms.maxStorableFragments {\n let lastHead = atomicExchange(&heads.data[headsIndex], fragIndex);\n linkedList.data[fragIndex].depth = position.z;\n linkedList.data[fragIndex].next = lastHead;\n linkedList.data[fragIndex].color = vec4(colors[(instance + 3u) % 6u], 0.3);\n }\n}",c="struct Uniforms {\n modelViewProjectionMatrix: mat4x4,\n maxStorableFragments: u32,\n targetWidth: u32,\n};\n\nstruct SliceInfo {\n sliceStartY: i32\n};\n\nstruct Heads {\n numFragments: u32,\n data: array\n};\n\nstruct LinkedListElement {\n color: vec4,\n depth: f32,\n next: u32\n};\n\nstruct LinkedList {\n data: array\n};\n\n@binding(0) @group(0) var uniforms: Uniforms;\n@binding(1) @group(0) var heads: Heads;\n@binding(2) @group(0) var linkedList: LinkedList;\n@binding(3) @group(0) var sliceInfo: SliceInfo;\n\n// Output a full screen quad\n@vertex\nfn main_vs(@builtin(vertex_index) vertIndex: u32) -> @builtin(position) vec4 {\n const position = array, 6>(\n vec2(-1.0, -1.0),\n vec2(1.0, -1.0),\n vec2(1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(1.0, 1.0),\n vec2(-1.0, 1.0),\n );\n \n return vec4(position[vertIndex], 0.0, 1.0);\n}\n\n@fragment\nfn main_fs(@builtin(position) position: vec4) -> @location(0) vec4 {\n let fragCoords = vec2(position.xy);\n let headsIndex = u32(fragCoords.y - sliceInfo.sliceStartY) * uniforms.targetWidth + u32(fragCoords.x);\n\n // The maximum layers we can process for any pixel\n const maxLayers = 24u;\n\n var layers: array;\n\n var numLayers = 0u;\n var elementIndex = heads.data[headsIndex];\n\n // copy the list elements into an array up to the maximum amount of layers\n while elementIndex != 0xFFFFFFFFu && numLayers < maxLayers {\n layers[numLayers] = linkedList.data[elementIndex];\n numLayers++;\n elementIndex = linkedList.data[elementIndex].next;\n }\n\n if numLayers == 0u {\n discard;\n }\n \n // sort the fragments by depth\n for (var i = 1u; i < numLayers; i++) {\n let toInsert = layers[i];\n var j = i;\n\n while j > 0u && toInsert.depth > layers[j - 1u].depth {\n layers[j] = layers[j - 1u];\n j--;\n }\n\n layers[j] = toInsert;\n }\n\n // pre-multiply alpha for the first layer\n var color = vec4(layers[0].color.a * layers[0].color.rgb, layers[0].color.a);\n\n // blend the remaining layers\n for (var i = 1u; i < numLayers; i++) {\n let mixed = mix(color.rgb, layers[i].color.rgb, layers[i].color.aaa);\n color = vec4(mixed, color.a);\n }\n\n return color;\n}",f="src/sample/a-buffer/main.ts";let d=async e=>{let{canvas:n,pageState:t,gui:r}=e,a=await navigator.gpu.requestAdapter(),o=await a.requestDevice();if(!t.active)return;let f=n.getContext("webgpu"),d=navigator.gpu.getPreferredCanvasFormat();f.configure({device:o,format:d,alphaMode:"premultiplied"});let m=new URLSearchParams(window.location.search),p={memoryStrategy:m.get("memoryStrategy")||"multipass"},g=o.createBuffer({size:3*s.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0,label:"vertexBuffer"});{let h=new Float32Array(g.getMappedRange());for(let b=0;b{let e=window.devicePixelRatio||1;"clamp-pixel-ratio"===p.memoryStrategy&&(e=Math.min(window.devicePixelRatio,3)),n.width=n.clientWidth*e,n.height=n.clientHeight*e;let t=o.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,label:"depthTexture"}),r=t.createView({label:"depthTextureView"}),a=5*Float32Array.BYTES_PER_ELEMENT+1*Uint32Array.BYTES_PER_ELEMENT,l=4*n.width*a,u=Math.floor(o.limits.maxStorageBufferBindingSize/l),c=Math.ceil(n.height/u),d=Math.ceil(n.height/c),m=o.createBuffer({size:d*l,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"linkedListBuffer"}),h=o.createBuffer({size:c*o.limits.minUniformBufferOffsetAlignment,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0,label:"sliceInfoBuffer"});{let b=new Int32Array(h.getMappedRange()),v=o.limits.minUniformBufferOffsetAlignment/Int32Array.BYTES_PER_ELEMENT;for(let E=0;E{C=z()};r.add(p,"memoryStrategy",["multipass","clamp-pixel-ratio"]).onFinishChange(N),requestAnimationFrame(function e(){t.active&&(C(),requestAnimationFrame(e))})},m=()=>(0,r.Tl)({name:"A-Buffer",description:"Demonstrates order independent transparency using a per-pixel \n linked-list of translucent fragments. Provides a choice for \n limiting memory usage (when required).",gui:!0,init:d,sources:[{name:f.substring(20),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport { mesh } from '../../meshes/teapot';\n\nimport opaqueWGSL from './opaque.wgsl';\nimport translucentWGSL from './translucent.wgsl';\nimport compositeWGSL from './composite.wgsl';\n\nfunction roundUp(n: number, k: number): number {\n return Math.ceil(n / k) * k;\n}\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const params = new URLSearchParams(window.location.search);\n\n const settings = {\n memoryStrategy: params.get('memoryStrategy') || 'multipass',\n };\n\n // Create the model vertex buffer\n const vertexBuffer = device.createBuffer({\n size: 3 * mesh.positions.length * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n label: 'vertexBuffer',\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], 3 * i);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n label: 'indexBuffer',\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // Uniforms contains:\n // * modelViewProjectionMatrix: mat4x4\n // * maxStorableFragments: u32\n // * targetWidth: u32\n const uniformsSize = roundUp(\n 16 * Float32Array.BYTES_PER_ELEMENT + 2 * Uint32Array.BYTES_PER_ELEMENT,\n 16\n );\n\n const uniformBuffer = device.createBuffer({\n size: uniformsSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n label: 'uniformBuffer',\n });\n\n const opaqueModule = device.createShaderModule({\n code: opaqueWGSL,\n label: 'opaqueModule',\n });\n\n const opaquePipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: opaqueModule,\n entryPoint: 'main_vs',\n buffers: [\n {\n arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,\n attributes: [\n {\n // position\n format: 'float32x3',\n offset: 0,\n shaderLocation: 0,\n },\n ],\n },\n ],\n },\n fragment: {\n module: opaqueModule,\n entryPoint: 'main_fs',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n label: 'opaquePipeline',\n });\n\n const opaquePassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined,\n clearValue: { r: 0, g: 0, b: 0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: undefined,\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n label: 'opaquePassDescriptor',\n };\n\n const opaqueBindGroup = device.createBindGroup({\n layout: opaquePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n size: 16 * Float32Array.BYTES_PER_ELEMENT,\n label: 'modelViewProjection',\n },\n },\n ],\n label: 'opaquePipeline',\n });\n\n const translucentModule = device.createShaderModule({\n code: translucentWGSL,\n label: 'translucentModule',\n });\n\n const translucentBindGroupLayout = device.createBindGroupLayout({\n label: 'translucentBindGroupLayout',\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 3,\n visibility: GPUShaderStage.FRAGMENT,\n texture: { sampleType: 'depth' },\n },\n {\n binding: 4,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n hasDynamicOffset: true,\n },\n },\n ],\n });\n\n const translucentPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [translucentBindGroupLayout],\n label: 'translucentPipelineLayout',\n }),\n vertex: {\n module: translucentModule,\n entryPoint: 'main_vs',\n buffers: [\n {\n arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,\n attributes: [\n {\n format: 'float32x3',\n offset: 0,\n shaderLocation: 0,\n },\n ],\n },\n ],\n },\n fragment: {\n module: translucentModule,\n entryPoint: 'main_fs',\n targets: [\n {\n format: presentationFormat,\n writeMask: 0x0,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n label: 'translucentPipeline',\n });\n\n const translucentPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n loadOp: 'load',\n storeOp: 'store',\n view: undefined,\n },\n ],\n label: 'translucentPassDescriptor',\n };\n\n const compositeModule = device.createShaderModule({\n code: compositeWGSL,\n label: 'compositeModule',\n });\n\n const compositeBindGroupLayout = device.createBindGroupLayout({\n label: 'compositeBindGroupLayout',\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'storage',\n },\n },\n {\n binding: 3,\n visibility: GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n hasDynamicOffset: true,\n },\n },\n ],\n });\n\n const compositePipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [compositeBindGroupLayout],\n label: 'compositePipelineLayout',\n }),\n vertex: {\n module: compositeModule,\n entryPoint: 'main_vs',\n },\n fragment: {\n module: compositeModule,\n entryPoint: 'main_fs',\n targets: [\n {\n format: presentationFormat,\n blend: {\n color: {\n srcFactor: 'one',\n operation: 'add',\n dstFactor: 'one-minus-src-alpha',\n },\n alpha: {},\n },\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n label: 'compositePipeline',\n });\n\n const compositePassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined,\n loadOp: 'load',\n storeOp: 'store',\n },\n ],\n label: 'compositePassDescriptor',\n };\n\n const configure = () => {\n let devicePixelRatio = window.devicePixelRatio || 1;\n\n // The default maximum storage buffer binding size is 128Mib. The amount\n // of memory we need to store transparent fragments depends on the size\n // of the canvas and the average number of layers per fragment we want to\n // support. When the devicePixelRatio is 1, we know that 128Mib is enough\n // to store 4 layers per pixel at 600x600. However, when the device pixel\n // ratio is high enough we will exceed this limit.\n //\n // We provide 2 choices of mitigations to this issue:\n // 1) Clamp the device pixel ratio to a value which we know will not break\n // the limit. The tradeoff here is that the canvas resolution will not\n // match the native resolution and therefore may have a reduction in\n // quality.\n // 2) Break the frame into a series of horizontal slices using the scissor\n // functionality and process a single slice at a time. This limits memory\n // usage because we only need enough memory to process the dimensions\n // of the slice. The tradeoff is the performance reduction due to multiple\n // passes.\n if (settings.memoryStrategy === 'clamp-pixel-ratio') {\n devicePixelRatio = Math.min(window.devicePixelRatio, 3);\n }\n\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage:\n GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n label: 'depthTexture',\n });\n\n const depthTextureView = depthTexture.createView({\n label: 'depthTextureView',\n });\n\n // Determines how much memory is allocated to store linked-list elements\n const averageLayersPerFragment = 4;\n\n // Each element stores\n // * color : vec4\n // * depth : f32\n // * index of next element in the list : u32\n const linkedListElementSize =\n 5 * Float32Array.BYTES_PER_ELEMENT + 1 * Uint32Array.BYTES_PER_ELEMENT;\n\n // We want to keep the linked-list buffer size under the maxStorageBufferBindingSize.\n // Split the frame into enough slices to meet that constraint.\n const bytesPerline =\n canvas.width * averageLayersPerFragment * linkedListElementSize;\n const maxLinesSupported = Math.floor(\n device.limits.maxStorageBufferBindingSize / bytesPerline\n );\n const numSlices = Math.ceil(canvas.height / maxLinesSupported);\n const sliceHeight = Math.ceil(canvas.height / numSlices);\n const linkedListBufferSize = sliceHeight * bytesPerline;\n\n const linkedListBuffer = device.createBuffer({\n size: linkedListBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n label: 'linkedListBuffer',\n });\n\n // To slice up the frame we need to pass the starting fragment y position of the slice.\n // We do this using a uniform buffer with a dynamic offset.\n const sliceInfoBuffer = device.createBuffer({\n size: numSlices * device.limits.minUniformBufferOffsetAlignment,\n usage: GPUBufferUsage.UNIFORM,\n mappedAtCreation: true,\n label: 'sliceInfoBuffer',\n });\n {\n const mapping = new Int32Array(sliceInfoBuffer.getMappedRange());\n\n // This assumes minUniformBufferOffsetAlignment is a multiple of 4\n const stride =\n device.limits.minUniformBufferOffsetAlignment /\n Int32Array.BYTES_PER_ELEMENT;\n for (let i = 0; i < numSlices; ++i) {\n mapping[i * stride] = i * sliceHeight;\n }\n sliceInfoBuffer.unmap();\n }\n\n // `Heads` struct contains the start index of the linked-list of translucent fragments\n // for a given pixel.\n // * numFragments : u32\n // * data : array\n const headsBuffer = device.createBuffer({\n size: (1 + canvas.width * sliceHeight) * Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n label: 'headsBuffer',\n });\n\n const headsInitBuffer = device.createBuffer({\n size: (1 + canvas.width * sliceHeight) * Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.COPY_SRC,\n mappedAtCreation: true,\n label: 'headsInitBuffer',\n });\n {\n const buffer = new Uint32Array(headsInitBuffer.getMappedRange());\n\n for (let i = 0; i < buffer.length; ++i) {\n buffer[i] = 0xffffffff;\n }\n\n headsInitBuffer.unmap();\n }\n\n const translucentBindGroup = device.createBindGroup({\n layout: translucentBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n label: 'uniforms',\n },\n },\n {\n binding: 1,\n resource: {\n buffer: headsBuffer,\n label: 'headsBuffer',\n },\n },\n {\n binding: 2,\n resource: {\n buffer: linkedListBuffer,\n label: 'linkedListBuffer',\n },\n },\n {\n binding: 3,\n resource: depthTextureView,\n },\n {\n binding: 4,\n resource: {\n buffer: sliceInfoBuffer,\n size: device.limits.minUniformBufferOffsetAlignment,\n label: 'sliceInfoBuffer',\n },\n },\n ],\n label: 'translucentBindGroup',\n });\n\n const compositeBindGroup = device.createBindGroup({\n layout: compositePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n label: 'uniforms',\n },\n },\n {\n binding: 1,\n resource: {\n buffer: headsBuffer,\n label: 'headsBuffer',\n },\n },\n {\n binding: 2,\n resource: {\n buffer: linkedListBuffer,\n label: 'linkedListBuffer',\n },\n },\n {\n binding: 3,\n resource: {\n buffer: sliceInfoBuffer,\n size: device.limits.minUniformBufferOffsetAlignment,\n label: 'sliceInfoBuffer',\n },\n },\n ],\n });\n\n opaquePassDescriptor.depthStencilAttachment.view = depthTextureView;\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const aspect = canvas.width / canvas.height;\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n const eyePosition = vec3.fromValues(0, 5, -100);\n\n const rad = Math.PI * (Date.now() / 5000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n return function doDraw() {\n // update the uniform buffer\n {\n const buffer = new ArrayBuffer(uniformBuffer.size);\n\n new Float32Array(buffer).set(getCameraViewProjMatrix());\n new Uint32Array(buffer, 16 * Float32Array.BYTES_PER_ELEMENT).set([\n averageLayersPerFragment * canvas.width * sliceHeight,\n canvas.width,\n ]);\n\n device.queue.writeBuffer(uniformBuffer, 0, buffer);\n }\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n // Draw the opaque objects\n opaquePassDescriptor.colorAttachments[0].view = textureView;\n const opaquePassEncoder =\n commandEncoder.beginRenderPass(opaquePassDescriptor);\n opaquePassEncoder.setPipeline(opaquePipeline);\n opaquePassEncoder.setBindGroup(0, opaqueBindGroup);\n opaquePassEncoder.setVertexBuffer(0, vertexBuffer);\n opaquePassEncoder.setIndexBuffer(indexBuffer, 'uint16');\n opaquePassEncoder.drawIndexed(mesh.triangles.length * 3, 8);\n opaquePassEncoder.end();\n\n for (let slice = 0; slice < numSlices; ++slice) {\n // initialize the heads buffer\n commandEncoder.copyBufferToBuffer(\n headsInitBuffer,\n 0,\n headsBuffer,\n 0,\n headsInitBuffer.size\n );\n\n const scissorX = 0;\n const scissorY = slice * sliceHeight;\n const scissorWidth = canvas.width;\n const scissorHeight =\n Math.min((slice + 1) * sliceHeight, canvas.height) -\n slice * sliceHeight;\n\n // Draw the translucent objects\n translucentPassDescriptor.colorAttachments[0].view = textureView;\n const translucentPassEncoder = commandEncoder.beginRenderPass(\n translucentPassDescriptor\n );\n\n // Set the scissor to only process a horizontal slice of the frame\n translucentPassEncoder.setScissorRect(\n scissorX,\n scissorY,\n scissorWidth,\n scissorHeight\n );\n\n translucentPassEncoder.setPipeline(translucentPipeline);\n translucentPassEncoder.setBindGroup(0, translucentBindGroup, [\n slice * device.limits.minUniformBufferOffsetAlignment,\n ]);\n translucentPassEncoder.setVertexBuffer(0, vertexBuffer);\n translucentPassEncoder.setIndexBuffer(indexBuffer, 'uint16');\n translucentPassEncoder.drawIndexed(mesh.triangles.length * 3, 8);\n translucentPassEncoder.end();\n\n // Composite the opaque and translucent objects\n compositePassDescriptor.colorAttachments[0].view = textureView;\n const compositePassEncoder = commandEncoder.beginRenderPass(\n compositePassDescriptor\n );\n\n // Set the scissor to only process a horizontal slice of the frame\n compositePassEncoder.setScissorRect(\n scissorX,\n scissorY,\n scissorWidth,\n scissorHeight\n );\n\n compositePassEncoder.setPipeline(compositePipeline);\n compositePassEncoder.setBindGroup(0, compositeBindGroup, [\n slice * device.limits.minUniformBufferOffsetAlignment,\n ]);\n compositePassEncoder.draw(6);\n compositePassEncoder.end();\n }\n\n device.queue.submit([commandEncoder.finish()]);\n };\n };\n\n let doDraw = configure();\n\n const updateSettings = () => {\n doDraw = configure();\n };\n\n gui\n .add(settings, 'memoryStrategy', ['multipass', 'clamp-pixel-ratio'])\n .onFinishChange(updateSettings);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n doDraw();\n\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst ABuffer: () => JSX.Element = () =>\n makeSample({\n name: 'A-Buffer',\n description: `Demonstrates order independent transparency using a per-pixel \n linked-list of translucent fragments. Provides a choice for \n limiting memory usage (when required).`,\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: 'opaque.wsgl',\n contents: opaqueWGSL,\n },\n {\n name: 'translucent.wsgl',\n contents: translucentWGSL,\n },\n {\n name: 'composite.wsgl',\n contents: compositeWGSL,\n },\n ],\n filename: __filename,\n });\n\nexport default ABuffer;\n"},{name:"opaque.wsgl",contents:l},{name:"translucent.wsgl",contents:u},{name:"composite.wsgl",contents:c}],filename:f});var p=m},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},8748:function(e,n){n.m=[[5.929688,4.125,0],[5.387188,4.125,2.7475],[5.2971,4.494141,2.70917],[5.832031,4.494141,0],[5.401602,4.617188,2.753633],[5.945313,4.617188,0],[5.614209,4.494141,2.844092],[6.175781,4.494141,0],[5.848437,4.125,2.94375],[6.429688,4.125,0],[3.899688,4.125,4.97],[3.830352,4.494141,4.900664],[3.910782,4.617188,4.981094],[4.074414,4.494141,5.144727],[4.254687,4.125,5.325],[1.677188,4.125,6.4575],[1.638858,4.494141,6.367412],[1.68332,4.617188,6.471914],[1.77378,4.494141,6.684522],[1.873438,4.125,6.91875],[-1.070312,4.125,7],[-1.070312,4.494141,6.902344],[-1.070312,4.617188,7.015625],[-1.070312,4.494141,7.246094],[-1.070312,4.125,7.5],[-1.070312,4.125,7],[-4.007656,4.125,6.4575],[-3.859572,4.494141,6.367412],[-1.070312,4.494141,6.902344],[-3.847676,4.617188,6.471914],[-1.070312,4.617188,7.015625],[-3.917371,4.494141,6.684522],[-1.070312,4.494141,7.246094],[-4.014062,4.125,6.91875],[-1.070312,4.125,7.5],[-6.209063,4.125,4.97],[-6.042168,4.494141,4.900664],[-6.0725,4.617188,4.981094],[-6.217675,4.494141,5.144727],[-6.395312,4.125,5.325],[-7.591093,4.125,2.7475],[-7.464421,4.494141,2.70917],[-7.550137,4.617188,2.753633],[-7.755822,4.494141,2.844092],[-7.989062,4.125,2.94375],[-8.070313,4.125,0],[-7.972656,4.494141,0],[-8.085938,4.617188,0],[-8.316406,4.494141,0],[-8.570313,4.125,0],[-8.070313,4.125,0],[-7.527812,4.125,-2.7475],[-7.437724,4.494141,-2.70917],[-7.972656,4.494141,0],[-7.542227,4.617188,-2.753633],[-8.085938,4.617188,0],[-7.754834,4.494141,-2.844092],[-8.316406,4.494141,0],[-7.989062,4.125,-2.94375],[-8.570313,4.125,0],[-6.040312,4.125,-4.97],[-5.970977,4.494141,-4.900664],[-6.051406,4.617188,-4.981094],[-6.215039,4.494141,-5.144727],[-6.395312,4.125,-5.325],[-3.817812,4.125,-6.4575],[-3.779482,4.494141,-6.367412],[-3.823945,4.617188,-6.471914],[-3.914404,4.494141,-6.684522],[-4.014062,4.125,-6.91875],[-1.070312,4.125,-7],[-1.070312,4.494141,-6.902344],[-1.070312,4.617188,-7.015625],[-1.070312,4.494141,-7.246094],[-1.070312,4.125,-7.5],[-1.070312,4.125,-7],[1.677188,4.125,-6.4575],[1.638858,4.494141,-6.367412],[-1.070312,4.494141,-6.902344],[1.68332,4.617188,-6.471914],[-1.070312,4.617188,-7.015625],[1.77378,4.494141,-6.684522],[-1.070312,4.494141,-7.246094],[1.873438,4.125,-6.91875],[-1.070312,4.125,-7.5],[3.899688,4.125,-4.97],[3.830352,4.494141,-4.900664],[3.910782,4.617188,-4.981094],[4.074414,4.494141,-5.144727],[4.254687,4.125,-5.325],[5.387188,4.125,-2.7475],[5.2971,4.494141,-2.70917],[5.401602,4.617188,-2.753633],[5.614209,4.494141,-2.844092],[5.848437,4.125,-2.94375],[5.929688,4.125,0],[5.832031,4.494141,0],[5.945313,4.617188,0],[6.175781,4.494141,0],[6.429688,4.125,0],[6.429688,4.125,0],[5.848437,4.125,2.94375],[6.695264,2.162109,3.304053],[7.347656,2.162109,0],[7.433985,.234375,3.61836],[8.148438,.234375,0],[7.956494,-1.623047,3.840674],[8.714844,-1.623047,0],[8.154688,-3.375,3.925],[8.929688,-3.375,0],[4.254687,4.125,5.325],[4.906446,2.162109,5.976758],[5.475,.234375,6.545312],[5.877149,-1.623047,6.947461],[6.029688,-3.375,7.1],[1.873438,4.125,6.91875],[2.23374,2.162109,7.765576],[2.548047,.234375,8.504297],[2.770362,-1.623047,9.026807],[2.854688,-3.375,9.225],[-1.070312,4.125,7.5],[-1.070312,2.162109,8.417969],[-1.070312,.234375,9.21875],[-1.070312,-1.623047,9.785156],[-1.070312,-3.375,10],[-1.070312,4.125,7.5],[-4.014062,4.125,6.91875],[-4.374365,2.162109,7.765576],[-1.070312,2.162109,8.417969],[-4.688672,.234375,8.504297],[-1.070312,.234375,9.21875],[-4.910986,-1.623047,9.026807],[-1.070312,-1.623047,9.785156],[-4.995313,-3.375,9.225],[-1.070312,-3.375,10],[-6.395312,4.125,5.325],[-7.047071,2.162109,5.976758],[-7.615624,.234375,6.545312],[-8.017773,-1.623047,6.947461],[-8.170312,-3.375,7.1],[-7.989062,4.125,2.94375],[-8.835889,2.162109,3.304053],[-9.57461,.234375,3.61836],[-10.097119,-1.623047,3.840674],[-10.295313,-3.375,3.925],[-8.570313,4.125,0],[-9.488281,2.162109,0],[-10.289063,.234375,0],[-10.855469,-1.623047,0],[-11.070313,-3.375,0],[-8.570313,4.125,0],[-7.989062,4.125,-2.94375],[-8.835889,2.162109,-3.304053],[-9.488281,2.162109,0],[-9.57461,.234375,-3.61836],[-10.289063,.234375,0],[-10.097119,-1.623047,-3.840674],[-10.855469,-1.623047,0],[-10.295313,-3.375,-3.925],[-11.070313,-3.375,0],[-6.395312,4.125,-5.325],[-7.047071,2.162109,-5.976758],[-7.615624,.234375,-6.545312],[-8.017773,-1.623047,-6.947461],[-8.170312,-3.375,-7.1],[-4.014062,4.125,-6.91875],[-4.374365,2.162109,-7.765576],[-4.688672,.234375,-8.504297],[-4.910986,-1.623047,-9.026807],[-4.995313,-3.375,-9.225],[-1.070312,4.125,-7.5],[-1.070312,2.162109,-8.417969],[-1.070312,.234375,-9.21875],[-1.070312,-1.623047,-9.785156],[-1.070312,-3.375,-10],[-1.070312,4.125,-7.5],[1.873438,4.125,-6.91875],[2.23374,2.162109,-7.765576],[-1.070312,2.162109,-8.417969],[2.548047,.234375,-8.504297],[-1.070312,.234375,-9.21875],[2.770362,-1.623047,-9.026807],[-1.070312,-1.623047,-9.785156],[2.854688,-3.375,-9.225],[-1.070312,-3.375,-10],[4.254687,4.125,-5.325],[4.906446,2.162109,-5.976758],[5.475,.234375,-6.545312],[5.877149,-1.623047,-6.947461],[6.029688,-3.375,-7.1],[5.848437,4.125,-2.94375],[6.695264,2.162109,-3.304053],[7.433985,.234375,-3.61836],[7.956494,-1.623047,-3.840674],[8.154688,-3.375,-3.925],[6.429688,4.125,0],[7.347656,2.162109,0],[8.148438,.234375,0],[8.714844,-1.623047,0],[8.929688,-3.375,0],[8.929688,-3.375,0],[8.154688,-3.375,3.925],[7.794336,-4.857422,3.77168],[8.539063,-4.857422,0],[7.001562,-5.953125,3.434375],[7.679688,-5.953125,0],[6.208789,-6.697266,3.09707],[6.820313,-6.697266,0],[5.848437,-7.125,2.94375],[6.429688,-7.125,0],[6.029688,-3.375,7.1],[5.752343,-4.857422,6.822656],[5.142187,-5.953125,6.2125],[4.532031,-6.697266,5.602344],[4.254687,-7.125,5.325],[2.854688,-3.375,9.225],[2.701367,-4.857422,8.864649],[2.364063,-5.953125,8.071875],[2.026758,-6.697266,7.279101],[1.873438,-7.125,6.91875],[-1.070312,-3.375,10],[-1.070312,-4.857422,9.609375],[-1.070312,-5.953125,8.75],[-1.070312,-6.697266,7.890625],[-1.070312,-7.125,7.5],[-1.070312,-3.375,10],[-4.995313,-3.375,9.225],[-4.841992,-4.857422,8.864649],[-1.070312,-4.857422,9.609375],[-4.504687,-5.953125,8.071875],[-1.070312,-5.953125,8.75],[-4.167383,-6.697266,7.279101],[-1.070312,-6.697266,7.890625],[-4.014062,-7.125,6.91875],[-1.070312,-7.125,7.5],[-8.170312,-3.375,7.1],[-7.892968,-4.857422,6.822656],[-7.282812,-5.953125,6.2125],[-6.672656,-6.697266,5.602344],[-6.395312,-7.125,5.325],[-10.295313,-3.375,3.925],[-9.934961,-4.857422,3.77168],[-9.142187,-5.953125,3.434375],[-8.349414,-6.697266,3.09707],[-7.989062,-7.125,2.94375],[-11.070313,-3.375,0],[-10.679688,-4.857422,0],[-9.820313,-5.953125,0],[-8.960938,-6.697266,0],[-8.570313,-7.125,0],[-11.070313,-3.375,0],[-10.295313,-3.375,-3.925],[-9.934961,-4.857422,-3.77168],[-10.679688,-4.857422,0],[-9.142187,-5.953125,-3.434375],[-9.820313,-5.953125,0],[-8.349414,-6.697266,-3.09707],[-8.960938,-6.697266,0],[-7.989062,-7.125,-2.94375],[-8.570313,-7.125,0],[-8.170312,-3.375,-7.1],[-7.892968,-4.857422,-6.822656],[-7.282812,-5.953125,-6.2125],[-6.672656,-6.697266,-5.602344],[-6.395312,-7.125,-5.325],[-4.995313,-3.375,-9.225],[-4.841992,-4.857422,-8.864649],[-4.504687,-5.953125,-8.071875],[-4.167383,-6.697266,-7.279101],[-4.014062,-7.125,-6.91875],[-1.070312,-3.375,-10],[-1.070312,-4.857422,-9.609375],[-1.070312,-5.953125,-8.75],[-1.070312,-6.697266,-7.890625],[-1.070312,-7.125,-7.5],[-1.070312,-3.375,-10],[2.854688,-3.375,-9.225],[2.701367,-4.857422,-8.864649],[-1.070312,-4.857422,-9.609375],[2.364063,-5.953125,-8.071875],[-1.070312,-5.953125,-8.75],[2.026758,-6.697266,-7.279101],[-1.070312,-6.697266,-7.890625],[1.873438,-7.125,-6.91875],[-1.070312,-7.125,-7.5],[6.029688,-3.375,-7.1],[5.752343,-4.857422,-6.822656],[5.142187,-5.953125,-6.2125],[4.532031,-6.697266,-5.602344],[4.254687,-7.125,-5.325],[8.154688,-3.375,-3.925],[7.794336,-4.857422,-3.77168],[7.001562,-5.953125,-3.434375],[6.208789,-6.697266,-3.09707],[5.848437,-7.125,-2.94375],[8.929688,-3.375,0],[8.539063,-4.857422,0],[7.679688,-5.953125,0],[6.820313,-6.697266,0],[6.429688,-7.125,0],[6.429688,-7.125,0],[5.848437,-7.125,2.94375],[5.691685,-7.400391,2.877056],[6.259766,-7.400391,0],[4.853868,-7.640625,2.520586],[5.351563,-7.640625,0],[2.783648,-7.810547,1.639761],[3.107422,-7.810547,0],[-1.070312,-7.875,0],[4.254687,-7.125,5.325],[4.134043,-7.400391,5.204355],[3.489219,-7.640625,4.559531],[1.895879,-7.810547,2.966191],[-1.070312,-7.875,0],[1.873438,-7.125,6.91875],[1.806743,-7.400391,6.761997],[1.450274,-7.640625,5.92418],[.569448,-7.810547,3.85396],[-1.070312,-7.875,0],[-1.070312,-7.125,7.5],[-1.070312,-7.400391,7.330078],[-1.070312,-7.640625,6.421875],[-1.070312,-7.810547,4.177734],[-1.070312,-7.875,0],[-1.070312,-7.125,7.5],[-4.014062,-7.125,6.91875],[-3.947368,-7.400391,6.761997],[-1.070312,-7.400391,7.330078],[-3.590898,-7.640625,5.92418],[-1.070312,-7.640625,6.421875],[-2.710073,-7.810547,3.85396],[-1.070312,-7.810547,4.177734],[-1.070312,-7.875,0],[-6.395312,-7.125,5.325],[-6.274668,-7.400391,5.204355],[-5.629844,-7.640625,4.559531],[-4.036504,-7.810547,2.966191],[-1.070312,-7.875,0],[-7.989062,-7.125,2.94375],[-7.832309,-7.400391,2.877056],[-6.994492,-7.640625,2.520586],[-4.924272,-7.810547,1.639761],[-1.070312,-7.875,0],[-8.570313,-7.125,0],[-8.400391,-7.400391,0],[-7.492188,-7.640625,0],[-5.248047,-7.810547,0],[-1.070312,-7.875,0],[-8.570313,-7.125,0],[-7.989062,-7.125,-2.94375],[-7.832309,-7.400391,-2.877056],[-8.400391,-7.400391,0],[-6.994492,-7.640625,-2.520586],[-7.492188,-7.640625,0],[-4.924272,-7.810547,-1.639761],[-5.248047,-7.810547,0],[-1.070312,-7.875,0],[-6.395312,-7.125,-5.325],[-6.274668,-7.400391,-5.204355],[-5.629844,-7.640625,-4.559531],[-4.036504,-7.810547,-2.966191],[-1.070312,-7.875,0],[-4.014062,-7.125,-6.91875],[-3.947368,-7.400391,-6.761997],[-3.590898,-7.640625,-5.92418],[-2.710073,-7.810547,-3.85396],[-1.070312,-7.875,0],[-1.070312,-7.125,-7.5],[-1.070312,-7.400391,-7.330078],[-1.070312,-7.640625,-6.421875],[-1.070312,-7.810547,-4.177734],[-1.070312,-7.875,0],[-1.070312,-7.125,-7.5],[1.873438,-7.125,-6.91875],[1.806743,-7.400391,-6.761997],[-1.070312,-7.400391,-7.330078],[1.450274,-7.640625,-5.92418],[-1.070312,-7.640625,-6.421875],[.569448,-7.810547,-3.85396],[-1.070312,-7.810547,-4.177734],[-1.070312,-7.875,0],[4.254687,-7.125,-5.325],[4.134043,-7.400391,-5.204355],[3.489219,-7.640625,-4.559531],[1.895879,-7.810547,-2.966191],[-1.070312,-7.875,0],[5.848437,-7.125,-2.94375],[5.691685,-7.400391,-2.877056],[4.853868,-7.640625,-2.520586],[2.783648,-7.810547,-1.639761],[-1.070312,-7.875,0],[6.429688,-7.125,0],[6.259766,-7.400391,0],[5.351563,-7.640625,0],[3.107422,-7.810547,0],[-1.070312,-7.875,0],[-9.070313,2.25,0],[-8.992188,2.425781,.84375],[-11.47583,2.405457,.84375],[-11.40625,2.232422,0],[-13.298828,2.263184,.84375],[-13.132813,2.109375,0],[-14.421631,1.877014,.84375],[-14.203125,1.775391,0],[-14.804688,1.125,.84375],[-14.570313,1.125,0],[-8.820313,2.8125,1.125],[-11.628906,2.786134,1.125],[-13.664063,2.601563,1.125],[-14.902344,2.100586,1.125],[-15.320313,1.125,1.125],[-8.648438,3.199219,.84375],[-11.781982,3.166809,.84375],[-14.029297,2.939941,.84375],[-15.383057,2.324158,.84375],[-15.835938,1.125,.84375],[-8.570313,3.375,0],[-11.851563,3.339844,0],[-14.195313,3.09375,0],[-15.601563,2.425781,0],[-16.070313,1.125,0],[-8.570313,3.375,0],[-8.648438,3.199219,-.84375],[-11.781982,3.166809,-.84375],[-11.851563,3.339844,0],[-14.029297,2.939941,-.84375],[-14.195313,3.09375,0],[-15.383057,2.324158,-.84375],[-15.601563,2.425781,0],[-15.835938,1.125,-.84375],[-16.070313,1.125,0],[-8.820313,2.8125,-1.125],[-11.628906,2.786134,-1.125],[-13.664063,2.601563,-1.125],[-14.902344,2.100586,-1.125],[-15.320313,1.125,-1.125],[-8.992188,2.425781,-.84375],[-11.47583,2.405457,-.84375],[-13.298828,2.263184,-.84375],[-14.421631,1.877014,-.84375],[-14.804688,1.125,-.84375],[-9.070313,2.25,0],[-11.40625,2.232422,0],[-13.132813,2.109375,0],[-14.203125,1.775391,0],[-14.570313,1.125,0],[-14.570313,1.125,0],[-14.804688,1.125,.84375],[-14.588013,.00705,.84375],[-14.375,.105469,0],[-13.90918,-1.275146,.84375],[-13.757813,-1.125,0],[-12.724976,-2.540863,.84375],[-12.671875,-2.355469,0],[-10.992188,-3.609375,.84375],[-11.070313,-3.375,0],[-15.320313,1.125,1.125],[-15.056641,-.209473,1.125],[-14.242188,-1.605469,1.125],[-12.841797,-2.94873,1.125],[-10.820313,-4.125,1.125],[-15.835938,1.125,.84375],[-15.525269,-.425995,.84375],[-14.575195,-1.935791,.84375],[-12.958618,-3.356598,.84375],[-10.648438,-4.640625,.84375],[-16.070313,1.125,0],[-15.738281,-.524414,0],[-14.726563,-2.085938,0],[-13.011719,-3.541992,0],[-10.570313,-4.875,0],[-16.070313,1.125,0],[-15.835938,1.125,-.84375],[-15.525269,-.425995,-.84375],[-15.738281,-.524414,0],[-14.575195,-1.935791,-.84375],[-14.726563,-2.085938,0],[-12.958618,-3.356598,-.84375],[-13.011719,-3.541992,0],[-10.648438,-4.640625,-.84375],[-10.570313,-4.875,0],[-15.320313,1.125,-1.125],[-15.056641,-.209473,-1.125],[-14.242188,-1.605469,-1.125],[-12.841797,-2.94873,-1.125],[-10.820313,-4.125,-1.125],[-14.804688,1.125,-.84375],[-14.588013,.00705,-.84375],[-13.90918,-1.275146,-.84375],[-12.724976,-2.540863,-.84375],[-10.992188,-3.609375,-.84375],[-14.570313,1.125,0],[-14.375,.105469,0],[-13.757813,-1.125,0],[-12.671875,-2.355469,0],[-11.070313,-3.375,0],[7.429688,-.75,0],[7.429688,-1.394531,1.85625],[10.01123,-.677124,1.676074],[9.828125,-.199219,0],[11.101563,.84668,1.279688],[10.867188,1.125,0],[11.723145,2.629761,.883301],[11.4375,2.730469,0],[12.898438,4.125,.703125],[12.429688,4.125,0],[7.429688,-2.8125,2.475],[10.414063,-1.728516,2.234766],[11.617188,.234375,1.70625],[12.351563,2.408203,1.177734],[13.929688,4.125,.9375],[7.429688,-4.230469,1.85625],[10.816895,-2.779907,1.676074],[12.132813,-.37793,1.279688],[12.97998,2.186646,.883301],[14.960938,4.125,.703125],[7.429688,-4.875,0],[11,-3.257813,0],[12.367188,-.65625,0],[13.265625,2.085938,0],[15.429688,4.125,0],[7.429688,-4.875,0],[7.429688,-4.230469,-1.85625],[10.816895,-2.779907,-1.676074],[11,-3.257813,0],[12.132813,-.37793,-1.279688],[12.367188,-.65625,0],[12.97998,2.186646,-.883301],[13.265625,2.085938,0],[14.960938,4.125,-.703125],[15.429688,4.125,0],[7.429688,-2.8125,-2.475],[10.414063,-1.728516,-2.234766],[11.617188,.234375,-1.70625],[12.351563,2.408203,-1.177734],[13.929688,4.125,-.9375],[7.429688,-1.394531,-1.85625],[10.01123,-.677124,-1.676074],[11.101563,.84668,-1.279688],[11.723145,2.629761,-.883301],[12.898438,4.125,-.703125],[7.429688,-.75,0],[9.828125,-.199219,0],[10.867188,1.125,0],[11.4375,2.730469,0],[12.429688,4.125,0],[12.429688,4.125,0],[12.898438,4.125,.703125],[13.291077,4.346237,.65918],[12.789063,4.335938,0],[13.525879,4.422729,.5625],[13.054688,4.40625,0],[13.532898,4.350357,.46582],[13.132813,4.335938,0],[13.242188,4.125,.421875],[12.929688,4.125,0],[13.929688,4.125,.9375],[14.395508,4.368896,.878906],[14.5625,4.458984,.75],[14.413086,4.38208,.621094],[13.929688,4.125,.5625],[14.960938,4.125,.703125],[15.499939,4.391556,.65918],[15.599121,4.495239,.5625],[15.293274,4.413804,.46582],[14.617188,4.125,.421875],[15.429688,4.125,0],[16.001953,4.401855,0],[16.070313,4.511719,0],[15.693359,4.428224,0],[14.929688,4.125,0],[15.429688,4.125,0],[14.960938,4.125,-.703125],[15.499939,4.391556,-.65918],[16.001953,4.401855,0],[15.599121,4.495239,-.5625],[16.070313,4.511719,0],[15.293274,4.413804,-.46582],[15.693359,4.428224,0],[14.617188,4.125,-.421875],[14.929688,4.125,0],[13.929688,4.125,-.9375],[14.395508,4.368896,-.878906],[14.5625,4.458984,-.75],[14.413086,4.38208,-.621094],[13.929688,4.125,-.5625],[12.898438,4.125,-.703125],[13.291077,4.346237,-.65918],[13.525879,4.422729,-.5625],[13.532898,4.350357,-.46582],[13.242188,4.125,-.421875],[12.429688,4.125,0],[12.789063,4.335938,0],[13.054688,4.40625,0],[13.132813,4.335938,0],[12.929688,4.125,0],[.501414,7.628906,.670256],[.632813,7.628906,0],[-1.070312,7.875,0],[.429278,7.03125,.639395],[.554688,7.03125,0],[-.162029,6.292969,.38696],[-.085937,6.292969,0],[-.147812,5.625,.3925],[-.070312,5.625,0],[.140489,7.628906,1.210801],[-1.070312,7.875,0],[.084844,7.03125,1.155156],[-.370879,6.292969,.699434],[-.360312,5.625,.71],[-.400056,7.628906,1.571726],[-1.070312,7.875,0],[-.430918,7.03125,1.49959],[-.683352,6.292969,.908284],[-.677812,5.625,.9225],[-1.070312,7.628906,1.703125],[-1.070312,7.875,0],[-1.070312,7.03125,1.625],[-1.070312,6.292969,.984375],[-1.070312,5.625,1],[-1.740569,7.628906,1.571726],[-1.070312,7.628906,1.703125],[-1.070312,7.875,0],[-1.709707,7.03125,1.49959],[-1.070312,7.03125,1.625],[-1.457273,6.292969,.908284],[-1.070312,6.292969,.984375],[-1.462812,5.625,.9225],[-1.070312,5.625,1],[-2.281113,7.628906,1.210801],[-1.070312,7.875,0],[-2.225469,7.03125,1.155156],[-1.769746,6.292969,.699434],[-1.780312,5.625,.71],[-2.642038,7.628906,.670256],[-1.070312,7.875,0],[-2.569902,7.03125,.639395],[-1.978596,6.292969,.38696],[-1.992812,5.625,.3925],[-2.773438,7.628906,0],[-1.070312,7.875,0],[-2.695313,7.03125,0],[-2.054687,6.292969,0],[-2.070312,5.625,0],[-2.642038,7.628906,-.670256],[-2.773438,7.628906,0],[-1.070312,7.875,0],[-2.569902,7.03125,-.639395],[-2.695313,7.03125,0],[-1.978596,6.292969,-.38696],[-2.054687,6.292969,0],[-1.992812,5.625,-.3925],[-2.070312,5.625,0],[-2.281113,7.628906,-1.210801],[-1.070312,7.875,0],[-2.225469,7.03125,-1.155156],[-1.769746,6.292969,-.699434],[-1.780312,5.625,-.71],[-1.740569,7.628906,-1.571726],[-1.070312,7.875,0],[-1.709707,7.03125,-1.49959],[-1.457273,6.292969,-.908284],[-1.462812,5.625,-.9225],[-1.070312,7.628906,-1.703125],[-1.070312,7.875,0],[-1.070312,7.03125,-1.625],[-1.070312,6.292969,-.984375],[-1.070312,5.625,-1],[-.400056,7.628906,-1.571726],[-1.070312,7.628906,-1.703125],[-1.070312,7.875,0],[-.430918,7.03125,-1.49959],[-1.070312,7.03125,-1.625],[-.683352,6.292969,-.908284],[-1.070312,6.292969,-.984375],[-.677812,5.625,-.9225],[-1.070312,5.625,-1],[.140489,7.628906,-1.210801],[-1.070312,7.875,0],[.084844,7.03125,-1.155156],[-.370879,6.292969,-.699434],[-.360312,5.625,-.71],[.501414,7.628906,-.670256],[-1.070312,7.875,0],[.429278,7.03125,-.639395],[-.162029,6.292969,-.38696],[-.147812,5.625,-.3925],[.632813,7.628906,0],[-1.070312,7.875,0],[.554688,7.03125,0],[-.085937,6.292969,0],[-.070312,5.625,0],[-.070312,5.625,0],[-.147812,5.625,.3925],[1.034141,5.179688,.895391],[1.210938,5.179688,0],[2.735,4.875,1.619062],[3.054688,4.875,0],[4.262891,4.570313,2.26914],[4.710938,4.570313,0],[4.925938,4.125,2.55125],[5.429688,4.125,0],[-.360312,5.625,.71],[.549375,5.179688,1.619688],[1.858438,4.875,2.92875],[3.034375,4.570313,4.104687],[3.544688,4.125,4.615],[-.677812,5.625,.9225],[-.174922,5.179688,2.104453],[.54875,4.875,3.805313],[1.198828,4.570313,5.333203],[1.480938,4.125,5.99625],[-1.070312,5.625,1],[-1.070312,5.179688,2.28125],[-1.070312,4.875,4.125],[-1.070312,4.570313,5.78125],[-1.070312,4.125,6.5],[-1.070312,5.625,1],[-1.462812,5.625,.9225],[-1.965703,5.179688,2.104453],[-1.070312,5.179688,2.28125],[-2.689375,4.875,3.805313],[-1.070312,4.875,4.125],[-3.339453,4.570313,5.333203],[-1.070312,4.570313,5.78125],[-3.621562,4.125,5.99625],[-1.070312,4.125,6.5],[-1.780312,5.625,.71],[-2.69,5.179688,1.619688],[-3.999062,4.875,2.92875],[-5.174999,4.570313,4.104687],[-5.685312,4.125,4.615],[-1.992812,5.625,.3925],[-3.174765,5.179688,.895391],[-4.875625,4.875,1.619062],[-6.403516,4.570313,2.26914],[-7.066563,4.125,2.55125],[-2.070312,5.625,0],[-3.351562,5.179688,0],[-5.195313,4.875,0],[-6.851563,4.570313,0],[-7.570313,4.125,0],[-2.070312,5.625,0],[-1.992812,5.625,-.3925],[-3.174765,5.179688,-.895391],[-3.351562,5.179688,0],[-4.875625,4.875,-1.619062],[-5.195313,4.875,0],[-6.403516,4.570313,-2.26914],[-6.851563,4.570313,0],[-7.066563,4.125,-2.55125],[-7.570313,4.125,0],[-1.780312,5.625,-.71],[-2.69,5.179688,-1.619688],[-3.999062,4.875,-2.92875],[-5.174999,4.570313,-4.104687],[-5.685312,4.125,-4.615],[-1.462812,5.625,-.9225],[-1.965703,5.179688,-2.104453],[-2.689375,4.875,-3.805313],[-3.339453,4.570313,-5.333203],[-3.621562,4.125,-5.99625],[-1.070312,5.625,-1],[-1.070312,5.179688,-2.28125],[-1.070312,4.875,-4.125],[-1.070312,4.570313,-5.78125],[-1.070312,4.125,-6.5],[-1.070312,5.625,-1],[-.677812,5.625,-.9225],[-.174922,5.179688,-2.104453],[-1.070312,5.179688,-2.28125],[.54875,4.875,-3.805313],[-1.070312,4.875,-4.125],[1.198828,4.570313,-5.333203],[-1.070312,4.570313,-5.78125],[1.480938,4.125,-5.99625],[-1.070312,4.125,-6.5],[-.360312,5.625,-.71],[.549375,5.179688,-1.619688],[1.858438,4.875,-2.92875],[3.034375,4.570313,-4.104687],[3.544688,4.125,-4.615],[-.147812,5.625,-.3925],[1.034141,5.179688,-.895391],[2.735,4.875,-1.619062],[4.262891,4.570313,-2.26914],[4.925938,4.125,-2.55125],[-.070312,5.625,0],[1.210938,5.179688,0],[3.054688,4.875,0],[4.710938,4.570313,0],[5.429688,4.125,0]],n.g=[[0,1,2],[2,3,0],[3,2,4],[4,5,3],[5,4,6],[6,7,5],[7,6,8],[8,9,7],[1,10,11],[11,2,1],[2,11,12],[12,4,2],[4,12,13],[13,6,4],[6,13,14],[14,8,6],[10,15,16],[16,11,10],[11,16,17],[17,12,11],[12,17,18],[18,13,12],[13,18,19],[19,14,13],[15,20,21],[21,16,15],[16,21,22],[22,17,16],[17,22,23],[23,18,17],[18,23,24],[24,19,18],[25,26,27],[27,28,25],[28,27,29],[29,30,28],[30,29,31],[31,32,30],[32,31,33],[33,34,32],[26,35,36],[36,27,26],[27,36,37],[37,29,27],[29,37,38],[38,31,29],[31,38,39],[39,33,31],[35,40,41],[41,36,35],[36,41,42],[42,37,36],[37,42,43],[43,38,37],[38,43,44],[44,39,38],[40,45,46],[46,41,40],[41,46,47],[47,42,41],[42,47,48],[48,43,42],[43,48,49],[49,44,43],[50,51,52],[52,53,50],[53,52,54],[54,55,53],[55,54,56],[56,57,55],[57,56,58],[58,59,57],[51,60,61],[61,52,51],[52,61,62],[62,54,52],[54,62,63],[63,56,54],[56,63,64],[64,58,56],[60,65,66],[66,61,60],[61,66,67],[67,62,61],[62,67,68],[68,63,62],[63,68,69],[69,64,63],[65,70,71],[71,66,65],[66,71,72],[72,67,66],[67,72,73],[73,68,67],[68,73,74],[74,69,68],[75,76,77],[77,78,75],[78,77,79],[79,80,78],[80,79,81],[81,82,80],[82,81,83],[83,84,82],[76,85,86],[86,77,76],[77,86,87],[87,79,77],[79,87,88],[88,81,79],[81,88,89],[89,83,81],[85,90,91],[91,86,85],[86,91,92],[92,87,86],[87,92,93],[93,88,87],[88,93,94],[94,89,88],[90,95,96],[96,91,90],[91,96,97],[97,92,91],[92,97,98],[98,93,92],[93,98,99],[99,94,93],[100,101,102],[102,103,100],[103,102,104],[104,105,103],[105,104,106],[106,107,105],[107,106,108],[108,109,107],[101,110,111],[111,102,101],[102,111,112],[112,104,102],[104,112,113],[113,106,104],[106,113,114],[114,108,106],[110,115,116],[116,111,110],[111,116,117],[117,112,111],[112,117,118],[118,113,112],[113,118,119],[119,114,113],[115,120,121],[121,116,115],[116,121,122],[122,117,116],[117,122,123],[123,118,117],[118,123,124],[124,119,118],[125,126,127],[127,128,125],[128,127,129],[129,130,128],[130,129,131],[131,132,130],[132,131,133],[133,134,132],[126,135,136],[136,127,126],[127,136,137],[137,129,127],[129,137,138],[138,131,129],[131,138,139],[139,133,131],[135,140,141],[141,136,135],[136,141,142],[142,137,136],[137,142,143],[143,138,137],[138,143,144],[144,139,138],[140,145,146],[146,141,140],[141,146,147],[147,142,141],[142,147,148],[148,143,142],[143,148,149],[149,144,143],[150,151,152],[152,153,150],[153,152,154],[154,155,153],[155,154,156],[156,157,155],[157,156,158],[158,159,157],[151,160,161],[161,152,151],[152,161,162],[162,154,152],[154,162,163],[163,156,154],[156,163,164],[164,158,156],[160,165,166],[166,161,160],[161,166,167],[167,162,161],[162,167,168],[168,163,162],[163,168,169],[169,164,163],[165,170,171],[171,166,165],[166,171,172],[172,167,166],[167,172,173],[173,168,167],[168,173,174],[174,169,168],[175,176,177],[177,178,175],[178,177,179],[179,180,178],[180,179,181],[181,182,180],[182,181,183],[183,184,182],[176,185,186],[186,177,176],[177,186,187],[187,179,177],[179,187,188],[188,181,179],[181,188,189],[189,183,181],[185,190,191],[191,186,185],[186,191,192],[192,187,186],[187,192,193],[193,188,187],[188,193,194],[194,189,188],[190,195,196],[196,191,190],[191,196,197],[197,192,191],[192,197,198],[198,193,192],[193,198,199],[199,194,193],[200,201,202],[202,203,200],[203,202,204],[204,205,203],[205,204,206],[206,207,205],[207,206,208],[208,209,207],[201,210,211],[211,202,201],[202,211,212],[212,204,202],[204,212,213],[213,206,204],[206,213,214],[214,208,206],[210,215,216],[216,211,210],[211,216,217],[217,212,211],[212,217,218],[218,213,212],[213,218,219],[219,214,213],[215,220,221],[221,216,215],[216,221,222],[222,217,216],[217,222,223],[223,218,217],[218,223,224],[224,219,218],[225,226,227],[227,228,225],[228,227,229],[229,230,228],[230,229,231],[231,232,230],[232,231,233],[233,234,232],[226,235,236],[236,227,226],[227,236,237],[237,229,227],[229,237,238],[238,231,229],[231,238,239],[239,233,231],[235,240,241],[241,236,235],[236,241,242],[242,237,236],[237,242,243],[243,238,237],[238,243,244],[244,239,238],[240,245,246],[246,241,240],[241,246,247],[247,242,241],[242,247,248],[248,243,242],[243,248,249],[249,244,243],[250,251,252],[252,253,250],[253,252,254],[254,255,253],[255,254,256],[256,257,255],[257,256,258],[258,259,257],[251,260,261],[261,252,251],[252,261,262],[262,254,252],[254,262,263],[263,256,254],[256,263,264],[264,258,256],[260,265,266],[266,261,260],[261,266,267],[267,262,261],[262,267,268],[268,263,262],[263,268,269],[269,264,263],[265,270,271],[271,266,265],[266,271,272],[272,267,266],[267,272,273],[273,268,267],[268,273,274],[274,269,268],[275,276,277],[277,278,275],[278,277,279],[279,280,278],[280,279,281],[281,282,280],[282,281,283],[283,284,282],[276,285,286],[286,277,276],[277,286,287],[287,279,277],[279,287,288],[288,281,279],[281,288,289],[289,283,281],[285,290,291],[291,286,285],[286,291,292],[292,287,286],[287,292,293],[293,288,287],[288,293,294],[294,289,288],[290,295,296],[296,291,290],[291,296,297],[297,292,291],[292,297,298],[298,293,292],[293,298,299],[299,294,293],[300,301,302],[302,303,300],[303,302,304],[304,305,303],[305,304,306],[306,307,305],[307,306,308],[301,309,310],[310,302,301],[302,310,311],[311,304,302],[304,311,312],[312,306,304],[306,312,313],[309,314,315],[315,310,309],[310,315,316],[316,311,310],[311,316,317],[317,312,311],[312,317,318],[314,319,320],[320,315,314],[315,320,321],[321,316,315],[316,321,322],[322,317,316],[317,322,323],[324,325,326],[326,327,324],[327,326,328],[328,329,327],[329,328,330],[330,331,329],[331,330,332],[325,333,334],[334,326,325],[326,334,335],[335,328,326],[328,335,336],[336,330,328],[330,336,337],[333,338,339],[339,334,333],[334,339,340],[340,335,334],[335,340,341],[341,336,335],[336,341,342],[338,343,344],[344,339,338],[339,344,345],[345,340,339],[340,345,346],[346,341,340],[341,346,347],[348,349,350],[350,351,348],[351,350,352],[352,353,351],[353,352,354],[354,355,353],[355,354,356],[349,357,358],[358,350,349],[350,358,359],[359,352,350],[352,359,360],[360,354,352],[354,360,361],[357,362,363],[363,358,357],[358,363,364],[364,359,358],[359,364,365],[365,360,359],[360,365,366],[362,367,368],[368,363,362],[363,368,369],[369,364,363],[364,369,370],[370,365,364],[365,370,371],[372,373,374],[374,375,372],[375,374,376],[376,377,375],[377,376,378],[378,379,377],[379,378,380],[373,381,382],[382,374,373],[374,382,383],[383,376,374],[376,383,384],[384,378,376],[378,384,385],[381,386,387],[387,382,381],[382,387,388],[388,383,382],[383,388,389],[389,384,383],[384,389,390],[386,391,392],[392,387,386],[387,392,393],[393,388,387],[388,393,394],[394,389,388],[389,394,395],[396,397,398],[398,399,396],[399,398,400],[400,401,399],[401,400,402],[402,403,401],[403,402,404],[404,405,403],[397,406,407],[407,398,397],[398,407,408],[408,400,398],[400,408,409],[409,402,400],[402,409,410],[410,404,402],[406,411,412],[412,407,406],[407,412,413],[413,408,407],[408,413,414],[414,409,408],[409,414,415],[415,410,409],[411,416,417],[417,412,411],[412,417,418],[418,413,412],[413,418,419],[419,414,413],[414,419,420],[420,415,414],[421,422,423],[423,424,421],[424,423,425],[425,426,424],[426,425,427],[427,428,426],[428,427,429],[429,430,428],[422,431,432],[432,423,422],[423,432,433],[433,425,423],[425,433,434],[434,427,425],[427,434,435],[435,429,427],[431,436,437],[437,432,431],[432,437,438],[438,433,432],[433,438,439],[439,434,433],[434,439,440],[440,435,434],[436,441,442],[442,437,436],[437,442,443],[443,438,437],[438,443,444],[444,439,438],[439,444,445],[445,440,439],[446,447,448],[448,449,446],[449,448,450],[450,451,449],[451,450,452],[452,453,451],[453,452,454],[454,455,453],[447,456,457],[457,448,447],[448,457,458],[458,450,448],[450,458,459],[459,452,450],[452,459,460],[460,454,452],[456,461,462],[462,457,456],[457,462,463],[463,458,457],[458,463,464],[464,459,458],[459,464,465],[465,460,459],[461,466,467],[467,462,461],[462,467,468],[468,463,462],[463,468,469],[469,464,463],[464,469,470],[470,465,464],[471,472,473],[473,474,471],[474,473,475],[475,476,474],[476,475,477],[477,478,476],[478,477,479],[479,480,478],[472,481,482],[482,473,472],[473,482,483],[483,475,473],[475,483,484],[484,477,475],[477,484,485],[485,479,477],[481,486,487],[487,482,481],[482,487,488],[488,483,482],[483,488,489],[489,484,483],[484,489,490],[490,485,484],[486,491,492],[492,487,486],[487,492,493],[493,488,487],[488,493,494],[494,489,488],[489,494,495],[495,490,489],[496,497,498],[498,499,496],[499,498,500],[500,501,499],[501,500,502],[502,503,501],[503,502,504],[504,505,503],[497,506,507],[507,498,497],[498,507,508],[508,500,498],[500,508,509],[509,502,500],[502,509,510],[510,504,502],[506,511,512],[512,507,506],[507,512,513],[513,508,507],[508,513,514],[514,509,508],[509,514,515],[515,510,509],[511,516,517],[517,512,511],[512,517,518],[518,513,512],[513,518,519],[519,514,513],[514,519,520],[520,515,514],[521,522,523],[523,524,521],[524,523,525],[525,526,524],[526,525,527],[527,528,526],[528,527,529],[529,530,528],[522,531,532],[532,523,522],[523,532,533],[533,525,523],[525,533,534],[534,527,525],[527,534,535],[535,529,527],[531,536,537],[537,532,531],[532,537,538],[538,533,532],[533,538,539],[539,534,533],[534,539,540],[540,535,534],[536,541,542],[542,537,536],[537,542,543],[543,538,537],[538,543,544],[544,539,538],[539,544,545],[545,540,539],[546,547,548],[548,549,546],[549,548,550],[550,551,549],[551,550,552],[552,553,551],[553,552,554],[554,555,553],[547,556,557],[557,548,547],[548,557,558],[558,550,548],[550,558,559],[559,552,550],[552,559,560],[560,554,552],[556,561,562],[562,557,556],[557,562,563],[563,558,557],[558,563,564],[564,559,558],[559,564,565],[565,560,559],[561,566,567],[567,562,561],[562,567,568],[568,563,562],[563,568,569],[569,564,563],[564,569,570],[570,565,564],[571,572,573],[573,574,571],[574,573,575],[575,576,574],[576,575,577],[577,578,576],[578,577,579],[579,580,578],[572,581,582],[582,573,572],[573,582,583],[583,575,573],[575,583,584],[584,577,575],[577,584,585],[585,579,577],[581,586,587],[587,582,581],[582,587,588],[588,583,582],[583,588,589],[589,584,583],[584,589,590],[590,585,584],[586,591,592],[592,587,586],[587,592,593],[593,588,587],[588,593,594],[594,589,588],[589,594,595],[595,590,589],[596,597,598],[597,596,599],[599,600,597],[600,599,601],[601,602,600],[602,601,603],[603,604,602],[605,596,606],[596,605,607],[607,599,596],[599,607,608],[608,601,599],[601,608,609],[609,603,601],[610,605,611],[605,610,612],[612,607,605],[607,612,613],[613,608,607],[608,613,614],[614,609,608],[615,610,616],[610,615,617],[617,612,610],[612,617,618],[618,613,612],[613,618,619],[619,614,613],[620,621,622],[621,620,623],[623,624,621],[624,623,625],[625,626,624],[626,625,627],[627,628,626],[629,620,630],[620,629,631],[631,623,620],[623,631,632],[632,625,623],[625,632,633],[633,627,625],[634,629,635],[629,634,636],[636,631,629],[631,636,637],[637,632,631],[632,637,638],[638,633,632],[639,634,640],[634,639,641],[641,636,634],[636,641,642],[642,637,636],[637,642,643],[643,638,637],[644,645,646],[645,644,647],[647,648,645],[648,647,649],[649,650,648],[650,649,651],[651,652,650],[653,644,654],[644,653,655],[655,647,644],[647,655,656],[656,649,647],[649,656,657],[657,651,649],[658,653,659],[653,658,660],[660,655,653],[655,660,661],[661,656,655],[656,661,662],[662,657,656],[663,658,664],[658,663,665],[665,660,658],[660,665,666],[666,661,660],[661,666,667],[667,662,661],[668,669,670],[669,668,671],[671,672,669],[672,671,673],[673,674,672],[674,673,675],[675,676,674],[677,668,678],[668,677,679],[679,671,668],[671,679,680],[680,673,671],[673,680,681],[681,675,673],[682,677,683],[677,682,684],[684,679,677],[679,684,685],[685,680,679],[680,685,686],[686,681,680],[687,682,688],[682,687,689],[689,684,682],[684,689,690],[690,685,684],[685,690,691],[691,686,685],[692,693,694],[694,695,692],[695,694,696],[696,697,695],[697,696,698],[698,699,697],[699,698,700],[700,701,699],[693,702,703],[703,694,693],[694,703,704],[704,696,694],[696,704,705],[705,698,696],[698,705,706],[706,700,698],[702,707,708],[708,703,702],[703,708,709],[709,704,703],[704,709,710],[710,705,704],[705,710,711],[711,706,705],[707,712,713],[713,708,707],[708,713,714],[714,709,708],[709,714,715],[715,710,709],[710,715,716],[716,711,710],[717,718,719],[719,720,717],[720,719,721],[721,722,720],[722,721,723],[723,724,722],[724,723,725],[725,726,724],[718,727,728],[728,719,718],[719,728,729],[729,721,719],[721,729,730],[730,723,721],[723,730,731],[731,725,723],[727,732,733],[733,728,727],[728,733,734],[734,729,728],[729,734,735],[735,730,729],[730,735,736],[736,731,730],[732,737,738],[738,733,732],[733,738,739],[739,734,733],[734,739,740],[740,735,734],[735,740,741],[741,736,735],[742,743,744],[744,745,742],[745,744,746],[746,747,745],[747,746,748],[748,749,747],[749,748,750],[750,751,749],[743,752,753],[753,744,743],[744,753,754],[754,746,744],[746,754,755],[755,748,746],[748,755,756],[756,750,748],[752,757,758],[758,753,752],[753,758,759],[759,754,753],[754,759,760],[760,755,754],[755,760,761],[761,756,755],[757,762,763],[763,758,757],[758,763,764],[764,759,758],[759,764,765],[765,760,759],[760,765,766],[766,761,760],[767,768,769],[769,770,767],[770,769,771],[771,772,770],[772,771,773],[773,774,772],[774,773,775],[775,776,774],[768,777,778],[778,769,768],[769,778,779],[779,771,769],[771,779,780],[780,773,771],[773,780,781],[781,775,773],[777,782,783],[783,778,777],[778,783,784],[784,779,778],[779,784,785],[785,780,779],[780,785,786],[786,781,780],[782,787,788],[788,783,782],[783,788,789],[789,784,783],[784,789,790],[790,785,784],[785,790,791],[791,786,785]]}}]); \ No newline at end of file diff --git a/_next/static/chunks/752.2b99aa35a30ac9aa.js b/_next/static/chunks/752.2b99aa35a30ac9aa.js deleted file mode 100644 index 4c1b9292..00000000 --- a/_next/static/chunks/752.2b99aa35a30ac9aa.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[752],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return p},hu:function(){return d}});var a=t(5893),r=t(9008),i=t.n(r),s=t(1163),o=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,o.useRef)(null),r=(0,o.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),l=(0,o.useRef)(null),u=(0,o.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),p=(0,o.useRef)(null),d=(0,o.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,s.useRouter)(),m=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,o.useState)(null),[h,P]=(0,o.useState)(null);return(0,o.useEffect)(()=>{if(m?P(m[1]):P(r[0].name),u&&l.current)for(l.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();d&&p.current&&(d.dom.style.position="absolute",d.showPanel(1),p.current.appendChild(d.dom));let t={active:!0},a=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let s=e.init({canvas:i,pageState:t,gui:u,stats:d});s instanceof Promise&&s.catch(e=>{console.error(e),g(e)})}catch(o){console.error(o),g(o)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),v?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(v)})]}):null]}),(0,a.jsxs)("div",{className:c().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:c().sourceFileNav,children:(0,a.jsx)("ul",{children:r.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":h==e.name,onClick(){P(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,a.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":h==e.name},n))]})]})},p=e=>(0,a.jsx)(u,{...e});function d(e,n){if(!e)throw Error(n)}},2752:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var a=t(5671),r="struct VertexOutput {\n @builtin(position) position : vec4,\n @location(4) color : vec4,\n}\n\n@vertex\nfn vert_main(\n @location(0) a_particlePos : vec2,\n @location(1) a_particleVel : vec2,\n @location(2) a_pos : vec2\n) -> VertexOutput {\n let angle = -atan2(a_particleVel.x, a_particleVel.y);\n let pos = vec2(\n (a_pos.x * cos(angle)) - (a_pos.y * sin(angle)),\n (a_pos.x * sin(angle)) + (a_pos.y * cos(angle))\n );\n \n var output : VertexOutput;\n output.position = vec4(pos + a_particlePos, 0.0, 1.0);\n output.color = vec4(\n 1.0 - sin(angle + 1.0) - a_particleVel.y,\n pos.x * 100.0 - a_particleVel.y + 0.1,\n a_particleVel.x + cos(angle + 0.5),\n 1.0);\n return output;\n}\n\n@fragment\nfn frag_main(@location(4) color : vec4) -> @location(0) vec4 {\n return color;\n}",i="struct Particle {\n pos : vec2,\n vel : vec2,\n}\nstruct SimParams {\n deltaT : f32,\n rule1Distance : f32,\n rule2Distance : f32,\n rule3Distance : f32,\n rule1Scale : f32,\n rule2Scale : f32,\n rule3Scale : f32,\n}\nstruct Particles {\n particles : array,\n}\n@binding(0) @group(0) var params : SimParams;\n@binding(1) @group(0) var particlesA : Particles;\n@binding(2) @group(0) var particlesB : Particles;\n\n// https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) {\n var index = GlobalInvocationID.x;\n\n var vPos = particlesA.particles[index].pos;\n var vVel = particlesA.particles[index].vel;\n var cMass = vec2(0.0);\n var cVel = vec2(0.0);\n var colVel = vec2(0.0);\n var cMassCount = 0u;\n var cVelCount = 0u;\n var pos : vec2;\n var vel : vec2;\n\n for (var i = 0u; i < arrayLength(&particlesA.particles); i++) {\n if (i == index) {\n continue;\n }\n\n pos = particlesA.particles[i].pos.xy;\n vel = particlesA.particles[i].vel.xy;\n if (distance(pos, vPos) < params.rule1Distance) {\n cMass += pos;\n cMassCount++;\n }\n if (distance(pos, vPos) < params.rule2Distance) {\n colVel -= pos - vPos;\n }\n if (distance(pos, vPos) < params.rule3Distance) {\n cVel += vel;\n cVelCount++;\n }\n }\n if (cMassCount > 0) {\n cMass = (cMass / vec2(f32(cMassCount))) - vPos;\n }\n if (cVelCount > 0) {\n cVel /= f32(cVelCount);\n }\n vVel += (cMass * params.rule1Scale) + (colVel * params.rule2Scale) + (cVel * params.rule3Scale);\n\n // clamp velocity for a more pleasing simulation\n vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);\n // kinematic update\n vPos = vPos + (vVel * params.deltaT);\n // Wrap around boundary\n if (vPos.x < -1.0) {\n vPos.x = 1.0;\n }\n if (vPos.x > 1.0) {\n vPos.x = -1.0;\n }\n if (vPos.y < -1.0) {\n vPos.y = 1.0;\n }\n if (vPos.y > 1.0) {\n vPos.y = -1.0;\n }\n // Write back\n particlesB.particles[index].pos = vPos;\n particlesB.particles[index].vel = vVel;\n}\n",s="src/sample/computeBoids/main.ts";let o=async e=>{let{canvas:n,pageState:t,gui:s}=e,o=await navigator.gpu.requestAdapter();(0,a.hu)(o,"requestAdapter returned null");let l=await o.requestDevice();if(!t.active)return;let c=n.getContext("webgpu"),u=window.devicePixelRatio||1;n.width=n.clientWidth*u,n.height=n.clientHeight*u;let p=navigator.gpu.getPreferredCanvasFormat();c.configure({device:l,format:p,alphaMode:"premultiplied"});let d=l.createShaderModule({code:r}),f=l.createRenderPipeline({layout:"auto",vertex:{module:d,entryPoint:"vert_main",buffers:[{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]},{arrayStride:8,stepMode:"vertex",attributes:[{shaderLocation:2,offset:0,format:"float32x2"}]}]},fragment:{module:d,entryPoint:"frag_main",targets:[{format:p}]},primitive:{topology:"triangle-list"}}),m=l.createComputePipeline({layout:"auto",compute:{module:l.createShaderModule({code:i}),entryPoint:"main"}}),v={colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]},g=new Float32Array([-.01,-.02,.01,-.02,0,.02]),h=l.createBuffer({size:g.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(h.getMappedRange()).set(g),h.unmap();let P={deltaT:.04,rule1Distance:.1,rule2Distance:.025,rule3Distance:.025,rule1Scale:.02,rule2Scale:.05,rule3Scale:.005},x=7*Float32Array.BYTES_PER_ELEMENT,b=l.createBuffer({size:x,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});function y(){l.queue.writeBuffer(b,0,new Float32Array([P.deltaT,P.rule1Distance,P.rule2Distance,P.rule3Distance,P.rule1Scale,P.rule2Scale,P.rule3Scale]))}y(),Object.keys(P).forEach(e=>{void 0===s?console.error("GUI not initialized"):s.add(P,e).onFinishChange(y)});let S=new Float32Array(6e3);for(let w=0;w<1500;++w)S[4*w+0]=2*(Math.random()-.5),S[4*w+1]=2*(Math.random()-.5),S[4*w+2]=2*(Math.random()-.5)*.1,S[4*w+3]=2*(Math.random()-.5)*.1;let B=[,,],_=[,,];for(let C=0;C<2;++C)B[C]=l.createBuffer({size:S.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE,mappedAtCreation:!0}),new Float32Array(B[C].getMappedRange()).set(S),B[C].unmap();for(let E=0;E<2;++E)_[E]=l.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:{buffer:B[E],offset:0,size:S.byteLength}},{binding:2,resource:{buffer:B[(E+1)%2],offset:0,size:S.byteLength}}]});let M=0;requestAnimationFrame(function e(){if(!t.active)return;v.colorAttachments[0].view=c.getCurrentTexture().createView();let n=l.createCommandEncoder();{let a=n.beginComputePass();a.setPipeline(m),a.setBindGroup(0,_[M%2]),a.dispatchWorkgroups(Math.ceil(23.4375)),a.end()}{let r=n.beginRenderPass(v);r.setPipeline(f),r.setVertexBuffer(0,B[(M+1)%2]),r.setVertexBuffer(1,h),r.draw(3,1500,0,0),r.end()}l.queue.submit([n.finish()]),++M,requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Compute Boids",description:"A GPU compute particle simulation that mimics the flocking behavior of birds. A compute shader updates two ping-pong buffers which store particle data. The data is used to draw instanced particles.",gui:!0,init:o,sources:[{name:s.substring(24),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport spriteWGSL from './sprite.wgsl';\nimport updateSpritesWGSL from './updateSprites.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const spriteShaderModule = device.createShaderModule({ code: spriteWGSL });\n const renderPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: spriteShaderModule,\n entryPoint: 'vert_main',\n buffers: [\n {\n // instanced particles buffer\n arrayStride: 4 * 4,\n stepMode: 'instance',\n attributes: [\n {\n // instance position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x2',\n },\n {\n // instance velocity\n shaderLocation: 1,\n offset: 2 * 4,\n format: 'float32x2',\n },\n ],\n },\n {\n // vertex buffer\n arrayStride: 2 * 4,\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 2,\n offset: 0,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: spriteShaderModule,\n entryPoint: 'frag_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const computePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: updateSpritesWGSL,\n }),\n entryPoint: 'main',\n },\n });\n\n const renderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined as GPUTextureView, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear' as const,\n storeOp: 'store' as const,\n },\n ],\n };\n\n // prettier-ignore\n const vertexBufferData = new Float32Array([\n -0.01, -0.02, 0.01,\n -0.02, 0.0, 0.02,\n ]);\n\n const spriteVertexBuffer = device.createBuffer({\n size: vertexBufferData.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(spriteVertexBuffer.getMappedRange()).set(vertexBufferData);\n spriteVertexBuffer.unmap();\n\n const simParams = {\n deltaT: 0.04,\n rule1Distance: 0.1,\n rule2Distance: 0.025,\n rule3Distance: 0.025,\n rule1Scale: 0.02,\n rule2Scale: 0.05,\n rule3Scale: 0.005,\n };\n\n const simParamBufferSize = 7 * Float32Array.BYTES_PER_ELEMENT;\n const simParamBuffer = device.createBuffer({\n size: simParamBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n function updateSimParams() {\n device.queue.writeBuffer(\n simParamBuffer,\n 0,\n new Float32Array([\n simParams.deltaT,\n simParams.rule1Distance,\n simParams.rule2Distance,\n simParams.rule3Distance,\n simParams.rule1Scale,\n simParams.rule2Scale,\n simParams.rule3Scale,\n ])\n );\n }\n\n updateSimParams();\n Object.keys(simParams).forEach((k) => {\n const key = k as keyof typeof simParams;\n if (gui === undefined) {\n console.error('GUI not initialized');\n } else {\n gui.add(simParams, key).onFinishChange(updateSimParams);\n }\n });\n\n const numParticles = 1500;\n const initialParticleData = new Float32Array(numParticles * 4);\n for (let i = 0; i < numParticles; ++i) {\n initialParticleData[4 * i + 0] = 2 * (Math.random() - 0.5);\n initialParticleData[4 * i + 1] = 2 * (Math.random() - 0.5);\n initialParticleData[4 * i + 2] = 2 * (Math.random() - 0.5) * 0.1;\n initialParticleData[4 * i + 3] = 2 * (Math.random() - 0.5) * 0.1;\n }\n\n const particleBuffers: GPUBuffer[] = new Array(2);\n const particleBindGroups: GPUBindGroup[] = new Array(2);\n for (let i = 0; i < 2; ++i) {\n particleBuffers[i] = device.createBuffer({\n size: initialParticleData.byteLength,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n mappedAtCreation: true,\n });\n new Float32Array(particleBuffers[i].getMappedRange()).set(\n initialParticleData\n );\n particleBuffers[i].unmap();\n }\n\n for (let i = 0; i < 2; ++i) {\n particleBindGroups[i] = device.createBindGroup({\n layout: computePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: simParamBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: particleBuffers[i],\n offset: 0,\n size: initialParticleData.byteLength,\n },\n },\n {\n binding: 2,\n resource: {\n buffer: particleBuffers[(i + 1) % 2],\n offset: 0,\n size: initialParticleData.byteLength,\n },\n },\n ],\n });\n }\n\n let t = 0;\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(computePipeline);\n passEncoder.setBindGroup(0, particleBindGroups[t % 2]);\n passEncoder.dispatchWorkgroups(Math.ceil(numParticles / 64));\n passEncoder.end();\n }\n {\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(renderPipeline);\n passEncoder.setVertexBuffer(0, particleBuffers[(t + 1) % 2]);\n passEncoder.setVertexBuffer(1, spriteVertexBuffer);\n passEncoder.draw(3, numParticles, 0, 0);\n passEncoder.end();\n }\n device.queue.submit([commandEncoder.finish()]);\n\n ++t;\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ComputeBoids: () => JSX.Element = () =>\n makeSample({\n name: 'Compute Boids',\n description:\n 'A GPU compute particle simulation that mimics \\\nthe flocking behavior of birds. A compute shader updates \\\ntwo ping-pong buffers which store particle data. The data \\\nis used to draw instanced particles.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: 'updateSprites.wgsl',\n contents: updateSpritesWGSL,\n editable: true,\n },\n {\n name: 'sprite.wgsl',\n contents: spriteWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ComputeBoids;\n"},{name:"updateSprites.wgsl",contents:i,editable:!0},{name:"sprite.wgsl",contents:r,editable:!0}],filename:s});var c=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/752.dc861088101e4a75.js b/_next/static/chunks/752.dc861088101e4a75.js new file mode 100644 index 00000000..1b57b62b --- /dev/null +++ b/_next/static/chunks/752.dc861088101e4a75.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[752],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return p},hu:function(){return d}});var a=t(5893),r=t(9008),i=t.n(r),s=t(1163),o=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,o.useRef)(null),r=(0,o.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),l=(0,o.useRef)(null),u=(0,o.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),p=(0,o.useRef)(null),d=(0,o.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,s.useRouter)(),m=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,o.useState)(null),[h,P]=(0,o.useState)(null);return(0,o.useEffect)(()=>{if(m?P(m[1]):P(r[0].name),u&&l.current)for(l.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();d&&p.current&&(d.dom.style.position="absolute",d.showPanel(1),p.current.appendChild(d.dom));let t={active:!0},a=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let s=e.init({canvas:i,pageState:t,gui:u,stats:d});s instanceof Promise&&s.catch(e=>{console.error(e),g(e)})}catch(o){console.error(o),g(o)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),v?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(v)})]}):null]}),(0,a.jsxs)("div",{className:c().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:c().sourceFileNav,children:(0,a.jsx)("ul",{children:r.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":h==e.name,onClick(){P(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,a.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":h==e.name},n))]})]})},p=e=>(0,a.jsx)(u,{...e});function d(e,n){if(!e)throw Error(n)}},2752:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var a=t(5671),r="struct VertexOutput {\n @builtin(position) position : vec4,\n @location(4) color : vec4,\n}\n\n@vertex\nfn vert_main(\n @location(0) a_particlePos : vec2,\n @location(1) a_particleVel : vec2,\n @location(2) a_pos : vec2\n) -> VertexOutput {\n let angle = -atan2(a_particleVel.x, a_particleVel.y);\n let pos = vec2(\n (a_pos.x * cos(angle)) - (a_pos.y * sin(angle)),\n (a_pos.x * sin(angle)) + (a_pos.y * cos(angle))\n );\n \n var output : VertexOutput;\n output.position = vec4(pos + a_particlePos, 0.0, 1.0);\n output.color = vec4(\n 1.0 - sin(angle + 1.0) - a_particleVel.y,\n pos.x * 100.0 - a_particleVel.y + 0.1,\n a_particleVel.x + cos(angle + 0.5),\n 1.0);\n return output;\n}\n\n@fragment\nfn frag_main(@location(4) color : vec4) -> @location(0) vec4 {\n return color;\n}",i="struct Particle {\n pos : vec2,\n vel : vec2,\n}\nstruct SimParams {\n deltaT : f32,\n rule1Distance : f32,\n rule2Distance : f32,\n rule3Distance : f32,\n rule1Scale : f32,\n rule2Scale : f32,\n rule3Scale : f32,\n}\nstruct Particles {\n particles : array,\n}\n@binding(0) @group(0) var params : SimParams;\n@binding(1) @group(0) var particlesA : Particles;\n@binding(2) @group(0) var particlesB : Particles;\n\n// https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) GlobalInvocationID : vec3) {\n var index = GlobalInvocationID.x;\n\n var vPos = particlesA.particles[index].pos;\n var vVel = particlesA.particles[index].vel;\n var cMass = vec2(0.0);\n var cVel = vec2(0.0);\n var colVel = vec2(0.0);\n var cMassCount = 0u;\n var cVelCount = 0u;\n var pos : vec2;\n var vel : vec2;\n\n for (var i = 0u; i < arrayLength(&particlesA.particles); i++) {\n if (i == index) {\n continue;\n }\n\n pos = particlesA.particles[i].pos.xy;\n vel = particlesA.particles[i].vel.xy;\n if (distance(pos, vPos) < params.rule1Distance) {\n cMass += pos;\n cMassCount++;\n }\n if (distance(pos, vPos) < params.rule2Distance) {\n colVel -= pos - vPos;\n }\n if (distance(pos, vPos) < params.rule3Distance) {\n cVel += vel;\n cVelCount++;\n }\n }\n if (cMassCount > 0) {\n cMass = (cMass / vec2(f32(cMassCount))) - vPos;\n }\n if (cVelCount > 0) {\n cVel /= f32(cVelCount);\n }\n vVel += (cMass * params.rule1Scale) + (colVel * params.rule2Scale) + (cVel * params.rule3Scale);\n\n // clamp velocity for a more pleasing simulation\n vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);\n // kinematic update\n vPos = vPos + (vVel * params.deltaT);\n // Wrap around boundary\n if (vPos.x < -1.0) {\n vPos.x = 1.0;\n }\n if (vPos.x > 1.0) {\n vPos.x = -1.0;\n }\n if (vPos.y < -1.0) {\n vPos.y = 1.0;\n }\n if (vPos.y > 1.0) {\n vPos.y = -1.0;\n }\n // Write back\n particlesB.particles[index].pos = vPos;\n particlesB.particles[index].vel = vVel;\n}\n",s="src/sample/computeBoids/main.ts";let o=async e=>{let{canvas:n,pageState:t,gui:s}=e,o=await navigator.gpu.requestAdapter();(0,a.hu)(o,"requestAdapter returned null");let l=await o.requestDevice();if(!t.active)return;let c=n.getContext("webgpu"),u=window.devicePixelRatio;n.width=n.clientWidth*u,n.height=n.clientHeight*u;let p=navigator.gpu.getPreferredCanvasFormat();c.configure({device:l,format:p,alphaMode:"premultiplied"});let d=l.createShaderModule({code:r}),f=l.createRenderPipeline({layout:"auto",vertex:{module:d,entryPoint:"vert_main",buffers:[{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]},{arrayStride:8,stepMode:"vertex",attributes:[{shaderLocation:2,offset:0,format:"float32x2"}]}]},fragment:{module:d,entryPoint:"frag_main",targets:[{format:p}]},primitive:{topology:"triangle-list"}}),m=l.createComputePipeline({layout:"auto",compute:{module:l.createShaderModule({code:i}),entryPoint:"main"}}),v={colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]},g=new Float32Array([-.01,-.02,.01,-.02,0,.02]),h=l.createBuffer({size:g.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(h.getMappedRange()).set(g),h.unmap();let P={deltaT:.04,rule1Distance:.1,rule2Distance:.025,rule3Distance:.025,rule1Scale:.02,rule2Scale:.05,rule3Scale:.005},x=7*Float32Array.BYTES_PER_ELEMENT,b=l.createBuffer({size:x,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});function y(){l.queue.writeBuffer(b,0,new Float32Array([P.deltaT,P.rule1Distance,P.rule2Distance,P.rule3Distance,P.rule1Scale,P.rule2Scale,P.rule3Scale]))}y(),Object.keys(P).forEach(e=>{void 0===s?console.error("GUI not initialized"):s.add(P,e).onFinishChange(y)});let S=new Float32Array(6e3);for(let w=0;w<1500;++w)S[4*w+0]=2*(Math.random()-.5),S[4*w+1]=2*(Math.random()-.5),S[4*w+2]=2*(Math.random()-.5)*.1,S[4*w+3]=2*(Math.random()-.5)*.1;let B=[,,],_=[,,];for(let C=0;C<2;++C)B[C]=l.createBuffer({size:S.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE,mappedAtCreation:!0}),new Float32Array(B[C].getMappedRange()).set(S),B[C].unmap();for(let E=0;E<2;++E)_[E]=l.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:b}},{binding:1,resource:{buffer:B[E],offset:0,size:S.byteLength}},{binding:2,resource:{buffer:B[(E+1)%2],offset:0,size:S.byteLength}}]});let M=0;requestAnimationFrame(function e(){if(!t.active)return;v.colorAttachments[0].view=c.getCurrentTexture().createView();let n=l.createCommandEncoder();{let a=n.beginComputePass();a.setPipeline(m),a.setBindGroup(0,_[M%2]),a.dispatchWorkgroups(Math.ceil(23.4375)),a.end()}{let r=n.beginRenderPass(v);r.setPipeline(f),r.setVertexBuffer(0,B[(M+1)%2]),r.setVertexBuffer(1,h),r.draw(3,1500,0,0),r.end()}l.queue.submit([n.finish()]),++M,requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Compute Boids",description:"A GPU compute particle simulation that mimics the flocking behavior of birds. A compute shader updates two ping-pong buffers which store particle data. The data is used to draw instanced particles.",gui:!0,init:o,sources:[{name:s.substring(24),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport spriteWGSL from './sprite.wgsl';\nimport updateSpritesWGSL from './updateSprites.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const spriteShaderModule = device.createShaderModule({ code: spriteWGSL });\n const renderPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: spriteShaderModule,\n entryPoint: 'vert_main',\n buffers: [\n {\n // instanced particles buffer\n arrayStride: 4 * 4,\n stepMode: 'instance',\n attributes: [\n {\n // instance position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x2',\n },\n {\n // instance velocity\n shaderLocation: 1,\n offset: 2 * 4,\n format: 'float32x2',\n },\n ],\n },\n {\n // vertex buffer\n arrayStride: 2 * 4,\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 2,\n offset: 0,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: spriteShaderModule,\n entryPoint: 'frag_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const computePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: updateSpritesWGSL,\n }),\n entryPoint: 'main',\n },\n });\n\n const renderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined as GPUTextureView, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear' as const,\n storeOp: 'store' as const,\n },\n ],\n };\n\n // prettier-ignore\n const vertexBufferData = new Float32Array([\n -0.01, -0.02, 0.01,\n -0.02, 0.0, 0.02,\n ]);\n\n const spriteVertexBuffer = device.createBuffer({\n size: vertexBufferData.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(spriteVertexBuffer.getMappedRange()).set(vertexBufferData);\n spriteVertexBuffer.unmap();\n\n const simParams = {\n deltaT: 0.04,\n rule1Distance: 0.1,\n rule2Distance: 0.025,\n rule3Distance: 0.025,\n rule1Scale: 0.02,\n rule2Scale: 0.05,\n rule3Scale: 0.005,\n };\n\n const simParamBufferSize = 7 * Float32Array.BYTES_PER_ELEMENT;\n const simParamBuffer = device.createBuffer({\n size: simParamBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n function updateSimParams() {\n device.queue.writeBuffer(\n simParamBuffer,\n 0,\n new Float32Array([\n simParams.deltaT,\n simParams.rule1Distance,\n simParams.rule2Distance,\n simParams.rule3Distance,\n simParams.rule1Scale,\n simParams.rule2Scale,\n simParams.rule3Scale,\n ])\n );\n }\n\n updateSimParams();\n Object.keys(simParams).forEach((k) => {\n const key = k as keyof typeof simParams;\n if (gui === undefined) {\n console.error('GUI not initialized');\n } else {\n gui.add(simParams, key).onFinishChange(updateSimParams);\n }\n });\n\n const numParticles = 1500;\n const initialParticleData = new Float32Array(numParticles * 4);\n for (let i = 0; i < numParticles; ++i) {\n initialParticleData[4 * i + 0] = 2 * (Math.random() - 0.5);\n initialParticleData[4 * i + 1] = 2 * (Math.random() - 0.5);\n initialParticleData[4 * i + 2] = 2 * (Math.random() - 0.5) * 0.1;\n initialParticleData[4 * i + 3] = 2 * (Math.random() - 0.5) * 0.1;\n }\n\n const particleBuffers: GPUBuffer[] = new Array(2);\n const particleBindGroups: GPUBindGroup[] = new Array(2);\n for (let i = 0; i < 2; ++i) {\n particleBuffers[i] = device.createBuffer({\n size: initialParticleData.byteLength,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n mappedAtCreation: true,\n });\n new Float32Array(particleBuffers[i].getMappedRange()).set(\n initialParticleData\n );\n particleBuffers[i].unmap();\n }\n\n for (let i = 0; i < 2; ++i) {\n particleBindGroups[i] = device.createBindGroup({\n layout: computePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: simParamBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: particleBuffers[i],\n offset: 0,\n size: initialParticleData.byteLength,\n },\n },\n {\n binding: 2,\n resource: {\n buffer: particleBuffers[(i + 1) % 2],\n offset: 0,\n size: initialParticleData.byteLength,\n },\n },\n ],\n });\n }\n\n let t = 0;\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(computePipeline);\n passEncoder.setBindGroup(0, particleBindGroups[t % 2]);\n passEncoder.dispatchWorkgroups(Math.ceil(numParticles / 64));\n passEncoder.end();\n }\n {\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(renderPipeline);\n passEncoder.setVertexBuffer(0, particleBuffers[(t + 1) % 2]);\n passEncoder.setVertexBuffer(1, spriteVertexBuffer);\n passEncoder.draw(3, numParticles, 0, 0);\n passEncoder.end();\n }\n device.queue.submit([commandEncoder.finish()]);\n\n ++t;\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ComputeBoids: () => JSX.Element = () =>\n makeSample({\n name: 'Compute Boids',\n description:\n 'A GPU compute particle simulation that mimics \\\nthe flocking behavior of birds. A compute shader updates \\\ntwo ping-pong buffers which store particle data. The data \\\nis used to draw instanced particles.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: 'updateSprites.wgsl',\n contents: updateSpritesWGSL,\n editable: true,\n },\n {\n name: 'sprite.wgsl',\n contents: spriteWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ComputeBoids;\n"},{name:"updateSprites.wgsl",contents:i,editable:!0},{name:"sprite.wgsl",contents:r,editable:!0}],filename:s});var c=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/770.4a7bbbfe28c32977.js b/_next/static/chunks/770.4a7bbbfe28c32977.js deleted file mode 100644 index e5da5114..00000000 --- a/_next/static/chunks/770.4a7bbbfe28c32977.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[770],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return p}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),u=t(7294),s=t(9147),c=t.n(s);t(7319);let l=e=>{let n=(0,u.useRef)(null),i=(0,u.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),s=(0,u.useRef)(null),l=(0,u.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,u.useRef)(null),p=(0,u.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),g=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,h]=(0,u.useState)(null),[v,b]=(0,u.useState)(null);return(0,u.useEffect)(()=>{if(g?b(g[1]):b(i[0].name),l&&s.current)for(s.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();p&&d.current&&(p.dom.style.position="absolute",p.showPanel(1),d.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:l,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(u){console.error(u),h(u)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:s}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){b(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":v==e.name},n))]})]})},d=e=>(0,r.jsx)(l,{...e});function p(e,n){if(!e)throw Error(n)}},1770:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var r=t(5671),i="struct Params {\n filterDim : i32,\n blockDim : u32,\n}\n\n@group(0) @binding(0) var samp : sampler;\n@group(0) @binding(1) var params : Params;\n@group(1) @binding(1) var inputTex : texture_2d;\n@group(1) @binding(2) var outputTex : texture_storage_2d;\n\nstruct Flip {\n value : u32,\n}\n@group(1) @binding(3) var flip : Flip;\n\n// This shader blurs the input texture in one direction, depending on whether\n// |flip.value| is 0 or 1.\n// It does so by running (128 / 4) threads per workgroup to load 128\n// texels into 4 rows of shared memory. Each thread loads a\n// 4 x 4 block of texels to take advantage of the texture sampling\n// hardware.\n// Then, each thread computes the blur result by averaging the adjacent texel values\n// in shared memory.\n// Because we're operating on a subset of the texture, we cannot compute all of the\n// results since not all of the neighbors are available in shared memory.\n// Specifically, with 128 x 128 tiles, we can only compute and write out\n// square blocks of size 128 - (filterSize - 1). We compute the number of blocks\n// needed in Javascript and dispatch that amount.\n\nvar tile : array, 128>, 4>;\n\n@compute @workgroup_size(32, 1, 1)\nfn main(\n @builtin(workgroup_id) WorkGroupID : vec3,\n @builtin(local_invocation_id) LocalInvocationID : vec3\n) {\n let filterOffset = (params.filterDim - 1) / 2;\n let dims = vec2(textureDimensions(inputTex, 0));\n let baseIndex = vec2(WorkGroupID.xy * vec2(params.blockDim, 4) +\n LocalInvocationID.xy * vec2(4, 1))\n - vec2(filterOffset, 0);\n\n for (var r = 0; r < 4; r++) {\n for (var c = 0; c < 4; c++) {\n var loadIndex = baseIndex + vec2(c, r);\n if (flip.value != 0u) {\n loadIndex = loadIndex.yx;\n }\n\n tile[r][4 * LocalInvocationID.x + u32(c)] = textureSampleLevel(\n inputTex,\n samp,\n (vec2(loadIndex) + vec2(0.25, 0.25)) / vec2(dims),\n 0.0\n ).rgb;\n }\n }\n\n workgroupBarrier();\n\n for (var r = 0; r < 4; r++) {\n for (var c = 0; c < 4; c++) {\n var writeIndex = baseIndex + vec2(c, r);\n if (flip.value != 0) {\n writeIndex = writeIndex.yx;\n }\n\n let center = i32(4 * LocalInvocationID.x) + c;\n if (center >= filterOffset &&\n center < 128 - filterOffset &&\n all(writeIndex < dims)) {\n var acc = vec3(0.0, 0.0, 0.0);\n for (var f = 0; f < params.filterDim; f++) {\n var i = center + f - filterOffset;\n acc = acc + (1.0 / f32(params.filterDim)) * tile[r][i];\n }\n textureStore(outputTex, writeIndex, vec4(acc, 1.0));\n }\n }\n }\n}\n",a=t(134),o="src/sample/imageBlur/main.ts";let u=async e=>{let n,{canvas:r,pageState:o,gui:u}=e,s=await navigator.gpu.requestAdapter(),c=await s.requestDevice();if(!o.active)return;let l=r.getContext("webgpu"),d=window.devicePixelRatio||1;r.width=r.clientWidth*d,r.height=r.clientHeight*d;let p=navigator.gpu.getPreferredCanvasFormat();l.configure({device:c,format:p,alphaMode:"premultiplied"});let m=c.createComputePipeline({layout:"auto",compute:{module:c.createShaderModule({code:i}),entryPoint:"main"}}),g=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:a.Z}),entryPoint:"vert_main"},fragment:{module:c.createShaderModule({code:a.Z}),entryPoint:"frag_main",targets:[{format:p}]},primitive:{topology:"triangle-list"}}),f=c.createSampler({magFilter:"linear",minFilter:"linear"}),h=await fetch(new t.U(t(5685)).toString()),v=await createImageBitmap(await h.blob()),[b,x]=[v.width,v.height],w=c.createTexture({size:[b,x,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});c.queue.copyExternalImageToTexture({source:v},{texture:w},[v.width,v.height]);let P=[0,1].map(()=>c.createTexture({size:{width:b,height:x},format:"rgba8unorm",usage:GPUTextureUsage.COPY_DST|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.TEXTURE_BINDING})),G=(()=>{let e=c.createBuffer({size:4,mappedAtCreation:!0,usage:GPUBufferUsage.UNIFORM});return new Uint32Array(e.getMappedRange())[0]=0,e.unmap(),e})(),B=(()=>{let e=c.createBuffer({size:4,mappedAtCreation:!0,usage:GPUBufferUsage.UNIFORM});return new Uint32Array(e.getMappedRange())[0]=1,e.unmap(),e})(),y=c.createBuffer({size:8,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.UNIFORM}),T=c.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:f},{binding:1,resource:{buffer:y}}]}),U=c.createBindGroup({layout:m.getBindGroupLayout(1),entries:[{binding:1,resource:w.createView()},{binding:2,resource:P[0].createView()},{binding:3,resource:{buffer:G}}]}),S=c.createBindGroup({layout:m.getBindGroupLayout(1),entries:[{binding:1,resource:P[0].createView()},{binding:2,resource:P[1].createView()},{binding:3,resource:{buffer:B}}]}),_=c.createBindGroup({layout:m.getBindGroupLayout(1),entries:[{binding:1,resource:P[1].createView()},{binding:2,resource:P[0].createView()},{binding:3,resource:{buffer:G}}]}),I=c.createBindGroup({layout:g.getBindGroupLayout(0),entries:[{binding:0,resource:f},{binding:1,resource:P[1].createView()}]}),C={filterSize:15,iterations:2},M=()=>{n=128-(C.filterSize-1),c.queue.writeBuffer(y,0,new Uint32Array([C.filterSize,n]))};u.add(C,"filterSize",1,33).step(2).onChange(M),u.add(C,"iterations",1,10).step(1),M(),requestAnimationFrame(function e(){if(!o.active)return;let t=c.createCommandEncoder(),r=t.beginComputePass();r.setPipeline(m),r.setBindGroup(0,T),r.setBindGroup(1,U),r.dispatchWorkgroups(Math.ceil(b/n),Math.ceil(x/4)),r.setBindGroup(1,S),r.dispatchWorkgroups(Math.ceil(x/n),Math.ceil(b/4));for(let i=0;i(0,r.Tl)({name:"Image Blur",description:"This example shows how to blur an image using a WebGPU compute shader.",gui:!0,init:u,sources:[{name:o.substring(21),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport blurWGSL from './blur.wgsl';\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\n\n// Contants from the blur.wgsl shader.\nconst tileDim = 128;\nconst batch = [4, 4];\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const blurPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: blurWGSL,\n }),\n entryPoint: 'main',\n },\n });\n\n const fullscreenQuadPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'frag_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const response = await fetch(\n new URL('../../../assets/img/Di-3d.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n const [srcWidth, srcHeight] = [imageBitmap.width, imageBitmap.height];\n const cubeTexture = device.createTexture({\n size: [srcWidth, srcHeight, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubeTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n\n const textures = [0, 1].map(() => {\n return device.createTexture({\n size: {\n width: srcWidth,\n height: srcHeight,\n },\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.TEXTURE_BINDING,\n });\n });\n\n const buffer0 = (() => {\n const buffer = device.createBuffer({\n size: 4,\n mappedAtCreation: true,\n usage: GPUBufferUsage.UNIFORM,\n });\n new Uint32Array(buffer.getMappedRange())[0] = 0;\n buffer.unmap();\n return buffer;\n })();\n\n const buffer1 = (() => {\n const buffer = device.createBuffer({\n size: 4,\n mappedAtCreation: true,\n usage: GPUBufferUsage.UNIFORM,\n });\n new Uint32Array(buffer.getMappedRange())[0] = 1;\n buffer.unmap();\n return buffer;\n })();\n\n const blurParamsBuffer = device.createBuffer({\n size: 8,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,\n });\n\n const computeConstants = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: sampler,\n },\n {\n binding: 1,\n resource: {\n buffer: blurParamsBuffer,\n },\n },\n ],\n });\n\n const computeBindGroup0 = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 1,\n resource: cubeTexture.createView(),\n },\n {\n binding: 2,\n resource: textures[0].createView(),\n },\n {\n binding: 3,\n resource: {\n buffer: buffer0,\n },\n },\n ],\n });\n\n const computeBindGroup1 = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 1,\n resource: textures[0].createView(),\n },\n {\n binding: 2,\n resource: textures[1].createView(),\n },\n {\n binding: 3,\n resource: {\n buffer: buffer1,\n },\n },\n ],\n });\n\n const computeBindGroup2 = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 1,\n resource: textures[1].createView(),\n },\n {\n binding: 2,\n resource: textures[0].createView(),\n },\n {\n binding: 3,\n resource: {\n buffer: buffer0,\n },\n },\n ],\n });\n\n const showResultBindGroup = device.createBindGroup({\n layout: fullscreenQuadPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: sampler,\n },\n {\n binding: 1,\n resource: textures[1].createView(),\n },\n ],\n });\n\n const settings = {\n filterSize: 15,\n iterations: 2,\n };\n\n let blockDim: number;\n const updateSettings = () => {\n blockDim = tileDim - (settings.filterSize - 1);\n device.queue.writeBuffer(\n blurParamsBuffer,\n 0,\n new Uint32Array([settings.filterSize, blockDim])\n );\n };\n gui.add(settings, 'filterSize', 1, 33).step(2).onChange(updateSettings);\n gui.add(settings, 'iterations', 1, 10).step(1);\n\n updateSettings();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n\n const computePass = commandEncoder.beginComputePass();\n computePass.setPipeline(blurPipeline);\n computePass.setBindGroup(0, computeConstants);\n\n computePass.setBindGroup(1, computeBindGroup0);\n computePass.dispatchWorkgroups(\n Math.ceil(srcWidth / blockDim),\n Math.ceil(srcHeight / batch[1])\n );\n\n computePass.setBindGroup(1, computeBindGroup1);\n computePass.dispatchWorkgroups(\n Math.ceil(srcHeight / blockDim),\n Math.ceil(srcWidth / batch[1])\n );\n\n for (let i = 0; i < settings.iterations - 1; ++i) {\n computePass.setBindGroup(1, computeBindGroup2);\n computePass.dispatchWorkgroups(\n Math.ceil(srcWidth / blockDim),\n Math.ceil(srcHeight / batch[1])\n );\n\n computePass.setBindGroup(1, computeBindGroup1);\n computePass.dispatchWorkgroups(\n Math.ceil(srcHeight / blockDim),\n Math.ceil(srcWidth / batch[1])\n );\n }\n\n computePass.end();\n\n const passEncoder = commandEncoder.beginRenderPass({\n colorAttachments: [\n {\n view: context.getCurrentTexture().createView(),\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n });\n\n passEncoder.setPipeline(fullscreenQuadPipeline);\n passEncoder.setBindGroup(0, showResultBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ImageBlur: () => JSX.Element = () =>\n makeSample({\n name: 'Image Blur',\n description:\n 'This example shows how to blur an image using a WebGPU compute shader.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './blur.wgsl',\n contents: blurWGSL,\n editable: true,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ImageBlur;\n"},{name:"./blur.wgsl",contents:i,editable:!0},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:a.Z,editable:!0}],filename:o});var c=s},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"},5685:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/Di-3d.ba319100a0ec2120.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/770.9b6ca64a0f4cbbef.js b/_next/static/chunks/770.9b6ca64a0f4cbbef.js new file mode 100644 index 00000000..934c5f4f --- /dev/null +++ b/_next/static/chunks/770.9b6ca64a0f4cbbef.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[770],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return p}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),u=t(7294),s=t(9147),c=t.n(s);t(7319);let l=e=>{let n=(0,u.useRef)(null),i=(0,u.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),s=(0,u.useRef)(null),l=(0,u.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),d=(0,u.useRef)(null),p=(0,u.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),g=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,h]=(0,u.useState)(null),[v,b]=(0,u.useState)(null);return(0,u.useEffect)(()=>{if(g?b(g[1]):b(i[0].name),l&&s.current)for(s.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();p&&d.current&&(p.dom.style.position="absolute",p.showPanel(1),d.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:l,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),h(e)})}catch(u){console.error(u),h(u)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:s}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){b(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":v==e.name},n))]})]})},d=e=>(0,r.jsx)(l,{...e});function p(e,n){if(!e)throw Error(n)}},1770:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var r=t(5671),i="struct Params {\n filterDim : i32,\n blockDim : u32,\n}\n\n@group(0) @binding(0) var samp : sampler;\n@group(0) @binding(1) var params : Params;\n@group(1) @binding(1) var inputTex : texture_2d;\n@group(1) @binding(2) var outputTex : texture_storage_2d;\n\nstruct Flip {\n value : u32,\n}\n@group(1) @binding(3) var flip : Flip;\n\n// This shader blurs the input texture in one direction, depending on whether\n// |flip.value| is 0 or 1.\n// It does so by running (128 / 4) threads per workgroup to load 128\n// texels into 4 rows of shared memory. Each thread loads a\n// 4 x 4 block of texels to take advantage of the texture sampling\n// hardware.\n// Then, each thread computes the blur result by averaging the adjacent texel values\n// in shared memory.\n// Because we're operating on a subset of the texture, we cannot compute all of the\n// results since not all of the neighbors are available in shared memory.\n// Specifically, with 128 x 128 tiles, we can only compute and write out\n// square blocks of size 128 - (filterSize - 1). We compute the number of blocks\n// needed in Javascript and dispatch that amount.\n\nvar tile : array, 128>, 4>;\n\n@compute @workgroup_size(32, 1, 1)\nfn main(\n @builtin(workgroup_id) WorkGroupID : vec3,\n @builtin(local_invocation_id) LocalInvocationID : vec3\n) {\n let filterOffset = (params.filterDim - 1) / 2;\n let dims = vec2(textureDimensions(inputTex, 0));\n let baseIndex = vec2(WorkGroupID.xy * vec2(params.blockDim, 4) +\n LocalInvocationID.xy * vec2(4, 1))\n - vec2(filterOffset, 0);\n\n for (var r = 0; r < 4; r++) {\n for (var c = 0; c < 4; c++) {\n var loadIndex = baseIndex + vec2(c, r);\n if (flip.value != 0u) {\n loadIndex = loadIndex.yx;\n }\n\n tile[r][4 * LocalInvocationID.x + u32(c)] = textureSampleLevel(\n inputTex,\n samp,\n (vec2(loadIndex) + vec2(0.25, 0.25)) / vec2(dims),\n 0.0\n ).rgb;\n }\n }\n\n workgroupBarrier();\n\n for (var r = 0; r < 4; r++) {\n for (var c = 0; c < 4; c++) {\n var writeIndex = baseIndex + vec2(c, r);\n if (flip.value != 0) {\n writeIndex = writeIndex.yx;\n }\n\n let center = i32(4 * LocalInvocationID.x) + c;\n if (center >= filterOffset &&\n center < 128 - filterOffset &&\n all(writeIndex < dims)) {\n var acc = vec3(0.0, 0.0, 0.0);\n for (var f = 0; f < params.filterDim; f++) {\n var i = center + f - filterOffset;\n acc = acc + (1.0 / f32(params.filterDim)) * tile[r][i];\n }\n textureStore(outputTex, writeIndex, vec4(acc, 1.0));\n }\n }\n }\n}\n",a=t(134),o="src/sample/imageBlur/main.ts";let u=async e=>{let n,{canvas:r,pageState:o,gui:u}=e,s=await navigator.gpu.requestAdapter(),c=await s.requestDevice();if(!o.active)return;let l=r.getContext("webgpu"),d=window.devicePixelRatio;r.width=r.clientWidth*d,r.height=r.clientHeight*d;let p=navigator.gpu.getPreferredCanvasFormat();l.configure({device:c,format:p,alphaMode:"premultiplied"});let m=c.createComputePipeline({layout:"auto",compute:{module:c.createShaderModule({code:i}),entryPoint:"main"}}),g=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:a.Z}),entryPoint:"vert_main"},fragment:{module:c.createShaderModule({code:a.Z}),entryPoint:"frag_main",targets:[{format:p}]},primitive:{topology:"triangle-list"}}),f=c.createSampler({magFilter:"linear",minFilter:"linear"}),h=await fetch(new t.U(t(5685)).toString()),v=await createImageBitmap(await h.blob()),[b,x]=[v.width,v.height],w=c.createTexture({size:[b,x,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});c.queue.copyExternalImageToTexture({source:v},{texture:w},[v.width,v.height]);let P=[0,1].map(()=>c.createTexture({size:{width:b,height:x},format:"rgba8unorm",usage:GPUTextureUsage.COPY_DST|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.TEXTURE_BINDING})),G=(()=>{let e=c.createBuffer({size:4,mappedAtCreation:!0,usage:GPUBufferUsage.UNIFORM});return new Uint32Array(e.getMappedRange())[0]=0,e.unmap(),e})(),B=(()=>{let e=c.createBuffer({size:4,mappedAtCreation:!0,usage:GPUBufferUsage.UNIFORM});return new Uint32Array(e.getMappedRange())[0]=1,e.unmap(),e})(),y=c.createBuffer({size:8,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.UNIFORM}),T=c.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:f},{binding:1,resource:{buffer:y}}]}),U=c.createBindGroup({layout:m.getBindGroupLayout(1),entries:[{binding:1,resource:w.createView()},{binding:2,resource:P[0].createView()},{binding:3,resource:{buffer:G}}]}),S=c.createBindGroup({layout:m.getBindGroupLayout(1),entries:[{binding:1,resource:P[0].createView()},{binding:2,resource:P[1].createView()},{binding:3,resource:{buffer:B}}]}),_=c.createBindGroup({layout:m.getBindGroupLayout(1),entries:[{binding:1,resource:P[1].createView()},{binding:2,resource:P[0].createView()},{binding:3,resource:{buffer:G}}]}),I=c.createBindGroup({layout:g.getBindGroupLayout(0),entries:[{binding:0,resource:f},{binding:1,resource:P[1].createView()}]}),C={filterSize:15,iterations:2},M=()=>{n=128-(C.filterSize-1),c.queue.writeBuffer(y,0,new Uint32Array([C.filterSize,n]))};u.add(C,"filterSize",1,33).step(2).onChange(M),u.add(C,"iterations",1,10).step(1),M(),requestAnimationFrame(function e(){if(!o.active)return;let t=c.createCommandEncoder(),r=t.beginComputePass();r.setPipeline(m),r.setBindGroup(0,T),r.setBindGroup(1,U),r.dispatchWorkgroups(Math.ceil(b/n),Math.ceil(x/4)),r.setBindGroup(1,S),r.dispatchWorkgroups(Math.ceil(x/n),Math.ceil(b/4));for(let i=0;i(0,r.Tl)({name:"Image Blur",description:"This example shows how to blur an image using a WebGPU compute shader.",gui:!0,init:u,sources:[{name:o.substring(21),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport blurWGSL from './blur.wgsl';\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\n\n// Contants from the blur.wgsl shader.\nconst tileDim = 128;\nconst batch = [4, 4];\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const blurPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: blurWGSL,\n }),\n entryPoint: 'main',\n },\n });\n\n const fullscreenQuadPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'frag_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const response = await fetch(\n new URL('../../../assets/img/Di-3d.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n const [srcWidth, srcHeight] = [imageBitmap.width, imageBitmap.height];\n const cubeTexture = device.createTexture({\n size: [srcWidth, srcHeight, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubeTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n\n const textures = [0, 1].map(() => {\n return device.createTexture({\n size: {\n width: srcWidth,\n height: srcHeight,\n },\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.TEXTURE_BINDING,\n });\n });\n\n const buffer0 = (() => {\n const buffer = device.createBuffer({\n size: 4,\n mappedAtCreation: true,\n usage: GPUBufferUsage.UNIFORM,\n });\n new Uint32Array(buffer.getMappedRange())[0] = 0;\n buffer.unmap();\n return buffer;\n })();\n\n const buffer1 = (() => {\n const buffer = device.createBuffer({\n size: 4,\n mappedAtCreation: true,\n usage: GPUBufferUsage.UNIFORM,\n });\n new Uint32Array(buffer.getMappedRange())[0] = 1;\n buffer.unmap();\n return buffer;\n })();\n\n const blurParamsBuffer = device.createBuffer({\n size: 8,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,\n });\n\n const computeConstants = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: sampler,\n },\n {\n binding: 1,\n resource: {\n buffer: blurParamsBuffer,\n },\n },\n ],\n });\n\n const computeBindGroup0 = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 1,\n resource: cubeTexture.createView(),\n },\n {\n binding: 2,\n resource: textures[0].createView(),\n },\n {\n binding: 3,\n resource: {\n buffer: buffer0,\n },\n },\n ],\n });\n\n const computeBindGroup1 = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 1,\n resource: textures[0].createView(),\n },\n {\n binding: 2,\n resource: textures[1].createView(),\n },\n {\n binding: 3,\n resource: {\n buffer: buffer1,\n },\n },\n ],\n });\n\n const computeBindGroup2 = device.createBindGroup({\n layout: blurPipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 1,\n resource: textures[1].createView(),\n },\n {\n binding: 2,\n resource: textures[0].createView(),\n },\n {\n binding: 3,\n resource: {\n buffer: buffer0,\n },\n },\n ],\n });\n\n const showResultBindGroup = device.createBindGroup({\n layout: fullscreenQuadPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: sampler,\n },\n {\n binding: 1,\n resource: textures[1].createView(),\n },\n ],\n });\n\n const settings = {\n filterSize: 15,\n iterations: 2,\n };\n\n let blockDim: number;\n const updateSettings = () => {\n blockDim = tileDim - (settings.filterSize - 1);\n device.queue.writeBuffer(\n blurParamsBuffer,\n 0,\n new Uint32Array([settings.filterSize, blockDim])\n );\n };\n gui.add(settings, 'filterSize', 1, 33).step(2).onChange(updateSettings);\n gui.add(settings, 'iterations', 1, 10).step(1);\n\n updateSettings();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n\n const computePass = commandEncoder.beginComputePass();\n computePass.setPipeline(blurPipeline);\n computePass.setBindGroup(0, computeConstants);\n\n computePass.setBindGroup(1, computeBindGroup0);\n computePass.dispatchWorkgroups(\n Math.ceil(srcWidth / blockDim),\n Math.ceil(srcHeight / batch[1])\n );\n\n computePass.setBindGroup(1, computeBindGroup1);\n computePass.dispatchWorkgroups(\n Math.ceil(srcHeight / blockDim),\n Math.ceil(srcWidth / batch[1])\n );\n\n for (let i = 0; i < settings.iterations - 1; ++i) {\n computePass.setBindGroup(1, computeBindGroup2);\n computePass.dispatchWorkgroups(\n Math.ceil(srcWidth / blockDim),\n Math.ceil(srcHeight / batch[1])\n );\n\n computePass.setBindGroup(1, computeBindGroup1);\n computePass.dispatchWorkgroups(\n Math.ceil(srcHeight / blockDim),\n Math.ceil(srcWidth / batch[1])\n );\n }\n\n computePass.end();\n\n const passEncoder = commandEncoder.beginRenderPass({\n colorAttachments: [\n {\n view: context.getCurrentTexture().createView(),\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n });\n\n passEncoder.setPipeline(fullscreenQuadPipeline);\n passEncoder.setBindGroup(0, showResultBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ImageBlur: () => JSX.Element = () =>\n makeSample({\n name: 'Image Blur',\n description:\n 'This example shows how to blur an image using a WebGPU compute shader.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './blur.wgsl',\n contents: blurWGSL,\n editable: true,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ImageBlur;\n"},{name:"./blur.wgsl",contents:i,editable:!0},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:a.Z,editable:!0}],filename:o});var c=s},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"},5685:function(e,n,t){"use strict";e.exports=t.p+"static/assets/img/Di-3d.ba319100a0ec2120.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/78.260e6b783b86a49d.js b/_next/static/chunks/78.260e6b783b86a49d.js deleted file mode 100644 index 55d30d60..00000000 --- a/_next/static/chunks/78.260e6b783b86a49d.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[78],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),l=t.n(c);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,i.useRouter)(),h=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[p,v]=(0,s.useState)(null),[g,w]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?w(h[1]):w(a[0].name),u&&c.current)for(c.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();d&&f.current&&(d.dom.style.position="absolute",d.showPanel(1),f.current.appendChild(d.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:u,stats:d});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),p?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(p)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){w(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":g==e.name},n))]})]})},f=e=>(0,r.jsx)(u,{...e});function d(e,n){if(!e)throw Error(n)}},6078:function(e,n,t){"use strict";var r="src/sample/worker/main.ts";t.r(n);var a=t(5671);let o=async e=>{let{canvas:n,pageState:r}=e;if(!r.active)return;let a=new Worker(t.tu(new URL(t.p+t.u(808),t.b)));a.addEventListener("message",e=>{"log"===e.data.type?console.log(e.data.message):console.error("Unknown Message Type: ".concat(e.data.type))});try{let o=n.transferControlToOffscreen(),i=window.devicePixelRatio||1;o.width=n.clientWidth*i,o.height=n.clientHeight*i,a.postMessage({type:"init",offscreenCanvas:o},[o])}catch(s){console.warn(s.message),a.terminate()}},i=()=>(0,a.Tl)({name:"WebGPU in a Worker",description:"This example shows one method of using WebGPU in a web worker and presenting to\n the main thread. It uses canvas.transferControlToOffscreen() to produce an offscreen canvas\n which is then transferred to the worker where all the WebGPU calls are made.",init:o,sources:[{name:r.substring(18),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n if (!pageState.active) return;\n\n // The web worker is created by passing a path to the worker's source file, which will then be\n // executed on a separate thread.\n const worker = new Worker(new URL('./worker.ts', import.meta.url));\n\n // The primary way to communicate with the worker is to send and receive messages.\n worker.addEventListener('message', (ev) => {\n // The format of the message can be whatever you'd like, but it's helpful to decide on a\n // consistent convention so that you can tell the message types apart as your apps grow in\n // complexity. Here we establish a convention that all messages to and from the worker will\n // have a `type` field that we can use to determine the content of the message.\n switch (ev.data.type) {\n case 'log': {\n // Workers don't have a built-in mechanism for logging to the console, so it's useful to\n // create a way to echo console messages.\n console.log(ev.data.message);\n break;\n }\n default: {\n console.error(`Unknown Message Type: ${ev.data.type}`);\n }\n }\n });\n\n try {\n // In order for the worker to display anything on the page, an OffscreenCanvas must be used.\n // Here we can create one from our normal canvas by calling transferControlToOffscreen().\n // Anything drawn to the OffscreenCanvas that call returns will automatically be displayed on\n // the source canvas on the page.\n const offscreenCanvas = canvas.transferControlToOffscreen();\n const devicePixelRatio = window.devicePixelRatio || 1;\n offscreenCanvas.width = canvas.clientWidth * devicePixelRatio;\n offscreenCanvas.height = canvas.clientHeight * devicePixelRatio;\n\n // Send a message to the worker telling it to initialize WebGPU with the OffscreenCanvas. The\n // array passed as the second argument here indicates that the OffscreenCanvas is to be\n // transferred to the worker, meaning this main thread will lose access to it and it will be\n // fully owned by the worker.\n worker.postMessage({ type: 'init', offscreenCanvas }, [offscreenCanvas]);\n } catch (err) {\n // TODO: This catch is added here because React will call init twice with the same canvas, and\n // the second time will fail the transferControlToOffscreen() because it's already been\n // transferred. I'd love to know how to get around that.\n console.warn(err.message);\n worker.terminate();\n }\n};\n\nconst WebGPUWorker: () => JSX.Element = () =>\n makeSample({\n name: 'WebGPU in a Worker',\n description: `This example shows one method of using WebGPU in a web worker and presenting to\n the main thread. It uses canvas.transferControlToOffscreen() to produce an offscreen canvas\n which is then transferred to the worker where all the WebGPU calls are made.`,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './worker.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./worker.ts').default,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../shaders/basic.vert.wgsl').default,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents:\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n require('!!raw-loader!../../shaders/vertexPositionColor.frag.wgsl')\n .default,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default WebGPUWorker;\n"},{name:"./worker.ts",contents:t(9168).Z},{name:"../../shaders/basic.vert.wgsl",contents:t(3569).Z},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:t(1945).Z},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=i},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},9168:function(e,n){"use strict";n.Z="import { mat4, vec3 } from 'wgpu-matrix';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\n// The worker process can instantiate a WebGPU device immediately, but it still needs an\n// OffscreenCanvas to be able to display anything. Here we listen for an 'init' message from the\n// main thread that will contain an OffscreenCanvas transferred from the page, and use that as the\n// signal to begin WebGPU initialization.\nself.addEventListener('message', (ev) => {\n switch (ev.data.type) {\n case 'init': {\n try {\n init(ev.data.offscreenCanvas);\n } catch (err) {\n self.postMessage({\n type: 'log',\n message: `Error while initializing WebGPU in worker process: ${err.message}`,\n });\n }\n break;\n }\n }\n});\n\n// Once we receive the OffscreenCanvas this init() function is called, which functions similarly\n// to the init() method for all the other samples. The remainder of this file is largely identical\n// to the rotatingCube sample.\nasync function init(canvas) {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n const context = canvas.getContext('webgpu');\n\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n\n // Note: It is important to return control to the browser regularly in order for the worker to\n // process events. You shouldn't simply loop infinitely with while(true) or similar! Using a\n // traditional requestAnimationFrame() loop in the worker is one way to ensure that events are\n // handled correctly by the worker.\n requestAnimationFrame(frame);\n}\n\nexport {};\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/78.8a974dff973260d0.js b/_next/static/chunks/78.8a974dff973260d0.js new file mode 100644 index 00000000..25e075b9 --- /dev/null +++ b/_next/static/chunks/78.8a974dff973260d0.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[78],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),l=t.n(c);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,i.useRouter)(),h=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[p,v]=(0,s.useState)(null),[g,w]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?w(h[1]):w(a[0].name),u&&c.current)for(c.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();d&&f.current&&(d.dom.style.position="absolute",d.showPanel(1),f.current.appendChild(d.dom));let t={active:!0},r=()=>{t.active=!1};try{let o=n.current;if(!o)throw Error("The canvas is not available");let i=e.init({canvas:o,pageState:t,gui:u,stats:d});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),p?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(p)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:a.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){w(e.name)},children:e.name})},n))})}),a.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":g==e.name},n))]})]})},f=e=>(0,r.jsx)(u,{...e});function d(e,n){if(!e)throw Error(n)}},6078:function(e,n,t){"use strict";var r="src/sample/worker/main.ts";t.r(n);var a=t(5671);let o=async e=>{let{canvas:n,pageState:r}=e;if(!r.active)return;let a=new Worker(t.tu(new URL(t.p+t.u(808),t.b)));a.addEventListener("message",e=>{"log"===e.data.type?console.log(e.data.message):console.error("Unknown Message Type: ".concat(e.data.type))});try{let o=n.transferControlToOffscreen(),i=window.devicePixelRatio;o.width=n.clientWidth*i,o.height=n.clientHeight*i,a.postMessage({type:"init",offscreenCanvas:o},[o])}catch(s){console.warn(s.message),a.terminate()}},i=()=>(0,a.Tl)({name:"WebGPU in a Worker",description:"This example shows one method of using WebGPU in a web worker and presenting to\n the main thread. It uses canvas.transferControlToOffscreen() to produce an offscreen canvas\n which is then transferred to the worker where all the WebGPU calls are made.",init:o,sources:[{name:r.substring(18),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n if (!pageState.active) return;\n\n // The web worker is created by passing a path to the worker's source file, which will then be\n // executed on a separate thread.\n const worker = new Worker(new URL('./worker.ts', import.meta.url));\n\n // The primary way to communicate with the worker is to send and receive messages.\n worker.addEventListener('message', (ev) => {\n // The format of the message can be whatever you'd like, but it's helpful to decide on a\n // consistent convention so that you can tell the message types apart as your apps grow in\n // complexity. Here we establish a convention that all messages to and from the worker will\n // have a `type` field that we can use to determine the content of the message.\n switch (ev.data.type) {\n case 'log': {\n // Workers don't have a built-in mechanism for logging to the console, so it's useful to\n // create a way to echo console messages.\n console.log(ev.data.message);\n break;\n }\n default: {\n console.error(`Unknown Message Type: ${ev.data.type}`);\n }\n }\n });\n\n try {\n // In order for the worker to display anything on the page, an OffscreenCanvas must be used.\n // Here we can create one from our normal canvas by calling transferControlToOffscreen().\n // Anything drawn to the OffscreenCanvas that call returns will automatically be displayed on\n // the source canvas on the page.\n const offscreenCanvas = canvas.transferControlToOffscreen();\n const devicePixelRatio = window.devicePixelRatio;\n offscreenCanvas.width = canvas.clientWidth * devicePixelRatio;\n offscreenCanvas.height = canvas.clientHeight * devicePixelRatio;\n\n // Send a message to the worker telling it to initialize WebGPU with the OffscreenCanvas. The\n // array passed as the second argument here indicates that the OffscreenCanvas is to be\n // transferred to the worker, meaning this main thread will lose access to it and it will be\n // fully owned by the worker.\n worker.postMessage({ type: 'init', offscreenCanvas }, [offscreenCanvas]);\n } catch (err) {\n // TODO: This catch is added here because React will call init twice with the same canvas, and\n // the second time will fail the transferControlToOffscreen() because it's already been\n // transferred. I'd love to know how to get around that.\n console.warn(err.message);\n worker.terminate();\n }\n};\n\nconst WebGPUWorker: () => JSX.Element = () =>\n makeSample({\n name: 'WebGPU in a Worker',\n description: `This example shows one method of using WebGPU in a web worker and presenting to\n the main thread. It uses canvas.transferControlToOffscreen() to produce an offscreen canvas\n which is then transferred to the worker where all the WebGPU calls are made.`,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './worker.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./worker.ts').default,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../shaders/basic.vert.wgsl').default,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents:\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n require('!!raw-loader!../../shaders/vertexPositionColor.frag.wgsl')\n .default,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default WebGPUWorker;\n"},{name:"./worker.ts",contents:t(9168).Z},{name:"../../shaders/basic.vert.wgsl",contents:t(3569).Z},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:t(1945).Z},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=i},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},9168:function(e,n){"use strict";n.Z="import { mat4, vec3 } from 'wgpu-matrix';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\n// The worker process can instantiate a WebGPU device immediately, but it still needs an\n// OffscreenCanvas to be able to display anything. Here we listen for an 'init' message from the\n// main thread that will contain an OffscreenCanvas transferred from the page, and use that as the\n// signal to begin WebGPU initialization.\nself.addEventListener('message', (ev) => {\n switch (ev.data.type) {\n case 'init': {\n try {\n init(ev.data.offscreenCanvas);\n } catch (err) {\n self.postMessage({\n type: 'log',\n message: `Error while initializing WebGPU in worker process: ${err.message}`,\n });\n }\n break;\n }\n }\n});\n\n// Once we receive the OffscreenCanvas this init() function is called, which functions similarly\n// to the init() method for all the other samples. The remainder of this file is largely identical\n// to the rotatingCube sample.\nasync function init(canvas) {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n const context = canvas.getContext('webgpu');\n\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n\n // Note: It is important to return control to the browser regularly in order for the worker to\n // process events. You shouldn't simply loop infinitely with while(true) or similar! Using a\n // traditional requestAnimationFrame() loop in the worker is one way to ensure that events are\n // handled correctly by the worker.\n requestAnimationFrame(frame);\n}\n\nexport {};\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]); \ No newline at end of file diff --git a/_next/static/chunks/841.097bc46a54981e6b.js b/_next/static/chunks/841.097bc46a54981e6b.js deleted file mode 100644 index a4d98599..00000000 --- a/_next/static/chunks/841.097bc46a54981e6b.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[841],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return c}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),l=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),p=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,y]=(0,s.useState)(null),[E,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(i[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();c&&f.current&&(c.dom.style.position="absolute",c.showPanel(1),f.current.appendChild(c.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:d,stats:c});o instanceof Promise&&o.catch(e=>{console.error(e),y(e)})}catch(s){console.error(s),y(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":E==e.name,onClick(){v(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":E==e.name},n))]})]})},f=e=>(0,r.jsx)(d,{...e});function c(e,n){if(!e)throw Error(n)}},841:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return u}});var r=t(5671),i="struct Time {\n value : f32,\n}\n\nstruct Uniforms {\n scale : f32,\n offsetX : f32,\n offsetY : f32,\n scalar : f32,\n scalarOffset : f32,\n}\n\n@binding(0) @group(0) var time : Time;\n@binding(0) @group(1) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) v_color : vec4,\n}\n\n@vertex\nfn vert_main(\n @location(0) position : vec4,\n @location(1) color : vec4\n) -> VertexOutput {\n var fade = (uniforms.scalarOffset + time.value * uniforms.scalar / 10.0) % 1.0;\n if (fade < 0.5) {\n fade = fade * 2.0;\n } else {\n fade = (1.0 - fade) * 2.0;\n }\n var xpos = position.x * uniforms.scale;\n var ypos = position.y * uniforms.scale;\n var angle = 3.14159 * 2.0 * fade;\n var xrot = xpos * cos(angle) - ypos * sin(angle);\n var yrot = xpos * sin(angle) + ypos * cos(angle);\n xpos = xrot + uniforms.offsetX;\n ypos = yrot + uniforms.offsetY;\n\n var output : VertexOutput;\n output.v_color = vec4(fade, 1.0 - fade, 0.0, 1.0) + color;\n output.Position = vec4(xpos, ypos, 0.0, 1.0);\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) v_color : vec4) -> @location(0) vec4 {\n return v_color;\n}\n",a="src/sample/animometer/main.ts";let o=async e=>{let n,t,a,{canvas:o,pageState:s,gui:u}=e,l=await navigator.gpu.requestAdapter();(0,r.hu)(l,"requestAdapter returned null");let d=await l.requestDevice();if(!s.active)return;let f=document.createElement("div");f.style.color="white",f.style.background="black",f.style.position="absolute",f.style.top="10px",f.style.left="10px";let c=document.createElement("pre");f.appendChild(c),o.parentNode?o.parentNode.appendChild(f):console.error("canvas.parentNode is null");let m=new URLSearchParams(window.location.search),p={numTriangles:Number(m.get("numTriangles"))||2e4,renderBundles:Boolean(m.get("renderBundles")),dynamicOffsets:Boolean(m.get("dynamicOffsets"))},g=o.getContext("webgpu"),y=window.devicePixelRatio||1;o.width=o.clientWidth*y,o.height=o.clientHeight*y;let E=navigator.gpu.getPreferredCanvasFormat();g.configure({device:d,format:E,alphaMode:"premultiplied",usage:GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});let v=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",minBindingSize:4}}]}),h=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",minBindingSize:20}}]}),T=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",hasDynamicOffset:!0,minBindingSize:20}}]}),B=4*Float32Array.BYTES_PER_ELEMENT,b=d.createPipelineLayout({bindGroupLayouts:[v,h]}),P=d.createPipelineLayout({bindGroupLayouts:[v,T]}),_=d.createShaderModule({code:i}),x={layout:"auto",vertex:{module:_,entryPoint:"vert_main",buffers:[{arrayStride:2*B,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x4"},{shaderLocation:1,offset:B,format:"float32x4"}]}]},fragment:{module:_,entryPoint:"frag_main",targets:[{format:E}]},primitive:{topology:"triangle-list",frontFace:"ccw",cullMode:"none"}},S=d.createRenderPipeline({...x,layout:b}),A=d.createRenderPipeline({...x,layout:P}),w=d.createBuffer({size:6*B,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});function G(){let e;let n=p.numTriangles,t=5*Float32Array.BYTES_PER_ELEMENT,r=256*Math.ceil(t/256),i=r/Float32Array.BYTES_PER_ELEMENT,a=d.createBuffer({size:n*r+Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.UNIFORM}),o=new Float32Array(n*i),s=Array(n);for(let u=0;u{F=G()};void 0===u?console.error("GUI not initialized"):(u.add(p,"numTriangles",0,2e5).step(1).onFinishChange(L),u.add(p,"renderBundles"),u.add(p,"dynamicOffsets"));let M=!0;requestAnimationFrame(function e(r){if(!s.active)return;let i=0;void 0!==n&&(i=r-n),n=r;let o=performance.now();F(r);let u=performance.now()-o;void 0===a&&(a=i),void 0===t&&(t=u),a=.8*a+.2*i,t=.8*t+.2*u,M&&(c.innerHTML="Avg Javascript: ".concat(t.toFixed(2)," ms\nAvg Frame: ").concat(a.toFixed(2)," ms"),M=!1,setTimeout(()=>{M=!0},100)),requestAnimationFrame(e)})},s=()=>(0,r.Tl)({name:"Animometer",description:"A WebGPU port of the Animometer MotionMark benchmark.",gui:!0,init:o,sources:[{name:a.substring(22),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport animometerWGSL from './animometer.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const perfDisplayContainer = document.createElement('div');\n perfDisplayContainer.style.color = 'white';\n perfDisplayContainer.style.background = 'black';\n perfDisplayContainer.style.position = 'absolute';\n perfDisplayContainer.style.top = '10px';\n perfDisplayContainer.style.left = '10px';\n\n const perfDisplay = document.createElement('pre');\n perfDisplayContainer.appendChild(perfDisplay);\n if (canvas.parentNode) {\n canvas.parentNode.appendChild(perfDisplayContainer);\n } else {\n console.error('canvas.parentNode is null');\n }\n\n const params = new URLSearchParams(window.location.search);\n const settings = {\n numTriangles: Number(params.get('numTriangles')) || 20000,\n renderBundles: Boolean(params.get('renderBundles')),\n dynamicOffsets: Boolean(params.get('dynamicOffsets')),\n };\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const timeBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n minBindingSize: 4,\n },\n },\n ],\n });\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n minBindingSize: 20,\n },\n },\n ],\n });\n\n const dynamicBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n hasDynamicOffset: true,\n minBindingSize: 20,\n },\n },\n ],\n });\n\n const vec4Size = 4 * Float32Array.BYTES_PER_ELEMENT;\n const pipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [timeBindGroupLayout, bindGroupLayout],\n });\n const dynamicPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [timeBindGroupLayout, dynamicBindGroupLayout],\n });\n\n const shaderModule = device.createShaderModule({\n code: animometerWGSL,\n });\n const pipelineDesc: GPURenderPipelineDescriptor = {\n layout: 'auto',\n vertex: {\n module: shaderModule,\n entryPoint: 'vert_main',\n buffers: [\n {\n // vertex buffer\n arrayStride: 2 * vec4Size,\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 0,\n offset: 0,\n format: 'float32x4',\n },\n {\n // vertex colors\n shaderLocation: 1,\n offset: vec4Size,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n fragment: {\n module: shaderModule,\n entryPoint: 'frag_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n frontFace: 'ccw',\n cullMode: 'none',\n },\n };\n\n const pipeline = device.createRenderPipeline({\n ...pipelineDesc,\n layout: pipelineLayout,\n });\n\n const dynamicPipeline = device.createRenderPipeline({\n ...pipelineDesc,\n layout: dynamicPipelineLayout,\n });\n\n const vertexBuffer = device.createBuffer({\n size: 2 * 3 * vec4Size,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n\n // prettier-ignore\n new Float32Array(vertexBuffer.getMappedRange()).set([\n // position data /**/ color data\n 0, 0.1, 0, 1, /**/ 1, 0, 0, 1,\n -0.1, -0.1, 0, 1, /**/ 0, 1, 0, 1,\n 0.1, -0.1, 0, 1, /**/ 0, 0, 1, 1,\n ]);\n vertexBuffer.unmap();\n\n function configure() {\n const numTriangles = settings.numTriangles;\n const uniformBytes = 5 * Float32Array.BYTES_PER_ELEMENT;\n const alignedUniformBytes = Math.ceil(uniformBytes / 256) * 256;\n const alignedUniformFloats =\n alignedUniformBytes / Float32Array.BYTES_PER_ELEMENT;\n const uniformBuffer = device.createBuffer({\n size: numTriangles * alignedUniformBytes + Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,\n });\n const uniformBufferData = new Float32Array(\n numTriangles * alignedUniformFloats\n );\n const bindGroups = new Array(numTriangles);\n for (let i = 0; i < numTriangles; ++i) {\n uniformBufferData[alignedUniformFloats * i + 0] =\n Math.random() * 0.2 + 0.2; // scale\n uniformBufferData[alignedUniformFloats * i + 1] =\n 0.9 * 2 * (Math.random() - 0.5); // offsetX\n uniformBufferData[alignedUniformFloats * i + 2] =\n 0.9 * 2 * (Math.random() - 0.5); // offsetY\n uniformBufferData[alignedUniformFloats * i + 3] =\n Math.random() * 1.5 + 0.5; // scalar\n uniformBufferData[alignedUniformFloats * i + 4] = Math.random() * 10; // scalarOffset\n\n bindGroups[i] = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: i * alignedUniformBytes,\n size: 6 * Float32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n }\n\n const dynamicBindGroup = device.createBindGroup({\n layout: dynamicBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: 6 * Float32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n const timeOffset = numTriangles * alignedUniformBytes;\n const timeBindGroup = device.createBindGroup({\n layout: timeBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: timeOffset,\n size: Float32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n // writeBuffer too large may OOM. TODO: The browser should internally chunk uploads.\n const maxMappingLength =\n (14 * 1024 * 1024) / Float32Array.BYTES_PER_ELEMENT;\n for (\n let offset = 0;\n offset < uniformBufferData.length;\n offset += maxMappingLength\n ) {\n const uploadCount = Math.min(\n uniformBufferData.length - offset,\n maxMappingLength\n );\n\n device.queue.writeBuffer(\n uniformBuffer,\n offset * Float32Array.BYTES_PER_ELEMENT,\n uniformBufferData.buffer,\n uniformBufferData.byteOffset + offset * Float32Array.BYTES_PER_ELEMENT,\n uploadCount * Float32Array.BYTES_PER_ELEMENT\n );\n }\n\n function recordRenderPass(\n passEncoder: GPURenderBundleEncoder | GPURenderPassEncoder\n ) {\n if (settings.dynamicOffsets) {\n passEncoder.setPipeline(dynamicPipeline);\n } else {\n passEncoder.setPipeline(pipeline);\n }\n passEncoder.setVertexBuffer(0, vertexBuffer);\n passEncoder.setBindGroup(0, timeBindGroup);\n const dynamicOffsets = [0];\n for (let i = 0; i < numTriangles; ++i) {\n if (settings.dynamicOffsets) {\n dynamicOffsets[0] = i * alignedUniformBytes;\n passEncoder.setBindGroup(1, dynamicBindGroup, dynamicOffsets);\n } else {\n passEncoder.setBindGroup(1, bindGroups[i]);\n }\n passEncoder.draw(3);\n }\n }\n\n let startTime: number | undefined = undefined;\n const uniformTime = new Float32Array([0]);\n\n const renderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined as GPUTextureView, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear' as const,\n storeOp: 'store' as const,\n },\n ],\n };\n\n const renderBundleEncoder = device.createRenderBundleEncoder({\n colorFormats: [presentationFormat],\n });\n recordRenderPass(renderBundleEncoder);\n const renderBundle = renderBundleEncoder.finish();\n\n return function doDraw(timestamp: number) {\n if (startTime === undefined) {\n startTime = timestamp;\n }\n uniformTime[0] = (timestamp - startTime) / 1000;\n device.queue.writeBuffer(uniformBuffer, timeOffset, uniformTime.buffer);\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n\n if (settings.renderBundles) {\n passEncoder.executeBundles([renderBundle]);\n } else {\n recordRenderPass(passEncoder);\n }\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n };\n }\n\n let doDraw = configure();\n\n const updateSettings = () => {\n doDraw = configure();\n };\n if (gui === undefined) {\n console.error('GUI not initialized');\n } else {\n gui\n .add(settings, 'numTriangles', 0, 200000)\n .step(1)\n .onFinishChange(updateSettings);\n gui.add(settings, 'renderBundles');\n gui.add(settings, 'dynamicOffsets');\n }\n\n let previousFrameTimestamp: number | undefined = undefined;\n let jsTimeAvg: number | undefined = undefined;\n let frameTimeAvg: number | undefined = undefined;\n let updateDisplay = true;\n\n function frame(timestamp: number) {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n let frameTime = 0;\n if (previousFrameTimestamp !== undefined) {\n frameTime = timestamp - previousFrameTimestamp;\n }\n previousFrameTimestamp = timestamp;\n\n const start = performance.now();\n doDraw(timestamp);\n const jsTime = performance.now() - start;\n if (frameTimeAvg === undefined) {\n frameTimeAvg = frameTime;\n }\n if (jsTimeAvg === undefined) {\n jsTimeAvg = jsTime;\n }\n\n const w = 0.2;\n frameTimeAvg = (1 - w) * frameTimeAvg + w * frameTime;\n jsTimeAvg = (1 - w) * jsTimeAvg + w * jsTime;\n\n if (updateDisplay) {\n perfDisplay.innerHTML = `Avg Javascript: ${jsTimeAvg.toFixed(\n 2\n )} ms\\nAvg Frame: ${frameTimeAvg.toFixed(2)} ms`;\n updateDisplay = false;\n setTimeout(() => {\n updateDisplay = true;\n }, 100);\n }\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst Animometer: () => JSX.Element = () =>\n makeSample({\n name: 'Animometer',\n description: 'A WebGPU port of the Animometer MotionMark benchmark.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './animometer.wgsl',\n contents: animometerWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default Animometer;\n"},{name:"./animometer.wgsl",contents:i,editable:!0}],filename:a});var u=s},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/841.73905322cab6a466.js b/_next/static/chunks/841.73905322cab6a466.js new file mode 100644 index 00000000..03d17e82 --- /dev/null +++ b/_next/static/chunks/841.73905322cab6a466.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[841],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return c}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),l=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),f=(0,s.useRef)(null),c=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),p=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,y]=(0,s.useState)(null),[E,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?v(p[1]):v(i[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();c&&f.current&&(c.dom.style.position="absolute",c.showPanel(1),f.current.appendChild(c.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:d,stats:c});o instanceof Promise&&o.catch(e=>{console.error(e),y(e)})}catch(s){console.error(s),y(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:l().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:l().sourceFileNav,children:(0,r.jsx)("ul",{children:i.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":E==e.name,onClick(){v(e.name)},children:e.name})},n))})}),i.map((e,n)=>(0,r.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":E==e.name},n))]})]})},f=e=>(0,r.jsx)(d,{...e});function c(e,n){if(!e)throw Error(n)}},841:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return u}});var r=t(5671),i="struct Time {\n value : f32,\n}\n\nstruct Uniforms {\n scale : f32,\n offsetX : f32,\n offsetY : f32,\n scalar : f32,\n scalarOffset : f32,\n}\n\n@binding(0) @group(0) var time : Time;\n@binding(0) @group(1) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) v_color : vec4,\n}\n\n@vertex\nfn vert_main(\n @location(0) position : vec4,\n @location(1) color : vec4\n) -> VertexOutput {\n var fade = (uniforms.scalarOffset + time.value * uniforms.scalar / 10.0) % 1.0;\n if (fade < 0.5) {\n fade = fade * 2.0;\n } else {\n fade = (1.0 - fade) * 2.0;\n }\n var xpos = position.x * uniforms.scale;\n var ypos = position.y * uniforms.scale;\n var angle = 3.14159 * 2.0 * fade;\n var xrot = xpos * cos(angle) - ypos * sin(angle);\n var yrot = xpos * sin(angle) + ypos * cos(angle);\n xpos = xrot + uniforms.offsetX;\n ypos = yrot + uniforms.offsetY;\n\n var output : VertexOutput;\n output.v_color = vec4(fade, 1.0 - fade, 0.0, 1.0) + color;\n output.Position = vec4(xpos, ypos, 0.0, 1.0);\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) v_color : vec4) -> @location(0) vec4 {\n return v_color;\n}\n",a="src/sample/animometer/main.ts";let o=async e=>{let n,t,a,{canvas:o,pageState:s,gui:u}=e,l=await navigator.gpu.requestAdapter();(0,r.hu)(l,"requestAdapter returned null");let d=await l.requestDevice();if(!s.active)return;let f=document.createElement("div");f.style.color="white",f.style.background="black",f.style.position="absolute",f.style.top="10px",f.style.left="10px";let c=document.createElement("pre");f.appendChild(c),o.parentNode?o.parentNode.appendChild(f):console.error("canvas.parentNode is null");let m=new URLSearchParams(window.location.search),p={numTriangles:Number(m.get("numTriangles"))||2e4,renderBundles:Boolean(m.get("renderBundles")),dynamicOffsets:Boolean(m.get("dynamicOffsets"))},g=o.getContext("webgpu"),y=window.devicePixelRatio;o.width=o.clientWidth*y,o.height=o.clientHeight*y;let E=navigator.gpu.getPreferredCanvasFormat();g.configure({device:d,format:E,alphaMode:"premultiplied",usage:GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});let v=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",minBindingSize:4}}]}),h=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",minBindingSize:20}}]}),T=d.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform",hasDynamicOffset:!0,minBindingSize:20}}]}),B=4*Float32Array.BYTES_PER_ELEMENT,b=d.createPipelineLayout({bindGroupLayouts:[v,h]}),P=d.createPipelineLayout({bindGroupLayouts:[v,T]}),_=d.createShaderModule({code:i}),x={layout:"auto",vertex:{module:_,entryPoint:"vert_main",buffers:[{arrayStride:2*B,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x4"},{shaderLocation:1,offset:B,format:"float32x4"}]}]},fragment:{module:_,entryPoint:"frag_main",targets:[{format:E}]},primitive:{topology:"triangle-list",frontFace:"ccw",cullMode:"none"}},S=d.createRenderPipeline({...x,layout:b}),A=d.createRenderPipeline({...x,layout:P}),w=d.createBuffer({size:6*B,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});function G(){let e;let n=p.numTriangles,t=5*Float32Array.BYTES_PER_ELEMENT,r=256*Math.ceil(t/256),i=r/Float32Array.BYTES_PER_ELEMENT,a=d.createBuffer({size:n*r+Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.UNIFORM}),o=new Float32Array(n*i),s=Array(n);for(let u=0;u{F=G()};void 0===u?console.error("GUI not initialized"):(u.add(p,"numTriangles",0,2e5).step(1).onFinishChange(L),u.add(p,"renderBundles"),u.add(p,"dynamicOffsets"));let M=!0;requestAnimationFrame(function e(r){if(!s.active)return;let i=0;void 0!==n&&(i=r-n),n=r;let o=performance.now();F(r);let u=performance.now()-o;void 0===a&&(a=i),void 0===t&&(t=u),a=.8*a+.2*i,t=.8*t+.2*u,M&&(c.innerHTML="Avg Javascript: ".concat(t.toFixed(2)," ms\nAvg Frame: ").concat(a.toFixed(2)," ms"),M=!1,setTimeout(()=>{M=!0},100)),requestAnimationFrame(e)})},s=()=>(0,r.Tl)({name:"Animometer",description:"A WebGPU port of the Animometer MotionMark benchmark.",gui:!0,init:o,sources:[{name:a.substring(22),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport animometerWGSL from './animometer.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const perfDisplayContainer = document.createElement('div');\n perfDisplayContainer.style.color = 'white';\n perfDisplayContainer.style.background = 'black';\n perfDisplayContainer.style.position = 'absolute';\n perfDisplayContainer.style.top = '10px';\n perfDisplayContainer.style.left = '10px';\n\n const perfDisplay = document.createElement('pre');\n perfDisplayContainer.appendChild(perfDisplay);\n if (canvas.parentNode) {\n canvas.parentNode.appendChild(perfDisplayContainer);\n } else {\n console.error('canvas.parentNode is null');\n }\n\n const params = new URLSearchParams(window.location.search);\n const settings = {\n numTriangles: Number(params.get('numTriangles')) || 20000,\n renderBundles: Boolean(params.get('renderBundles')),\n dynamicOffsets: Boolean(params.get('dynamicOffsets')),\n };\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const timeBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n minBindingSize: 4,\n },\n },\n ],\n });\n\n const bindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n minBindingSize: 20,\n },\n },\n ],\n });\n\n const dynamicBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n hasDynamicOffset: true,\n minBindingSize: 20,\n },\n },\n ],\n });\n\n const vec4Size = 4 * Float32Array.BYTES_PER_ELEMENT;\n const pipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [timeBindGroupLayout, bindGroupLayout],\n });\n const dynamicPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [timeBindGroupLayout, dynamicBindGroupLayout],\n });\n\n const shaderModule = device.createShaderModule({\n code: animometerWGSL,\n });\n const pipelineDesc: GPURenderPipelineDescriptor = {\n layout: 'auto',\n vertex: {\n module: shaderModule,\n entryPoint: 'vert_main',\n buffers: [\n {\n // vertex buffer\n arrayStride: 2 * vec4Size,\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 0,\n offset: 0,\n format: 'float32x4',\n },\n {\n // vertex colors\n shaderLocation: 1,\n offset: vec4Size,\n format: 'float32x4',\n },\n ],\n },\n ],\n },\n fragment: {\n module: shaderModule,\n entryPoint: 'frag_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n frontFace: 'ccw',\n cullMode: 'none',\n },\n };\n\n const pipeline = device.createRenderPipeline({\n ...pipelineDesc,\n layout: pipelineLayout,\n });\n\n const dynamicPipeline = device.createRenderPipeline({\n ...pipelineDesc,\n layout: dynamicPipelineLayout,\n });\n\n const vertexBuffer = device.createBuffer({\n size: 2 * 3 * vec4Size,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n\n // prettier-ignore\n new Float32Array(vertexBuffer.getMappedRange()).set([\n // position data /**/ color data\n 0, 0.1, 0, 1, /**/ 1, 0, 0, 1,\n -0.1, -0.1, 0, 1, /**/ 0, 1, 0, 1,\n 0.1, -0.1, 0, 1, /**/ 0, 0, 1, 1,\n ]);\n vertexBuffer.unmap();\n\n function configure() {\n const numTriangles = settings.numTriangles;\n const uniformBytes = 5 * Float32Array.BYTES_PER_ELEMENT;\n const alignedUniformBytes = Math.ceil(uniformBytes / 256) * 256;\n const alignedUniformFloats =\n alignedUniformBytes / Float32Array.BYTES_PER_ELEMENT;\n const uniformBuffer = device.createBuffer({\n size: numTriangles * alignedUniformBytes + Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,\n });\n const uniformBufferData = new Float32Array(\n numTriangles * alignedUniformFloats\n );\n const bindGroups = new Array(numTriangles);\n for (let i = 0; i < numTriangles; ++i) {\n uniformBufferData[alignedUniformFloats * i + 0] =\n Math.random() * 0.2 + 0.2; // scale\n uniformBufferData[alignedUniformFloats * i + 1] =\n 0.9 * 2 * (Math.random() - 0.5); // offsetX\n uniformBufferData[alignedUniformFloats * i + 2] =\n 0.9 * 2 * (Math.random() - 0.5); // offsetY\n uniformBufferData[alignedUniformFloats * i + 3] =\n Math.random() * 1.5 + 0.5; // scalar\n uniformBufferData[alignedUniformFloats * i + 4] = Math.random() * 10; // scalarOffset\n\n bindGroups[i] = device.createBindGroup({\n layout: bindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: i * alignedUniformBytes,\n size: 6 * Float32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n }\n\n const dynamicBindGroup = device.createBindGroup({\n layout: dynamicBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: 6 * Float32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n const timeOffset = numTriangles * alignedUniformBytes;\n const timeBindGroup = device.createBindGroup({\n layout: timeBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: timeOffset,\n size: Float32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n // writeBuffer too large may OOM. TODO: The browser should internally chunk uploads.\n const maxMappingLength =\n (14 * 1024 * 1024) / Float32Array.BYTES_PER_ELEMENT;\n for (\n let offset = 0;\n offset < uniformBufferData.length;\n offset += maxMappingLength\n ) {\n const uploadCount = Math.min(\n uniformBufferData.length - offset,\n maxMappingLength\n );\n\n device.queue.writeBuffer(\n uniformBuffer,\n offset * Float32Array.BYTES_PER_ELEMENT,\n uniformBufferData.buffer,\n uniformBufferData.byteOffset + offset * Float32Array.BYTES_PER_ELEMENT,\n uploadCount * Float32Array.BYTES_PER_ELEMENT\n );\n }\n\n function recordRenderPass(\n passEncoder: GPURenderBundleEncoder | GPURenderPassEncoder\n ) {\n if (settings.dynamicOffsets) {\n passEncoder.setPipeline(dynamicPipeline);\n } else {\n passEncoder.setPipeline(pipeline);\n }\n passEncoder.setVertexBuffer(0, vertexBuffer);\n passEncoder.setBindGroup(0, timeBindGroup);\n const dynamicOffsets = [0];\n for (let i = 0; i < numTriangles; ++i) {\n if (settings.dynamicOffsets) {\n dynamicOffsets[0] = i * alignedUniformBytes;\n passEncoder.setBindGroup(1, dynamicBindGroup, dynamicOffsets);\n } else {\n passEncoder.setBindGroup(1, bindGroups[i]);\n }\n passEncoder.draw(3);\n }\n }\n\n let startTime: number | undefined = undefined;\n const uniformTime = new Float32Array([0]);\n\n const renderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined as GPUTextureView, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear' as const,\n storeOp: 'store' as const,\n },\n ],\n };\n\n const renderBundleEncoder = device.createRenderBundleEncoder({\n colorFormats: [presentationFormat],\n });\n recordRenderPass(renderBundleEncoder);\n const renderBundle = renderBundleEncoder.finish();\n\n return function doDraw(timestamp: number) {\n if (startTime === undefined) {\n startTime = timestamp;\n }\n uniformTime[0] = (timestamp - startTime) / 1000;\n device.queue.writeBuffer(uniformBuffer, timeOffset, uniformTime.buffer);\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n\n if (settings.renderBundles) {\n passEncoder.executeBundles([renderBundle]);\n } else {\n recordRenderPass(passEncoder);\n }\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n };\n }\n\n let doDraw = configure();\n\n const updateSettings = () => {\n doDraw = configure();\n };\n if (gui === undefined) {\n console.error('GUI not initialized');\n } else {\n gui\n .add(settings, 'numTriangles', 0, 200000)\n .step(1)\n .onFinishChange(updateSettings);\n gui.add(settings, 'renderBundles');\n gui.add(settings, 'dynamicOffsets');\n }\n\n let previousFrameTimestamp: number | undefined = undefined;\n let jsTimeAvg: number | undefined = undefined;\n let frameTimeAvg: number | undefined = undefined;\n let updateDisplay = true;\n\n function frame(timestamp: number) {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n let frameTime = 0;\n if (previousFrameTimestamp !== undefined) {\n frameTime = timestamp - previousFrameTimestamp;\n }\n previousFrameTimestamp = timestamp;\n\n const start = performance.now();\n doDraw(timestamp);\n const jsTime = performance.now() - start;\n if (frameTimeAvg === undefined) {\n frameTimeAvg = frameTime;\n }\n if (jsTimeAvg === undefined) {\n jsTimeAvg = jsTime;\n }\n\n const w = 0.2;\n frameTimeAvg = (1 - w) * frameTimeAvg + w * frameTime;\n jsTimeAvg = (1 - w) * jsTimeAvg + w * jsTime;\n\n if (updateDisplay) {\n perfDisplay.innerHTML = `Avg Javascript: ${jsTimeAvg.toFixed(\n 2\n )} ms\\nAvg Frame: ${frameTimeAvg.toFixed(2)} ms`;\n updateDisplay = false;\n setTimeout(() => {\n updateDisplay = true;\n }, 100);\n }\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst Animometer: () => JSX.Element = () =>\n makeSample({\n name: 'Animometer',\n description: 'A WebGPU port of the Animometer MotionMark benchmark.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './animometer.wgsl',\n contents: animometerWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default Animometer;\n"},{name:"./animometer.wgsl",contents:i,editable:!0}],filename:a});var u=s},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/874.33e8d878d9434433.js b/_next/static/chunks/874.5e02a26c980d5570.js similarity index 91% rename from _next/static/chunks/874.33e8d878d9434433.js rename to _next/static/chunks/874.5e02a26c980d5570.js index 00408a05..12dace7f 100644 --- a/_next/static/chunks/874.33e8d878d9434433.js +++ b/_next/static/chunks/874.5e02a26c980d5570.js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[874],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return m}});var a=t(5893),r=t(9008),i=t.n(r),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),r=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),p=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,g]=(0,s.useState)(null),[v,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?b(p[1]):b(r[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&l.current&&(m.dom.style.position="absolute",m.showPanel(1),l.current.appendChild(m.dom));let t={active:!0},a=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:d,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),h?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(h)})]}):null]}),(0,a.jsxs)("div",{className:c().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:c().sourceFileNav,children:(0,a.jsx)("ul",{children:r.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){b(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,a.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":v==e.name},n))]})]})},l=e=>(0,a.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},6874:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return S}});var a,r,i=t(5671),o="// A storage buffer holding an array of atomic.\n// The array elements are a sequence of red, green, blue components, for each\n// lightmap texel, for each quad surface.\n@group(1) @binding(0)\nvar accumulation : array>;\n\n// The output lightmap texture.\n@group(1) @binding(1)\nvar lightmap : texture_storage_2d_array;\n\n// Uniform data used by the accumulation_to_lightmap entry point\nstruct Uniforms {\n // Scalar for converting accumulation values to output lightmap values\n accumulation_to_lightmap_scale : f32,\n // Accumulation buffer rescaling value\n accumulation_buffer_scale : f32,\n // The width of the light\n light_width : f32,\n // The height of the light\n light_height : f32,\n // The center of the light\n light_center : vec3f,\n}\n\n// accumulation_to_lightmap uniforms binding point\n@group(1) @binding(2) var uniforms : Uniforms;\n\n// Number of photons emitted per workgroup\noverride PhotonsPerWorkgroup : u32;\n\n// Maximum value that can be added to the accumulation buffer from a single photon\noverride PhotonEnergy : f32;\n\n// Number of bounces of each photon\nconst PhotonBounces = 4;\n\n// Amount of light absorbed with each photon bounce (0: 0%, 1: 100%)\nconst LightAbsorbtion = 0.5;\n\n// Radiosity compute shader.\n// Each invocation creates a photon from the light source, and accumulates\n// bounce lighting into the 'accumulation' buffer.\n@compute @workgroup_size(PhotonsPerWorkgroup)\nfn radiosity(@builtin(global_invocation_id) invocation_id : vec3u) {\n init_rand(invocation_id);\n photon();\n}\n\n// Spawns a photon at the light source, performs ray tracing in the scene,\n// accumulating light values into 'accumulation' for each quad surface hit.\nfn photon() {\n // Create a random ray from the light.\n var ray = new_light_ray();\n // Give the photon an initial energy value.\n var color = PhotonEnergy * vec3f(1, 0.8, 0.6);\n\n // Start bouncing.\n for (var i = 0; i < (PhotonBounces+1); i++) {\n // Find the closest hit of the ray with the scene's quads.\n let hit = raytrace(ray);\n let quad = quads[hit.quad];\n\n // Bounce the ray.\n ray.start = hit.pos + quad.plane.xyz * 1e-5;\n ray.dir = normalize(reflect(ray.dir, quad.plane.xyz) + rand_unit_sphere() * 0.75);\n\n // Photon color is multiplied by the quad's color.\n color *= quad.color;\n\n // Accumulate the aborbed light into the 'accumulation' buffer.\n accumulate(hit.uv, hit.quad, color * LightAbsorbtion);\n\n // What wasn't absorbed is reflected.\n color *= 1 - LightAbsorbtion;\n }\n}\n\n// Performs an atomicAdd() with 'color' into the 'accumulation' buffer at 'uv'\n// and 'quad'.\nfn accumulate(uv : vec2f, quad : u32, color : vec3f) {\n let dims = textureDimensions(lightmap);\n let base_idx = accumulation_base_index(vec2u(uv * vec2f(dims)), quad);\n atomicAdd(&accumulation[base_idx + 0], u32(color.r + 0.5));\n atomicAdd(&accumulation[base_idx + 1], u32(color.g + 0.5));\n atomicAdd(&accumulation[base_idx + 2], u32(color.b + 0.5));\n}\n\n// Returns the base element index for the texel at 'coord' for 'quad'\nfn accumulation_base_index(coord : vec2u, quad : u32) -> u32 {\n let dims = textureDimensions(lightmap);\n let c = min(vec2u(dims) - 1, coord);\n return 3 * (c.x + dims.x * c.y + dims.x * dims.y * quad);\n}\n\n// Returns a new Ray at a random point on the light, in a random downwards\n// direction.\nfn new_light_ray() -> Ray {\n let center = uniforms.light_center;\n let pos = center + vec3f(uniforms.light_width * (rand() - 0.5),\n 0,\n uniforms.light_height * (rand() - 0.5));\n var dir = rand_cosine_weighted_hemisphere().xzy;\n dir.y = -dir.y;\n return Ray(pos, dir);\n}\n\noverride AccumulationToLightmapWorkgroupSizeX : u32;\noverride AccumulationToLightmapWorkgroupSizeY : u32;\n\n// Compute shader used to copy the atomic data in 'accumulation' to\n// 'lightmap'. 'accumulation' might also be scaled to reduce integer overflow.\n@compute @workgroup_size(AccumulationToLightmapWorkgroupSizeX, AccumulationToLightmapWorkgroupSizeY)\nfn accumulation_to_lightmap(@builtin(global_invocation_id) invocation_id : vec3u,\n @builtin(workgroup_id) workgroup_id : vec3u) {\n let dims = textureDimensions(lightmap);\n let quad = workgroup_id.z; // The workgroup 'z' value holds the quad index.\n let coord = invocation_id.xy;\n if (all(coord < dims)) {\n // Load the color value out of 'accumulation'\n let base_idx = accumulation_base_index(coord, quad);\n let color = vec3(f32(atomicLoad(&accumulation[base_idx + 0])),\n f32(atomicLoad(&accumulation[base_idx + 1])),\n f32(atomicLoad(&accumulation[base_idx + 2])));\n\n // Multiply the color by 'uniforms.accumulation_to_lightmap_scale' and write it to\n // the lightmap.\n textureStore(lightmap, coord, quad, vec4(color * uniforms.accumulation_to_lightmap_scale, 1));\n\n // If the 'accumulation' buffer is nearing saturation, then\n // 'uniforms.accumulation_buffer_scale' will be less than 1, scaling the values\n // to something less likely to overflow the u32.\n if (uniforms.accumulation_buffer_scale != 1.0) {\n let scaled = color * uniforms.accumulation_buffer_scale + 0.5;\n atomicStore(&accumulation[base_idx + 0], u32(scaled.r));\n atomicStore(&accumulation[base_idx + 1], u32(scaled.g));\n atomicStore(&accumulation[base_idx + 2], u32(scaled.b));\n }\n }\n}\n",s="// The lightmap data\n@group(1) @binding(0) var lightmap : texture_2d_array;\n\n// The sampler used to sample the lightmap\n@group(1) @binding(1) var smpl : sampler;\n\n// Vertex shader input data\nstruct VertexIn {\n @location(0) position : vec4f,\n @location(1) uv : vec3f,\n @location(2) emissive : vec3f,\n}\n\n// Vertex shader output data\nstruct VertexOut {\n @builtin(position) position : vec4f,\n @location(0) uv : vec2f,\n @location(1) emissive : vec3f,\n @interpolate(flat)\n @location(2) quad : u32,\n}\n\n@vertex\nfn vs_main(input : VertexIn) -> VertexOut {\n var output : VertexOut;\n output.position = common_uniforms.mvp * input.position;\n output.uv = input.uv.xy;\n output.quad = u32(input.uv.z + 0.5);\n output.emissive = input.emissive;\n return output;\n}\n\n@fragment\nfn fs_main(vertex_out : VertexOut) -> @location(0) vec4f {\n return textureSample(lightmap, smpl, vertex_out.uv, vertex_out.quad) + vec4f(vertex_out.emissive, 1);\n}\n",u="// The lightmap data\n@group(1) @binding(0) var lightmap : texture_2d_array;\n\n// The sampler used to sample the lightmap\n@group(1) @binding(1) var smpl : sampler;\n\n// The output framebuffer\n@group(1) @binding(2) var framebuffer : texture_storage_2d;\n\noverride WorkgroupSizeX : u32;\noverride WorkgroupSizeY : u32;\n\nconst NumReflectionRays = 5;\n\n@compute @workgroup_size(WorkgroupSizeX, WorkgroupSizeY)\nfn main(@builtin(global_invocation_id) invocation_id : vec3u) {\n if (all(invocation_id.xy < textureDimensions(framebuffer))) {\n init_rand(invocation_id);\n\n // Calculate the fragment's NDC coordinates for the intersection of the near\n // clip plane and far clip plane\n let uv = vec2f(invocation_id.xy) / vec2f(textureDimensions(framebuffer).xy);\n let ndcXY = (uv - 0.5) * vec2(2, -2);\n\n // Transform the coordinates back into world space\n var near = common_uniforms.inv_mvp * vec4f(ndcXY, 0.0, 1);\n var far = common_uniforms.inv_mvp * vec4f(ndcXY, 1, 1);\n near /= near.w;\n far /= far.w;\n\n // Create a ray that starts at the near clip plane, heading in the fragment's\n // z-direction, and raytrace to find the nearest quad that the ray intersects.\n let ray = Ray(near.xyz, normalize(far.xyz - near.xyz));\n let hit = raytrace(ray);\n\n let hit_color = sample_hit(hit);\n var normal = quads[hit.quad].plane.xyz;\n\n // Fire a few rays off the surface to collect some reflections\n let bounce = reflect(ray.dir, normal);\n var reflection : vec3f;\n for (var i = 0; i < NumReflectionRays; i++) {\n let reflection_dir = normalize(bounce + rand_unit_sphere()*0.1);\n let reflection_ray = Ray(hit.pos + bounce * 1e-5, reflection_dir);\n let reflection_hit = raytrace(reflection_ray);\n reflection += sample_hit(reflection_hit);\n }\n let color = mix(reflection / NumReflectionRays, hit_color, 0.95);\n\n textureStore(framebuffer, invocation_id.xy, vec4(color, 1));\n }\n}\n\n\n// Returns the sampled hit quad's lightmap at 'hit.uv', and adds the quad's\n// emissive value.\nfn sample_hit(hit : HitInfo) -> vec3f {\n let quad = quads[hit.quad];\n // Sample the quad's lightmap, and add emissive.\n return textureSampleLevel(lightmap, smpl, hit.uv, hit.quad, 0).rgb +\n quad.emissive * quad.color;\n}\n",c="// The linear-light input framebuffer\n@group(0) @binding(0) var input : texture_2d;\n\n// The tonemapped, gamma-corrected output framebuffer\n@group(0) @binding(1) var output : texture_storage_2d<{OUTPUT_FORMAT}, write>;\n\nconst TonemapExposure = 0.5;\n\nconst Gamma = 2.2;\n\noverride WorkgroupSizeX : u32;\noverride WorkgroupSizeY : u32;\n\n@compute @workgroup_size(WorkgroupSizeX, WorkgroupSizeY)\nfn main(@builtin(global_invocation_id) invocation_id : vec3u) {\n let color = textureLoad(input, invocation_id.xy, 0).rgb;\n let tonemapped = reinhard_tonemap(color);\n textureStore(output, invocation_id.xy, vec4f(tonemapped, 1));\n}\n\nfn reinhard_tonemap(linearColor: vec3f) -> vec3f {\n let color = linearColor * TonemapExposure;\n let mapped = color / (1+color);\n return pow(mapped, vec3f(1 / Gamma));\n}\n",d="const pi = 3.14159265359;\n\n// Quad describes 2D rectangle on a plane\nstruct Quad {\n // The surface plane\n plane : vec4f,\n // A plane with a normal in the 'u' direction, intersecting the origin, at\n // right-angles to the surface plane.\n // The dot product of 'right' with a 'vec4(pos, 1)' will range between [-1..1]\n // if the projected point is within the quad.\n right : vec4f,\n // A plane with a normal in the 'v' direction, intersecting the origin, at\n // right-angles to the surface plane.\n // The dot product of 'up' with a 'vec4(pos, 1)' will range between [-1..1]\n // if the projected point is within the quad.\n up : vec4f,\n // The diffuse color of the quad\n color : vec3f,\n // Emissive value. 0=no emissive, 1=full emissive.\n emissive : f32,\n};\n\n// Ray is a start point and direction.\nstruct Ray {\n start : vec3f,\n dir : vec3f,\n}\n\n// Value for HitInfo.quad if no intersection occured.\nconst kNoHit = 0xffffffff;\n\n// HitInfo describes the hit location of a ray-quad intersection\nstruct HitInfo {\n // Distance along the ray to the intersection\n dist : f32,\n // The quad index that was hit\n quad : u32,\n // The position of the intersection\n pos : vec3f,\n // The UVs of the quad at the point of intersection\n uv : vec2f,\n}\n\n// CommonUniforms uniform buffer data\nstruct CommonUniforms {\n // Model View Projection matrix\n mvp : mat4x4f,\n // Inverse of mvp\n inv_mvp : mat4x4f,\n // Random seed for the workgroup\n seed : vec3u,\n}\n\n// The common uniform buffer binding.\n@group(0) @binding(0) var common_uniforms : CommonUniforms;\n\n// The quad buffer binding.\n@group(0) @binding(1) var quads : array;\n\n// intersect_ray_quad will check to see if the ray 'r' intersects the quad 'q'.\n// If an intersection occurs, and the intersection is closer than 'closest' then\n// the intersection information is returned, otherwise 'closest' is returned.\nfn intersect_ray_quad(r : Ray, quad : u32, closest : HitInfo) -> HitInfo {\n let q = quads[quad];\n let plane_dist = dot(q.plane, vec4(r.start, 1));\n let ray_dist = plane_dist / -dot(q.plane.xyz, r.dir);\n let pos = r.start + r.dir * ray_dist;\n let uv = vec2(dot(vec4f(pos, 1), q.right),\n dot(vec4f(pos, 1), q.up)) * 0.5 + 0.5;\n let hit = plane_dist > 0 &&\n ray_dist > 0 &&\n ray_dist < closest.dist &&\n all((uv > vec2f()) & (uv < vec2f(1)));\n return HitInfo(\n select(closest.dist, ray_dist, hit),\n select(closest.quad, quad, hit),\n select(closest.pos, pos, hit),\n select(closest.uv, uv, hit),\n );\n}\n\n// raytrace finds the closest intersecting quad for the given ray\nfn raytrace(ray : Ray) -> HitInfo {\n var hit = HitInfo();\n hit.dist = 1e20;\n hit.quad = kNoHit;\n for (var quad = 0u; quad < arrayLength(&quads); quad++) {\n hit = intersect_ray_quad(ray, quad, hit);\n }\n return hit;\n}\n\n// A psuedo random number. Initialized with init_rand(), updated with rand().\nvar rnd : vec3u;\n\n// Initializes the random number generator.\nfn init_rand(invocation_id : vec3u) {\n const A = vec3(1741651 * 1009,\n 140893 * 1609 * 13,\n 6521 * 983 * 7 * 2);\n rnd = (invocation_id * A) ^ common_uniforms.seed;\n}\n\n// Returns a random number between 0 and 1.\nfn rand() -> f32 {\n const C = vec3(60493 * 9377,\n 11279 * 2539 * 23,\n 7919 * 631 * 5 * 3);\n\n rnd = (rnd * C) ^ (rnd.yzx >> vec3(4u));\n return f32(rnd.x ^ rnd.y) / f32(0xffffffff);\n}\n\n// Returns a random point within a unit sphere centered at (0,0,0).\nfn rand_unit_sphere() -> vec3f {\n var u = rand();\n var v = rand();\n var theta = u * 2.0 * pi;\n var phi = acos(2.0 * v - 1.0);\n var r = pow(rand(), 1.0/3.0);\n var sin_theta = sin(theta);\n var cos_theta = cos(theta);\n var sin_phi = sin(phi);\n var cos_phi = cos(phi);\n var x = r * sin_phi * sin_theta;\n var y = r * sin_phi * cos_theta;\n var z = r * cos_phi;\n return vec3f(x, y, z);\n}\n\nfn rand_concentric_disk() -> vec2f {\n let u = vec2f(rand(), rand());\n let uOffset = 2.f * u - vec2f(1, 1);\n\n if (uOffset.x == 0 && uOffset.y == 0){\n return vec2f(0, 0);\n }\n\n var theta = 0.0;\n var r = 0.0;\n if (abs(uOffset.x) > abs(uOffset.y)) {\n r = uOffset.x;\n theta = (pi / 4) * (uOffset.y / uOffset.x);\n } else {\n r = uOffset.y;\n theta = (pi / 2) - (pi / 4) * (uOffset.x / uOffset.y);\n }\n return r * vec2f(cos(theta), sin(theta));\n}\n\nfn rand_cosine_weighted_hemisphere() -> vec3f {\n let d = rand_concentric_disk();\n let z = sqrt(max(0.0, 1.0 - d.x * d.x - d.y * d.y));\n return vec3f(d.x, d.y, z);\n}\n",l=t(6416);function m(e){let n=1/l.R3.lenSq(e);return l.R3.mul(l.R3.fromValues(n,n,n),e)}function f(e){let n=l.R3.fromValues(Math.cos(e.rotation)*(e.width/2),0,Math.sin(e.rotation)*(e.depth/2)),t=l.R3.fromValues(0,e.height/2,0),a=l.R3.fromValues(Math.sin(e.rotation)*(e.width/2),0,-Math.cos(e.rotation)*(e.depth/2)),i=e.color instanceof Array?e.color:Array(6).fill(e.color),o=n=>"concave"===e.type?n:l.R3.negate(n);return[{center:l.R3.add(e.center,n),right:o(l.R3.negate(a)),up:t,color:i[r.PositiveX]},{center:l.R3.add(e.center,t),right:o(n),up:l.R3.negate(a),color:i[r.PositiveY]},{center:l.R3.add(e.center,a),right:o(n),up:t,color:i[r.PositiveZ]},{center:l.R3.sub(e.center,n),right:o(a),up:t,color:i[r.NegativeX]},{center:l.R3.sub(e.center,t),right:o(n),up:a,color:i[r.NegativeY]},{center:l.R3.sub(e.center,a),right:o(l.R3.negate(n)),up:t,color:i[r.NegativeZ]}]}(a=r||(r={}))[a.PositiveX=0]="PositiveX",a[a.PositiveY=1]="PositiveY",a[a.PositiveZ=2]="PositiveZ",a[a.NegativeX=3]="NegativeX",a[a.NegativeY=4]="NegativeY",a[a.NegativeZ=5]="NegativeZ";let p={center:l.R3.fromValues(0,9.95,0),right:l.R3.fromValues(1,0,0),up:l.R3.fromValues(0,0,1),color:l.R3.fromValues(5,5,5),emissive:1};class h{constructor(e){this.quads=[...f({center:l.R3.fromValues(0,5,0),width:10,height:10,depth:10,rotation:0,color:[l.R3.fromValues(0,.5,0),l.R3.fromValues(.5,.5,.5),l.R3.fromValues(.5,.5,.5),l.R3.fromValues(.5,0,0),l.R3.fromValues(.5,.5,.5),l.R3.fromValues(.5,.5,.5)],type:"concave"}),...f({center:l.R3.fromValues(1.5,1.5,1),width:3,height:3,depth:3,rotation:.3,color:l.R3.fromValues(.8,.8,.8),type:"convex"}),...f({center:l.R3.fromValues(-2,3,-2),width:3,height:6,depth:3,rotation:-.4,color:l.R3.fromValues(.8,.8,.8),type:"convex"}),p],this.lightCenter=p.center,this.lightWidth=2*l.R3.len(p.right),this.lightHeight=2*l.R3.len(p.up);let n=e.createBuffer({size:64*this.quads.length,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),t=new Float32Array(n.getMappedRange()),a=new Float32Array(40*this.quads.length),r=new Uint32Array(9*this.quads.length),i=0,o=0,s=0,u=0,c=0;for(let d=0;d x\n const x = vec3.fromValues(\n Math.cos(params.rotation) * (params.width / 2),\n 0,\n Math.sin(params.rotation) * (params.depth / 2)\n );\n const y = vec3.fromValues(0, params.height / 2, 0);\n const z = vec3.fromValues(\n Math.sin(params.rotation) * (params.width / 2),\n 0,\n -Math.cos(params.rotation) * (params.depth / 2)\n );\n const colors =\n params.color instanceof Array\n ? params.color\n : new Array(6).fill(params.color);\n const sign = (v: Vec3) => {\n return params.type === 'concave' ? v : vec3.negate(v);\n };\n return [\n {\n // PositiveX\n center: vec3.add(params.center, x),\n right: sign(vec3.negate(z)),\n up: y,\n color: colors[CubeFace.PositiveX],\n },\n {\n // PositiveY\n center: vec3.add(params.center, y),\n right: sign(x),\n up: vec3.negate(z),\n color: colors[CubeFace.PositiveY],\n },\n {\n // PositiveZ\n center: vec3.add(params.center, z),\n right: sign(x),\n up: y,\n color: colors[CubeFace.PositiveZ],\n },\n {\n // NegativeX\n center: vec3.sub(params.center, x),\n right: sign(z),\n up: y,\n color: colors[CubeFace.NegativeX],\n },\n {\n // NegativeY\n center: vec3.sub(params.center, y),\n right: sign(x),\n up: z,\n color: colors[CubeFace.NegativeY],\n },\n {\n // NegativeZ\n center: vec3.sub(params.center, z),\n right: sign(vec3.negate(x)),\n up: y,\n color: colors[CubeFace.NegativeZ],\n },\n ];\n}\n\nconst light: Quad = {\n center: vec3.fromValues(0, 9.95, 0),\n right: vec3.fromValues(1, 0, 0),\n up: vec3.fromValues(0, 0, 1),\n color: vec3.fromValues(5.0, 5.0, 5.0),\n emissive: 1.0,\n};\n\n/**\n * Scene holds the cornell-box scene information.\n */\nexport default class Scene {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n readonly vertexCount: number;\n readonly indexCount: number;\n readonly vertices: GPUBuffer;\n readonly indices: GPUBuffer;\n readonly vertexBufferLayout: GPUVertexBufferLayout[];\n readonly quadBuffer: GPUBuffer;\n readonly quads = [\n ...box({\n center: vec3.fromValues(0, 5, 0),\n width: 10,\n height: 10,\n depth: 10,\n rotation: 0,\n color: [\n vec3.fromValues(0.0, 0.5, 0.0), // PositiveX\n vec3.fromValues(0.5, 0.5, 0.5), // PositiveY\n vec3.fromValues(0.5, 0.5, 0.5), // PositiveZ\n vec3.fromValues(0.5, 0.0, 0.0), // NegativeX\n vec3.fromValues(0.5, 0.5, 0.5), // NegativeY\n vec3.fromValues(0.5, 0.5, 0.5), // NegativeZ\n ],\n type: 'concave',\n }),\n ...box({\n center: vec3.fromValues(1.5, 1.5, 1),\n width: 3,\n height: 3,\n depth: 3,\n rotation: 0.3,\n color: vec3.fromValues(0.8, 0.8, 0.8),\n type: 'convex',\n }),\n ...box({\n center: vec3.fromValues(-2, 3, -2),\n width: 3,\n height: 6,\n depth: 3,\n rotation: -0.4,\n color: vec3.fromValues(0.8, 0.8, 0.8),\n type: 'convex',\n }),\n light,\n ];\n readonly lightCenter = light.center;\n readonly lightWidth = vec3.len(light.right) * 2;\n readonly lightHeight = vec3.len(light.up) * 2;\n\n constructor(device: GPUDevice) {\n const quadStride = 16 * 4;\n const quadBuffer = device.createBuffer({\n size: quadStride * this.quads.length,\n usage: GPUBufferUsage.STORAGE,\n mappedAtCreation: true,\n });\n const quadData = new Float32Array(quadBuffer.getMappedRange());\n const vertexStride = 4 * 10;\n const vertexData = new Float32Array(this.quads.length * vertexStride);\n const indexData = new Uint32Array(this.quads.length * 9); // TODO: 6?\n let vertexCount = 0;\n let indexCount = 0;\n let quadDataOffset = 0;\n let vertexDataOffset = 0;\n let indexDataOffset = 0;\n for (let quadIdx = 0; quadIdx < this.quads.length; quadIdx++) {\n const quad = this.quads[quadIdx];\n const normal = vec3.normalize(vec3.cross(quad.right, quad.up));\n quadData[quadDataOffset++] = normal[0];\n quadData[quadDataOffset++] = normal[1];\n quadData[quadDataOffset++] = normal[2];\n quadData[quadDataOffset++] = -vec3.dot(normal, quad.center);\n\n const invRight = reciprocal(quad.right);\n quadData[quadDataOffset++] = invRight[0];\n quadData[quadDataOffset++] = invRight[1];\n quadData[quadDataOffset++] = invRight[2];\n quadData[quadDataOffset++] = -vec3.dot(invRight, quad.center);\n\n const invUp = reciprocal(quad.up);\n quadData[quadDataOffset++] = invUp[0];\n quadData[quadDataOffset++] = invUp[1];\n quadData[quadDataOffset++] = invUp[2];\n quadData[quadDataOffset++] = -vec3.dot(invUp, quad.center);\n\n quadData[quadDataOffset++] = quad.color[0];\n quadData[quadDataOffset++] = quad.color[1];\n quadData[quadDataOffset++] = quad.color[2];\n quadData[quadDataOffset++] = quad.emissive ?? 0;\n\n // a ----- b\n // | |\n // | m |\n // | |\n // c ----- d\n const a = vec3.add(vec3.sub(quad.center, quad.right), quad.up);\n const b = vec3.add(vec3.add(quad.center, quad.right), quad.up);\n const c = vec3.sub(vec3.sub(quad.center, quad.right), quad.up);\n const d = vec3.sub(vec3.add(quad.center, quad.right), quad.up);\n\n vertexData[vertexDataOffset++] = a[0];\n vertexData[vertexDataOffset++] = a[1];\n vertexData[vertexDataOffset++] = a[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 0; // uv.x\n vertexData[vertexDataOffset++] = 1; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n vertexData[vertexDataOffset++] = b[0];\n vertexData[vertexDataOffset++] = b[1];\n vertexData[vertexDataOffset++] = b[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 1; // uv.x\n vertexData[vertexDataOffset++] = 1; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n vertexData[vertexDataOffset++] = c[0];\n vertexData[vertexDataOffset++] = c[1];\n vertexData[vertexDataOffset++] = c[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 0; // uv.x\n vertexData[vertexDataOffset++] = 0; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n vertexData[vertexDataOffset++] = d[0];\n vertexData[vertexDataOffset++] = d[1];\n vertexData[vertexDataOffset++] = d[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 1; // uv.x\n vertexData[vertexDataOffset++] = 0; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n indexData[indexDataOffset++] = vertexCount + 0; // a\n indexData[indexDataOffset++] = vertexCount + 2; // c\n indexData[indexDataOffset++] = vertexCount + 1; // b\n indexData[indexDataOffset++] = vertexCount + 1; // b\n indexData[indexDataOffset++] = vertexCount + 2; // c\n indexData[indexDataOffset++] = vertexCount + 3; // d\n indexCount += 6;\n vertexCount += 4;\n }\n\n quadBuffer.unmap();\n\n const vertices = device.createBuffer({\n size: vertexData.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(vertices.getMappedRange()).set(vertexData);\n vertices.unmap();\n\n const indices = device.createBuffer({\n size: indexData.byteLength,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n new Uint16Array(indices.getMappedRange()).set(indexData);\n indices.unmap();\n\n const vertexBufferLayout: GPUVertexBufferLayout[] = [\n {\n arrayStride: vertexStride,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0 * 4,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: 4 * 4,\n format: 'float32x3',\n },\n {\n // color\n shaderLocation: 2,\n offset: 7 * 4,\n format: 'float32x3',\n },\n ],\n },\n ];\n\n this.vertexCount = vertexCount;\n this.indexCount = indexCount;\n this.vertices = vertices;\n this.indices = indices;\n this.vertexBufferLayout = vertexBufferLayout;\n this.quadBuffer = quadBuffer;\n }\n}\n"};class g{update(e){let n=l._E.perspective(2*Math.PI/8,e.aspect,.5,100),t=e.rotateCamera?this.frame/1e3:0,a=l._E.lookAt(l.R3.fromValues(15*Math.sin(t),5,15*Math.cos(t)),l.R3.fromValues(0,5,0),l.R3.fromValues(0,1,0)),r=l._E.multiply(n,a),i=l._E.invert(r),o=new Float32Array(this.uniformBuffer.size/4),s=new Uint32Array(o.buffer);for(let u=0;u<16;u++)o[u]=r[u];for(let c=0;c<16;c++)o[c+16]=i[c];s[32]=4294967295*Math.random(),s[33]=4294967295*Math.random(),s[34]=4294967295*Math.random(),this.device.queue.writeBuffer(this.uniformBuffer,0,o.buffer,o.byteOffset,o.byteLength),this.frame++}constructor(e,n){this.wgsl=d,this.frame=0,this.device=e,this.uniformBuffer=e.createBuffer({label:"Common.uniformBuffer",size:144,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let t=e.createBindGroupLayout({label:"Common.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}}]}),a=e.createBindGroup({label:"Common.bindGroup",layout:t,entries:[{binding:0,resource:{buffer:this.uniformBuffer,offset:0,size:this.uniformBuffer.size}},{binding:1,resource:{buffer:n,offset:0,size:n.size}}]});this.uniforms={bindGroupLayout:t,bindGroup:a}}}g.sourceInfo={name:"src/sample/cornell/common.ts".substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport commonWGSL from './common.wgsl';\n\n/**\n * Common holds the shared WGSL between the shaders, including the common uniform buffer.\n */\nexport default class Common {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n /** The WGSL of the common shader */\n readonly wgsl = commonWGSL;\n /** The common uniform buffer bind group and layout */\n readonly uniforms: {\n bindGroupLayout: GPUBindGroupLayout;\n bindGroup: GPUBindGroup;\n };\n\n private readonly device: GPUDevice;\n private readonly uniformBuffer: GPUBuffer;\n\n private frame = 0;\n\n constructor(device: GPUDevice, quads: GPUBuffer) {\n this.device = device;\n this.uniformBuffer = device.createBuffer({\n label: 'Common.uniformBuffer',\n size:\n 0 + //\n 4 * 16 + // mvp\n 4 * 16 + // inv_mvp\n 4 * 4, // seed\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Common.bindGroupLayout',\n entries: [\n {\n // common_uniforms\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE,\n buffer: { type: 'uniform' },\n },\n {\n // quads\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type: 'read-only-storage' },\n },\n ],\n });\n\n const bindGroup = device.createBindGroup({\n label: 'Common.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // common_uniforms\n binding: 0,\n resource: {\n buffer: this.uniformBuffer,\n offset: 0,\n size: this.uniformBuffer.size,\n },\n },\n {\n // quads\n binding: 1,\n resource: {\n buffer: quads,\n offset: 0,\n size: quads.size,\n },\n },\n ],\n });\n\n this.uniforms = { bindGroupLayout, bindGroup };\n }\n\n /** Updates the uniform buffer data */\n update(params: { rotateCamera: boolean; aspect: number }) {\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 8,\n params.aspect,\n 0.5,\n 100\n );\n\n const viewRotation = params.rotateCamera ? this.frame / 1000 : 0;\n\n const viewMatrix = mat4.lookAt(\n vec3.fromValues(\n Math.sin(viewRotation) * 15,\n 5,\n Math.cos(viewRotation) * 15\n ),\n vec3.fromValues(0, 5, 0),\n vec3.fromValues(0, 1, 0)\n );\n const mvp = mat4.multiply(projectionMatrix, viewMatrix);\n const invMVP = mat4.invert(mvp);\n\n const uniformDataF32 = new Float32Array(this.uniformBuffer.size / 4);\n const uniformDataU32 = new Uint32Array(uniformDataF32.buffer);\n for (let i = 0; i < 16; i++) {\n uniformDataF32[i] = mvp[i];\n }\n for (let i = 0; i < 16; i++) {\n uniformDataF32[i + 16] = invMVP[i];\n }\n uniformDataU32[32] = 0xffffffff * Math.random();\n uniformDataU32[33] = 0xffffffff * Math.random();\n uniformDataU32[34] = 0xffffffff * Math.random();\n\n this.device.queue.writeBuffer(\n this.uniformBuffer,\n 0,\n uniformDataF32.buffer,\n uniformDataF32.byteOffset,\n uniformDataF32.byteLength\n );\n\n this.frame++;\n }\n}\n"};class v{run(e){this.accumulationMean+=this.kPhotonsPerFrame*this.kPhotonEnergy/this.kTotalLightmapTexels;let n=1/this.accumulationMean,t=this.accumulationMean>2*this.kAccumulationMeanMax?.5:1;this.accumulationMean*=t;let a=new Float32Array(this.uniformBuffer.size/4);a[0]=n,a[1]=t,a[2]=this.scene.lightWidth,a[3]=this.scene.lightHeight,a[4]=this.scene.lightCenter[0],a[5]=this.scene.lightCenter[1],a[6]=this.scene.lightCenter[2],this.device.queue.writeBuffer(this.uniformBuffer,0,a.buffer,a.byteOffset,a.byteLength);let r=e.beginComputePass();r.setBindGroup(0,this.common.uniforms.bindGroup),r.setBindGroup(1,this.bindGroup),r.setPipeline(this.radiosityPipeline),r.dispatchWorkgroups(this.kWorkgroupsPerFrame),r.setPipeline(this.accumulationToLightmapPipeline),r.dispatchWorkgroups(Math.ceil(v.lightmapWidth/this.kAccumulationToLightmapWorkgroupSizeX),Math.ceil(v.lightmapHeight/this.kAccumulationToLightmapWorkgroupSizeY),this.lightmap.depthOrArrayLayers),r.end()}constructor(e,n,t){this.kPhotonsPerWorkgroup=256,this.kWorkgroupsPerFrame=1024,this.kPhotonsPerFrame=this.kPhotonsPerWorkgroup*this.kWorkgroupsPerFrame,this.kPhotonEnergy=1e5,this.kAccumulationToLightmapWorkgroupSizeX=16,this.kAccumulationToLightmapWorkgroupSizeY=16,this.accumulationMean=0,this.kAccumulationMeanMax=268435456,this.device=e,this.common=n,this.scene=t,this.lightmap=e.createTexture({label:"Radiosity.lightmap",size:{width:v.lightmapWidth,height:v.lightmapHeight,depthOrArrayLayers:t.quads.length},format:v.lightmapFormat,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.STORAGE_BINDING}),this.accumulationBuffer=e.createBuffer({label:"Radiosity.accumulationBuffer",size:v.lightmapWidth*v.lightmapHeight*t.quads.length*16,usage:GPUBufferUsage.STORAGE}),this.kTotalLightmapTexels=v.lightmapWidth*v.lightmapHeight*t.quads.length,this.uniformBuffer=e.createBuffer({label:"Radiosity.uniformBuffer",size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let a=e.createBindGroupLayout({label:"Radiosity.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:v.lightmapFormat,viewDimension:"2d-array"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}}]});this.bindGroup=e.createBindGroup({label:"Radiosity.bindGroup",layout:a,entries:[{binding:0,resource:{buffer:this.accumulationBuffer,size:this.accumulationBuffer.size}},{binding:1,resource:this.lightmap.createView()},{binding:2,resource:{buffer:this.uniformBuffer,size:this.uniformBuffer.size}}]});let r=e.createShaderModule({code:o+n.wgsl}),i=e.createPipelineLayout({label:"Radiosity.accumulatePipelineLayout",bindGroupLayouts:[n.uniforms.bindGroupLayout,a]});this.radiosityPipeline=e.createComputePipeline({label:"Radiosity.radiosityPipeline",layout:i,compute:{module:r,entryPoint:"radiosity",constants:{PhotonsPerWorkgroup:this.kPhotonsPerWorkgroup,PhotonEnergy:this.kPhotonEnergy}}}),this.accumulationToLightmapPipeline=e.createComputePipeline({label:"Radiosity.accumulationToLightmapPipeline",layout:i,compute:{module:r,entryPoint:"accumulation_to_lightmap",constants:{AccumulationToLightmapWorkgroupSizeX:this.kAccumulationToLightmapWorkgroupSizeX,AccumulationToLightmapWorkgroupSizeY:this.kAccumulationToLightmapWorkgroupSizeY}}})}}v.sourceInfo={name:"src/sample/cornell/radiosity.ts".substring(19),contents:"import Common from './common';\nimport radiosityWGSL from './radiosity.wgsl';\nimport Scene from './scene';\n\n/**\n * Radiosity computes lightmaps, calculated by software raytracing of light in\n * the scene.\n */\nexport default class Radiosity {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n // The output lightmap format and dimensions\n static readonly lightmapFormat = 'rgba16float';\n static readonly lightmapWidth = 256;\n static readonly lightmapHeight = 256;\n\n // The output lightmap.\n readonly lightmap: GPUTexture;\n\n // Number of photons emitted per workgroup.\n // This is equal to the workgroup size (one photon per invocation)\n private readonly kPhotonsPerWorkgroup = 256;\n // Number of radiosity workgroups dispatched per frame.\n private readonly kWorkgroupsPerFrame = 1024;\n private readonly kPhotonsPerFrame =\n this.kPhotonsPerWorkgroup * this.kWorkgroupsPerFrame;\n // Maximum value that can be added to the 'accumulation' buffer, per photon,\n // across all texels.\n private readonly kPhotonEnergy = 100000;\n // The total number of lightmap texels for all quads.\n private readonly kTotalLightmapTexels;\n\n private readonly kAccumulationToLightmapWorkgroupSizeX = 16;\n private readonly kAccumulationToLightmapWorkgroupSizeY = 16;\n\n private readonly device: GPUDevice;\n private readonly common: Common;\n private readonly scene: Scene;\n private readonly radiosityPipeline: GPUComputePipeline;\n private readonly accumulationToLightmapPipeline: GPUComputePipeline;\n private readonly bindGroup: GPUBindGroup;\n private readonly accumulationBuffer: GPUBuffer;\n private readonly uniformBuffer: GPUBuffer;\n\n // The 'accumulation' buffer average value\n private accumulationMean = 0;\n\n // The maximum value of 'accumulationAverage' before all values in\n // 'accumulation' are reduced to avoid integer overflows.\n private readonly kAccumulationMeanMax = 0x10000000;\n\n constructor(device: GPUDevice, common: Common, scene: Scene) {\n this.device = device;\n this.common = common;\n this.scene = scene;\n this.lightmap = device.createTexture({\n label: 'Radiosity.lightmap',\n size: {\n width: Radiosity.lightmapWidth,\n height: Radiosity.lightmapHeight,\n depthOrArrayLayers: scene.quads.length,\n },\n format: Radiosity.lightmapFormat,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,\n });\n this.accumulationBuffer = device.createBuffer({\n label: 'Radiosity.accumulationBuffer',\n size:\n Radiosity.lightmapWidth *\n Radiosity.lightmapHeight *\n scene.quads.length *\n 16,\n usage: GPUBufferUsage.STORAGE,\n });\n this.kTotalLightmapTexels =\n Radiosity.lightmapWidth * Radiosity.lightmapHeight * scene.quads.length;\n this.uniformBuffer = device.createBuffer({\n label: 'Radiosity.uniformBuffer',\n size: 8 * 4, // 8 x f32\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Radiosity.bindGroupLayout',\n entries: [\n {\n // accumulation buffer\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type: 'storage' },\n },\n {\n // lightmap\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n storageTexture: {\n access: 'write-only',\n format: Radiosity.lightmapFormat,\n viewDimension: '2d-array',\n },\n },\n {\n // radiosity_uniforms\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type: 'uniform' },\n },\n ],\n });\n this.bindGroup = device.createBindGroup({\n label: 'Radiosity.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // accumulation buffer\n binding: 0,\n resource: {\n buffer: this.accumulationBuffer,\n size: this.accumulationBuffer.size,\n },\n },\n {\n // lightmap\n binding: 1,\n resource: this.lightmap.createView(),\n },\n {\n // radiosity_uniforms\n binding: 2,\n resource: {\n buffer: this.uniformBuffer,\n size: this.uniformBuffer.size,\n },\n },\n ],\n });\n\n const mod = device.createShaderModule({\n code: radiosityWGSL + common.wgsl,\n });\n const pipelineLayout = device.createPipelineLayout({\n label: 'Radiosity.accumulatePipelineLayout',\n bindGroupLayouts: [common.uniforms.bindGroupLayout, bindGroupLayout],\n });\n\n this.radiosityPipeline = device.createComputePipeline({\n label: 'Radiosity.radiosityPipeline',\n layout: pipelineLayout,\n compute: {\n module: mod,\n entryPoint: 'radiosity',\n constants: {\n PhotonsPerWorkgroup: this.kPhotonsPerWorkgroup,\n PhotonEnergy: this.kPhotonEnergy,\n },\n },\n });\n\n this.accumulationToLightmapPipeline = device.createComputePipeline({\n label: 'Radiosity.accumulationToLightmapPipeline',\n layout: pipelineLayout,\n compute: {\n module: mod,\n entryPoint: 'accumulation_to_lightmap',\n constants: {\n AccumulationToLightmapWorkgroupSizeX:\n this.kAccumulationToLightmapWorkgroupSizeX,\n AccumulationToLightmapWorkgroupSizeY:\n this.kAccumulationToLightmapWorkgroupSizeY,\n },\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n // Calculate the new mean value for the accumulation buffer\n this.accumulationMean +=\n (this.kPhotonsPerFrame * this.kPhotonEnergy) / this.kTotalLightmapTexels;\n\n // Calculate the 'accumulation' -> 'lightmap' scale factor from 'accumulationMean'\n const accumulationToLightmapScale = 1 / this.accumulationMean;\n // If 'accumulationMean' is greater than 'kAccumulationMeanMax', then reduce\n // the 'accumulation' buffer values to prevent u32 overflow.\n const accumulationBufferScale =\n this.accumulationMean > 2 * this.kAccumulationMeanMax ? 0.5 : 1;\n this.accumulationMean *= accumulationBufferScale;\n\n // Update the radiosity uniform buffer data.\n const uniformDataF32 = new Float32Array(this.uniformBuffer.size / 4);\n uniformDataF32[0] = accumulationToLightmapScale;\n uniformDataF32[1] = accumulationBufferScale;\n uniformDataF32[2] = this.scene.lightWidth;\n uniformDataF32[3] = this.scene.lightHeight;\n uniformDataF32[4] = this.scene.lightCenter[0];\n uniformDataF32[5] = this.scene.lightCenter[1];\n uniformDataF32[6] = this.scene.lightCenter[2];\n this.device.queue.writeBuffer(\n this.uniformBuffer,\n 0,\n uniformDataF32.buffer,\n uniformDataF32.byteOffset,\n uniformDataF32.byteLength\n );\n\n // Dispatch the radiosity workgroups\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setBindGroup(0, this.common.uniforms.bindGroup);\n passEncoder.setBindGroup(1, this.bindGroup);\n passEncoder.setPipeline(this.radiosityPipeline);\n passEncoder.dispatchWorkgroups(this.kWorkgroupsPerFrame);\n\n // Then copy the 'accumulation' data to 'lightmap'\n passEncoder.setPipeline(this.accumulationToLightmapPipeline);\n passEncoder.dispatchWorkgroups(\n Math.ceil(\n Radiosity.lightmapWidth / this.kAccumulationToLightmapWorkgroupSizeX\n ),\n Math.ceil(\n Radiosity.lightmapHeight / this.kAccumulationToLightmapWorkgroupSizeY\n ),\n this.lightmap.depthOrArrayLayers\n );\n passEncoder.end();\n }\n}\n"},v.lightmapFormat="rgba16float",v.lightmapWidth=256,v.lightmapHeight=256;class b{run(e){let n=e.beginRenderPass(this.renderPassDescriptor);n.setPipeline(this.pipeline),n.setVertexBuffer(0,this.scene.vertices),n.setIndexBuffer(this.scene.indices,"uint16"),n.setBindGroup(0,this.common.uniforms.bindGroup),n.setBindGroup(1,this.bindGroup),n.drawIndexed(this.scene.indexCount),n.end()}constructor(e,n,t,a,r){this.common=n,this.scene=t;let i=e.createTexture({label:"RasterizerRenderer.depthTexture",size:[r.width,r.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT});this.renderPassDescriptor={label:"RasterizerRenderer.renderPassDescriptor",colorAttachments:[{view:r.createView(),clearValue:[.1,.2,.3,1],loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:i.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}};let o=e.createBindGroupLayout({label:"RasterizerRenderer.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,texture:{viewDimension:"2d-array"}},{binding:1,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,sampler:{}}]});this.bindGroup=e.createBindGroup({label:"RasterizerRenderer.bindGroup",layout:o,entries:[{binding:0,resource:a.lightmap.createView()},{binding:1,resource:e.createSampler({addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",magFilter:"linear",minFilter:"linear"})}]});let u=e.createShaderModule({label:"RasterizerRenderer.module",code:s+n.wgsl});this.pipeline=e.createRenderPipeline({label:"RasterizerRenderer.pipeline",layout:e.createPipelineLayout({bindGroupLayouts:[n.uniforms.bindGroupLayout,o]}),vertex:{module:u,entryPoint:"vs_main",buffers:t.vertexBufferLayout},fragment:{module:u,entryPoint:"fs_main",targets:[{format:r.format}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}})}}b.sourceInfo={name:"src/sample/cornell/rasterizer.ts".substring(19),contents:"import rasterizerWGSL from './rasterizer.wgsl';\n\nimport Common from './common';\nimport Radiosity from './radiosity';\nimport Scene from './scene';\n\n/**\n * Rasterizer renders the scene using a regular raserization graphics pipeline.\n */\nexport default class Rasterizer {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n private readonly common: Common;\n private readonly scene: Scene;\n private readonly renderPassDescriptor: GPURenderPassDescriptor;\n private readonly pipeline: GPURenderPipeline;\n private readonly bindGroup: GPUBindGroup;\n\n constructor(\n device: GPUDevice,\n common: Common,\n scene: Scene,\n radiosity: Radiosity,\n framebuffer: GPUTexture\n ) {\n this.common = common;\n this.scene = scene;\n\n const depthTexture = device.createTexture({\n label: 'RasterizerRenderer.depthTexture',\n size: [framebuffer.width, framebuffer.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n this.renderPassDescriptor = {\n label: 'RasterizerRenderer.renderPassDescriptor',\n colorAttachments: [\n {\n view: framebuffer.createView(),\n clearValue: [0.1, 0.2, 0.3, 1],\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'RasterizerRenderer.bindGroupLayout',\n entries: [\n {\n // lightmap\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n texture: { viewDimension: '2d-array' },\n },\n {\n // sampler\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n sampler: {},\n },\n ],\n });\n\n this.bindGroup = device.createBindGroup({\n label: 'RasterizerRenderer.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // lightmap\n binding: 0,\n resource: radiosity.lightmap.createView(),\n },\n {\n // sampler\n binding: 1,\n resource: device.createSampler({\n addressModeU: 'clamp-to-edge',\n addressModeV: 'clamp-to-edge',\n magFilter: 'linear',\n minFilter: 'linear',\n }),\n },\n ],\n });\n\n const mod = device.createShaderModule({\n label: 'RasterizerRenderer.module',\n code: rasterizerWGSL + common.wgsl,\n });\n\n this.pipeline = device.createRenderPipeline({\n label: 'RasterizerRenderer.pipeline',\n layout: device.createPipelineLayout({\n bindGroupLayouts: [common.uniforms.bindGroupLayout, bindGroupLayout],\n }),\n vertex: {\n module: mod,\n entryPoint: 'vs_main',\n buffers: scene.vertexBufferLayout,\n },\n fragment: {\n module: mod,\n entryPoint: 'fs_main',\n targets: [{ format: framebuffer.format }],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n const passEncoder = commandEncoder.beginRenderPass(\n this.renderPassDescriptor\n );\n passEncoder.setPipeline(this.pipeline);\n passEncoder.setVertexBuffer(0, this.scene.vertices);\n passEncoder.setIndexBuffer(this.scene.indices, 'uint16');\n passEncoder.setBindGroup(0, this.common.uniforms.bindGroup);\n passEncoder.setBindGroup(1, this.bindGroup);\n passEncoder.drawIndexed(this.scene.indexCount);\n passEncoder.end();\n }\n}\n"};class y{run(e){let n=e.beginComputePass();n.setBindGroup(0,this.bindGroup),n.setPipeline(this.pipeline),n.dispatchWorkgroups(Math.ceil(this.width/this.kWorkgroupSizeX),Math.ceil(this.height/this.kWorkgroupSizeY)),n.end()}constructor(e,n,t,a){this.kWorkgroupSizeX=16,this.kWorkgroupSizeY=16,this.width=t.width,this.height=t.height;let r=e.createBindGroupLayout({label:"Tonemapper.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,texture:{viewDimension:"2d"}},{binding:1,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:a.format,viewDimension:"2d"}}]});this.bindGroup=e.createBindGroup({label:"Tonemapper.bindGroup",layout:r,entries:[{binding:0,resource:t.createView()},{binding:1,resource:a.createView()}]});let i=e.createShaderModule({code:c.replace("{OUTPUT_FORMAT}",a.format)+n.wgsl}),o=e.createPipelineLayout({label:"Tonemap.pipelineLayout",bindGroupLayouts:[r]});this.pipeline=e.createComputePipeline({label:"Tonemap.pipeline",layout:o,compute:{module:i,entryPoint:"main",constants:{WorkgroupSizeX:this.kWorkgroupSizeX,WorkgroupSizeY:this.kWorkgroupSizeY}}})}}y.sourceInfo={name:"src/sample/cornell/tonemapper.ts".substring(19),contents:"import Common from './common';\nimport tonemapperWGSL from './tonemapper.wgsl';\n\n/**\n * Tonemapper implements a tonemapper to convert a linear-light framebuffer to\n * a gamma-correct, tonemapped framebuffer used for presentation.\n */\nexport default class Tonemapper {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n private readonly bindGroup: GPUBindGroup;\n private readonly pipeline: GPUComputePipeline;\n private readonly width: number;\n private readonly height: number;\n private readonly kWorkgroupSizeX = 16;\n private readonly kWorkgroupSizeY = 16;\n\n constructor(\n device: GPUDevice,\n common: Common,\n input: GPUTexture,\n output: GPUTexture\n ) {\n this.width = input.width;\n this.height = input.height;\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Tonemapper.bindGroupLayout',\n entries: [\n {\n // input\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n texture: {\n viewDimension: '2d',\n },\n },\n {\n // output\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n storageTexture: {\n access: 'write-only',\n format: output.format,\n viewDimension: '2d',\n },\n },\n ],\n });\n this.bindGroup = device.createBindGroup({\n label: 'Tonemapper.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // input\n binding: 0,\n resource: input.createView(),\n },\n {\n // output\n binding: 1,\n resource: output.createView(),\n },\n ],\n });\n\n const mod = device.createShaderModule({\n code:\n tonemapperWGSL.replace('{OUTPUT_FORMAT}', output.format) + common.wgsl,\n });\n const pipelineLayout = device.createPipelineLayout({\n label: 'Tonemap.pipelineLayout',\n bindGroupLayouts: [bindGroupLayout],\n });\n\n this.pipeline = device.createComputePipeline({\n label: 'Tonemap.pipeline',\n layout: pipelineLayout,\n compute: {\n module: mod,\n entryPoint: 'main',\n constants: {\n WorkgroupSizeX: this.kWorkgroupSizeX,\n WorkgroupSizeY: this.kWorkgroupSizeY,\n },\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setBindGroup(0, this.bindGroup);\n passEncoder.setPipeline(this.pipeline);\n passEncoder.dispatchWorkgroups(\n Math.ceil(this.width / this.kWorkgroupSizeX),\n Math.ceil(this.height / this.kWorkgroupSizeY)\n );\n passEncoder.end();\n }\n}\n"};class x{run(e){let n=e.beginComputePass();n.setPipeline(this.pipeline),n.setBindGroup(0,this.common.uniforms.bindGroup),n.setBindGroup(1,this.bindGroup),n.dispatchWorkgroups(Math.ceil(this.framebuffer.width/this.kWorkgroupSizeX),Math.ceil(this.framebuffer.height/this.kWorkgroupSizeY)),n.end()}constructor(e,n,t,a){this.kWorkgroupSizeX=16,this.kWorkgroupSizeY=16,this.common=n,this.framebuffer=a;let r=e.createBindGroupLayout({label:"Raytracer.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,texture:{viewDimension:"2d-array"}},{binding:1,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,sampler:{}},{binding:2,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:a.format,viewDimension:"2d"}}]});this.bindGroup=e.createBindGroup({label:"rendererBindGroup",layout:r,entries:[{binding:0,resource:t.lightmap.createView()},{binding:1,resource:e.createSampler({addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",addressModeW:"clamp-to-edge",magFilter:"linear",minFilter:"linear"})},{binding:2,resource:a.createView()}]}),this.pipeline=e.createComputePipeline({label:"raytracerPipeline",layout:e.createPipelineLayout({bindGroupLayouts:[n.uniforms.bindGroupLayout,r]}),compute:{module:e.createShaderModule({code:u+n.wgsl}),entryPoint:"main",constants:{WorkgroupSizeX:this.kWorkgroupSizeX,WorkgroupSizeY:this.kWorkgroupSizeY}}})}}x.sourceInfo={name:"src/sample/cornell/raytracer.ts".substring(19),contents:"import raytracerWGSL from './raytracer.wgsl';\n\nimport Common from './common';\nimport Radiosity from './radiosity';\n\n/**\n * Raytracer renders the scene using a software ray-tracing compute pipeline.\n */\nexport default class Raytracer {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n private readonly common: Common;\n private readonly framebuffer: GPUTexture;\n private readonly pipeline: GPUComputePipeline;\n private readonly bindGroup: GPUBindGroup;\n\n private readonly kWorkgroupSizeX = 16;\n private readonly kWorkgroupSizeY = 16;\n\n constructor(\n device: GPUDevice,\n common: Common,\n radiosity: Radiosity,\n framebuffer: GPUTexture\n ) {\n this.common = common;\n this.framebuffer = framebuffer;\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Raytracer.bindGroupLayout',\n entries: [\n {\n // lightmap\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n texture: { viewDimension: '2d-array' },\n },\n {\n // sampler\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n sampler: {},\n },\n {\n // framebuffer\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n storageTexture: {\n access: 'write-only',\n format: framebuffer.format,\n viewDimension: '2d',\n },\n },\n ],\n });\n\n this.bindGroup = device.createBindGroup({\n label: 'rendererBindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: radiosity.lightmap.createView(),\n },\n {\n binding: 1,\n resource: device.createSampler({\n addressModeU: 'clamp-to-edge',\n addressModeV: 'clamp-to-edge',\n addressModeW: 'clamp-to-edge',\n magFilter: 'linear',\n minFilter: 'linear',\n }),\n },\n {\n binding: 2,\n resource: framebuffer.createView(),\n },\n ],\n });\n\n this.pipeline = device.createComputePipeline({\n label: 'raytracerPipeline',\n layout: device.createPipelineLayout({\n bindGroupLayouts: [common.uniforms.bindGroupLayout, bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: raytracerWGSL + common.wgsl,\n }),\n entryPoint: 'main',\n constants: {\n WorkgroupSizeX: this.kWorkgroupSizeX,\n WorkgroupSizeY: this.kWorkgroupSizeY,\n },\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(this.pipeline);\n passEncoder.setBindGroup(0, this.common.uniforms.bindGroup);\n passEncoder.setBindGroup(1, this.bindGroup);\n passEncoder.dispatchWorkgroups(\n Math.ceil(this.framebuffer.width / this.kWorkgroupSizeX),\n Math.ceil(this.framebuffer.height / this.kWorkgroupSizeY)\n );\n passEncoder.end();\n }\n}\n"};var P="src/sample/cornell/main.ts";let G=async e=>{let{canvas:n,pageState:t,gui:a}=e,r=navigator.gpu.getPreferredCanvasFormat(),i="bgra8unorm"===r?["bgra8unorm-storage"]:[],o=await navigator.gpu.requestAdapter();for(let s of i)if(!o.features.has(s))throw Error("sample requires ".concat(s,", but is not supported by the adapter"));let u=await o.requestDevice({requiredFeatures:i});if(!t.active)return;let c={renderer:"rasterizer",rotateCamera:!0};a.add(c,"renderer",["rasterizer","raytracer"]),a.add(c,"rotateCamera",!0);let d=window.devicePixelRatio||1;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let l=n.getContext("webgpu");l.configure({device:u,format:r,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.STORAGE_BINDING,alphaMode:"premultiplied"});let m=u.createTexture({label:"framebuffer",size:[n.width,n.height],format:"rgba16float",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.TEXTURE_BINDING}),f=new h(u),p=new g(u,f.quadBuffer),P=new v(u,p,f),G=new b(u,p,f,P,m),_=new x(u,p,P,m);requestAnimationFrame(function e(){if(!t.active)return;let a=l.getCurrentTexture(),r=u.createCommandEncoder();switch(p.update({rotateCamera:c.rotateCamera,aspect:n.width/n.height}),P.run(r),c.renderer){case"rasterizer":G.run(r);break;case"raytracer":_.run(r)}let i=new y(u,p,m,a);i.run(r),u.queue.submit([r.finish()]),requestAnimationFrame(e)})},_=()=>(0,i.Tl)({name:"Cornell box",description:"A classic Cornell box, using a lightmap generated using software ray-tracing.",gui:!0,init:G,sources:[{name:P.substring(19),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport radiosityWGSL from './radiosity.wgsl';\nimport rasterizerWGSL from './rasterizer.wgsl';\nimport raytracerWGSL from './raytracer.wgsl';\nimport tonemapperWGSL from './tonemapper.wgsl';\nimport commonWGSL from './common.wgsl';\nimport Scene from './scene';\nimport Common from './common';\nimport Radiosity from './radiosity';\nimport Rasterizer from './rasterizer';\nimport Tonemapper from './tonemapper';\nimport Raytracer from './raytracer';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n const requiredFeatures: GPUFeatureName[] =\n presentationFormat === 'bgra8unorm' ? ['bgra8unorm-storage'] : [];\n const adapter = await navigator.gpu.requestAdapter();\n for (const feature of requiredFeatures) {\n if (!adapter.features.has(feature)) {\n throw new Error(\n `sample requires ${feature}, but is not supported by the adapter`\n );\n }\n }\n const device = await adapter.requestDevice({ requiredFeatures });\n\n if (!pageState.active) return;\n\n const params: {\n renderer: 'rasterizer' | 'raytracer';\n rotateCamera: boolean;\n } = {\n renderer: 'rasterizer',\n rotateCamera: true,\n };\n\n gui.add(params, 'renderer', ['rasterizer', 'raytracer']);\n gui.add(params, 'rotateCamera', true);\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n context.configure({\n device,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.STORAGE_BINDING,\n alphaMode: 'premultiplied',\n });\n\n const framebuffer = device.createTexture({\n label: 'framebuffer',\n size: [canvas.width, canvas.height],\n format: 'rgba16float',\n usage:\n GPUTextureUsage.RENDER_ATTACHMENT |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.TEXTURE_BINDING,\n });\n\n const scene = new Scene(device);\n const common = new Common(device, scene.quadBuffer);\n const radiosity = new Radiosity(device, common, scene);\n const rasterizer = new Rasterizer(\n device,\n common,\n scene,\n radiosity,\n framebuffer\n );\n const raytracer = new Raytracer(device, common, radiosity, framebuffer);\n\n function frame() {\n if (!pageState.active) {\n // Sample is no longer the active page.\n return;\n }\n\n const canvasTexture = context.getCurrentTexture();\n const commandEncoder = device.createCommandEncoder();\n\n common.update({\n rotateCamera: params.rotateCamera,\n aspect: canvas.width / canvas.height,\n });\n radiosity.run(commandEncoder);\n\n switch (params.renderer) {\n case 'rasterizer': {\n rasterizer.run(commandEncoder);\n break;\n }\n case 'raytracer': {\n raytracer.run(commandEncoder);\n break;\n }\n }\n\n const tonemapper = new Tonemapper(\n device,\n common,\n framebuffer,\n canvasTexture\n );\n tonemapper.run(commandEncoder);\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst CornellBox: () => JSX.Element = () =>\n makeSample({\n name: 'Cornell box',\n description:\n 'A classic Cornell box, using a lightmap generated using software ray-tracing.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n Common.sourceInfo,\n Scene.sourceInfo,\n Radiosity.sourceInfo,\n Rasterizer.sourceInfo,\n Raytracer.sourceInfo,\n Tonemapper.sourceInfo,\n {\n name: './radiosity.wgsl',\n contents: radiosityWGSL,\n editable: true,\n },\n {\n name: './rasterizer.wgsl',\n contents: rasterizerWGSL,\n editable: true,\n },\n {\n name: './raytracer.wgsl',\n contents: raytracerWGSL,\n editable: true,\n },\n {\n name: './tonemapper.wgsl',\n contents: tonemapperWGSL,\n editable: true,\n },\n {\n name: './common.wgsl',\n contents: commonWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default CornellBox;\n"},g.sourceInfo,h.sourceInfo,v.sourceInfo,b.sourceInfo,x.sourceInfo,y.sourceInfo,{name:"./radiosity.wgsl",contents:o,editable:!0},{name:"./rasterizer.wgsl",contents:s,editable:!0},{name:"./raytracer.wgsl",contents:u,editable:!0},{name:"./tonemapper.wgsl",contents:c,editable:!0},{name:"./common.wgsl",contents:d,editable:!0}],filename:P});var S=_},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[874],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return m}});var a=t(5893),r=t(9008),i=t.n(r),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,s.useRef)(null),r=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376);return new n.GUI({autoPlace:!1})}},[]),l=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),p=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,g]=(0,s.useState)(null),[v,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(p?b(p[1]):b(r[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();m&&l.current&&(m.dom.style.position="absolute",m.showPanel(1),l.current.appendChild(m.dom));let t={active:!0},a=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let o=e.init({canvas:i,pageState:t,gui:d,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),h?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(h)})]}):null]}),(0,a.jsxs)("div",{className:c().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:l}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:c().sourceFileNav,children:(0,a.jsx)("ul",{children:r.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){b(e.name)},children:e.name})},n))})}),r.map((e,n)=>(0,a.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":v==e.name},n))]})]})},l=e=>(0,a.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},6874:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return S}});var a,r,i=t(5671),o="// A storage buffer holding an array of atomic.\n// The array elements are a sequence of red, green, blue components, for each\n// lightmap texel, for each quad surface.\n@group(1) @binding(0)\nvar accumulation : array>;\n\n// The output lightmap texture.\n@group(1) @binding(1)\nvar lightmap : texture_storage_2d_array;\n\n// Uniform data used by the accumulation_to_lightmap entry point\nstruct Uniforms {\n // Scalar for converting accumulation values to output lightmap values\n accumulation_to_lightmap_scale : f32,\n // Accumulation buffer rescaling value\n accumulation_buffer_scale : f32,\n // The width of the light\n light_width : f32,\n // The height of the light\n light_height : f32,\n // The center of the light\n light_center : vec3f,\n}\n\n// accumulation_to_lightmap uniforms binding point\n@group(1) @binding(2) var uniforms : Uniforms;\n\n// Number of photons emitted per workgroup\noverride PhotonsPerWorkgroup : u32;\n\n// Maximum value that can be added to the accumulation buffer from a single photon\noverride PhotonEnergy : f32;\n\n// Number of bounces of each photon\nconst PhotonBounces = 4;\n\n// Amount of light absorbed with each photon bounce (0: 0%, 1: 100%)\nconst LightAbsorbtion = 0.5;\n\n// Radiosity compute shader.\n// Each invocation creates a photon from the light source, and accumulates\n// bounce lighting into the 'accumulation' buffer.\n@compute @workgroup_size(PhotonsPerWorkgroup)\nfn radiosity(@builtin(global_invocation_id) invocation_id : vec3u) {\n init_rand(invocation_id);\n photon();\n}\n\n// Spawns a photon at the light source, performs ray tracing in the scene,\n// accumulating light values into 'accumulation' for each quad surface hit.\nfn photon() {\n // Create a random ray from the light.\n var ray = new_light_ray();\n // Give the photon an initial energy value.\n var color = PhotonEnergy * vec3f(1, 0.8, 0.6);\n\n // Start bouncing.\n for (var i = 0; i < (PhotonBounces+1); i++) {\n // Find the closest hit of the ray with the scene's quads.\n let hit = raytrace(ray);\n let quad = quads[hit.quad];\n\n // Bounce the ray.\n ray.start = hit.pos + quad.plane.xyz * 1e-5;\n ray.dir = normalize(reflect(ray.dir, quad.plane.xyz) + rand_unit_sphere() * 0.75);\n\n // Photon color is multiplied by the quad's color.\n color *= quad.color;\n\n // Accumulate the aborbed light into the 'accumulation' buffer.\n accumulate(hit.uv, hit.quad, color * LightAbsorbtion);\n\n // What wasn't absorbed is reflected.\n color *= 1 - LightAbsorbtion;\n }\n}\n\n// Performs an atomicAdd() with 'color' into the 'accumulation' buffer at 'uv'\n// and 'quad'.\nfn accumulate(uv : vec2f, quad : u32, color : vec3f) {\n let dims = textureDimensions(lightmap);\n let base_idx = accumulation_base_index(vec2u(uv * vec2f(dims)), quad);\n atomicAdd(&accumulation[base_idx + 0], u32(color.r + 0.5));\n atomicAdd(&accumulation[base_idx + 1], u32(color.g + 0.5));\n atomicAdd(&accumulation[base_idx + 2], u32(color.b + 0.5));\n}\n\n// Returns the base element index for the texel at 'coord' for 'quad'\nfn accumulation_base_index(coord : vec2u, quad : u32) -> u32 {\n let dims = textureDimensions(lightmap);\n let c = min(vec2u(dims) - 1, coord);\n return 3 * (c.x + dims.x * c.y + dims.x * dims.y * quad);\n}\n\n// Returns a new Ray at a random point on the light, in a random downwards\n// direction.\nfn new_light_ray() -> Ray {\n let center = uniforms.light_center;\n let pos = center + vec3f(uniforms.light_width * (rand() - 0.5),\n 0,\n uniforms.light_height * (rand() - 0.5));\n var dir = rand_cosine_weighted_hemisphere().xzy;\n dir.y = -dir.y;\n return Ray(pos, dir);\n}\n\noverride AccumulationToLightmapWorkgroupSizeX : u32;\noverride AccumulationToLightmapWorkgroupSizeY : u32;\n\n// Compute shader used to copy the atomic data in 'accumulation' to\n// 'lightmap'. 'accumulation' might also be scaled to reduce integer overflow.\n@compute @workgroup_size(AccumulationToLightmapWorkgroupSizeX, AccumulationToLightmapWorkgroupSizeY)\nfn accumulation_to_lightmap(@builtin(global_invocation_id) invocation_id : vec3u,\n @builtin(workgroup_id) workgroup_id : vec3u) {\n let dims = textureDimensions(lightmap);\n let quad = workgroup_id.z; // The workgroup 'z' value holds the quad index.\n let coord = invocation_id.xy;\n if (all(coord < dims)) {\n // Load the color value out of 'accumulation'\n let base_idx = accumulation_base_index(coord, quad);\n let color = vec3(f32(atomicLoad(&accumulation[base_idx + 0])),\n f32(atomicLoad(&accumulation[base_idx + 1])),\n f32(atomicLoad(&accumulation[base_idx + 2])));\n\n // Multiply the color by 'uniforms.accumulation_to_lightmap_scale' and write it to\n // the lightmap.\n textureStore(lightmap, coord, quad, vec4(color * uniforms.accumulation_to_lightmap_scale, 1));\n\n // If the 'accumulation' buffer is nearing saturation, then\n // 'uniforms.accumulation_buffer_scale' will be less than 1, scaling the values\n // to something less likely to overflow the u32.\n if (uniforms.accumulation_buffer_scale != 1.0) {\n let scaled = color * uniforms.accumulation_buffer_scale + 0.5;\n atomicStore(&accumulation[base_idx + 0], u32(scaled.r));\n atomicStore(&accumulation[base_idx + 1], u32(scaled.g));\n atomicStore(&accumulation[base_idx + 2], u32(scaled.b));\n }\n }\n}\n",s="// The lightmap data\n@group(1) @binding(0) var lightmap : texture_2d_array;\n\n// The sampler used to sample the lightmap\n@group(1) @binding(1) var smpl : sampler;\n\n// Vertex shader input data\nstruct VertexIn {\n @location(0) position : vec4f,\n @location(1) uv : vec3f,\n @location(2) emissive : vec3f,\n}\n\n// Vertex shader output data\nstruct VertexOut {\n @builtin(position) position : vec4f,\n @location(0) uv : vec2f,\n @location(1) emissive : vec3f,\n @interpolate(flat)\n @location(2) quad : u32,\n}\n\n@vertex\nfn vs_main(input : VertexIn) -> VertexOut {\n var output : VertexOut;\n output.position = common_uniforms.mvp * input.position;\n output.uv = input.uv.xy;\n output.quad = u32(input.uv.z + 0.5);\n output.emissive = input.emissive;\n return output;\n}\n\n@fragment\nfn fs_main(vertex_out : VertexOut) -> @location(0) vec4f {\n return textureSample(lightmap, smpl, vertex_out.uv, vertex_out.quad) + vec4f(vertex_out.emissive, 1);\n}\n",u="// The lightmap data\n@group(1) @binding(0) var lightmap : texture_2d_array;\n\n// The sampler used to sample the lightmap\n@group(1) @binding(1) var smpl : sampler;\n\n// The output framebuffer\n@group(1) @binding(2) var framebuffer : texture_storage_2d;\n\noverride WorkgroupSizeX : u32;\noverride WorkgroupSizeY : u32;\n\nconst NumReflectionRays = 5;\n\n@compute @workgroup_size(WorkgroupSizeX, WorkgroupSizeY)\nfn main(@builtin(global_invocation_id) invocation_id : vec3u) {\n if (all(invocation_id.xy < textureDimensions(framebuffer))) {\n init_rand(invocation_id);\n\n // Calculate the fragment's NDC coordinates for the intersection of the near\n // clip plane and far clip plane\n let uv = vec2f(invocation_id.xy) / vec2f(textureDimensions(framebuffer).xy);\n let ndcXY = (uv - 0.5) * vec2(2, -2);\n\n // Transform the coordinates back into world space\n var near = common_uniforms.inv_mvp * vec4f(ndcXY, 0.0, 1);\n var far = common_uniforms.inv_mvp * vec4f(ndcXY, 1, 1);\n near /= near.w;\n far /= far.w;\n\n // Create a ray that starts at the near clip plane, heading in the fragment's\n // z-direction, and raytrace to find the nearest quad that the ray intersects.\n let ray = Ray(near.xyz, normalize(far.xyz - near.xyz));\n let hit = raytrace(ray);\n\n let hit_color = sample_hit(hit);\n var normal = quads[hit.quad].plane.xyz;\n\n // Fire a few rays off the surface to collect some reflections\n let bounce = reflect(ray.dir, normal);\n var reflection : vec3f;\n for (var i = 0; i < NumReflectionRays; i++) {\n let reflection_dir = normalize(bounce + rand_unit_sphere()*0.1);\n let reflection_ray = Ray(hit.pos + bounce * 1e-5, reflection_dir);\n let reflection_hit = raytrace(reflection_ray);\n reflection += sample_hit(reflection_hit);\n }\n let color = mix(reflection / NumReflectionRays, hit_color, 0.95);\n\n textureStore(framebuffer, invocation_id.xy, vec4(color, 1));\n }\n}\n\n\n// Returns the sampled hit quad's lightmap at 'hit.uv', and adds the quad's\n// emissive value.\nfn sample_hit(hit : HitInfo) -> vec3f {\n let quad = quads[hit.quad];\n // Sample the quad's lightmap, and add emissive.\n return textureSampleLevel(lightmap, smpl, hit.uv, hit.quad, 0).rgb +\n quad.emissive * quad.color;\n}\n",c="// The linear-light input framebuffer\n@group(0) @binding(0) var input : texture_2d;\n\n// The tonemapped, gamma-corrected output framebuffer\n@group(0) @binding(1) var output : texture_storage_2d<{OUTPUT_FORMAT}, write>;\n\nconst TonemapExposure = 0.5;\n\nconst Gamma = 2.2;\n\noverride WorkgroupSizeX : u32;\noverride WorkgroupSizeY : u32;\n\n@compute @workgroup_size(WorkgroupSizeX, WorkgroupSizeY)\nfn main(@builtin(global_invocation_id) invocation_id : vec3u) {\n let color = textureLoad(input, invocation_id.xy, 0).rgb;\n let tonemapped = reinhard_tonemap(color);\n textureStore(output, invocation_id.xy, vec4f(tonemapped, 1));\n}\n\nfn reinhard_tonemap(linearColor: vec3f) -> vec3f {\n let color = linearColor * TonemapExposure;\n let mapped = color / (1+color);\n return pow(mapped, vec3f(1 / Gamma));\n}\n",d="const pi = 3.14159265359;\n\n// Quad describes 2D rectangle on a plane\nstruct Quad {\n // The surface plane\n plane : vec4f,\n // A plane with a normal in the 'u' direction, intersecting the origin, at\n // right-angles to the surface plane.\n // The dot product of 'right' with a 'vec4(pos, 1)' will range between [-1..1]\n // if the projected point is within the quad.\n right : vec4f,\n // A plane with a normal in the 'v' direction, intersecting the origin, at\n // right-angles to the surface plane.\n // The dot product of 'up' with a 'vec4(pos, 1)' will range between [-1..1]\n // if the projected point is within the quad.\n up : vec4f,\n // The diffuse color of the quad\n color : vec3f,\n // Emissive value. 0=no emissive, 1=full emissive.\n emissive : f32,\n};\n\n// Ray is a start point and direction.\nstruct Ray {\n start : vec3f,\n dir : vec3f,\n}\n\n// Value for HitInfo.quad if no intersection occured.\nconst kNoHit = 0xffffffff;\n\n// HitInfo describes the hit location of a ray-quad intersection\nstruct HitInfo {\n // Distance along the ray to the intersection\n dist : f32,\n // The quad index that was hit\n quad : u32,\n // The position of the intersection\n pos : vec3f,\n // The UVs of the quad at the point of intersection\n uv : vec2f,\n}\n\n// CommonUniforms uniform buffer data\nstruct CommonUniforms {\n // Model View Projection matrix\n mvp : mat4x4f,\n // Inverse of mvp\n inv_mvp : mat4x4f,\n // Random seed for the workgroup\n seed : vec3u,\n}\n\n// The common uniform buffer binding.\n@group(0) @binding(0) var common_uniforms : CommonUniforms;\n\n// The quad buffer binding.\n@group(0) @binding(1) var quads : array;\n\n// intersect_ray_quad will check to see if the ray 'r' intersects the quad 'q'.\n// If an intersection occurs, and the intersection is closer than 'closest' then\n// the intersection information is returned, otherwise 'closest' is returned.\nfn intersect_ray_quad(r : Ray, quad : u32, closest : HitInfo) -> HitInfo {\n let q = quads[quad];\n let plane_dist = dot(q.plane, vec4(r.start, 1));\n let ray_dist = plane_dist / -dot(q.plane.xyz, r.dir);\n let pos = r.start + r.dir * ray_dist;\n let uv = vec2(dot(vec4f(pos, 1), q.right),\n dot(vec4f(pos, 1), q.up)) * 0.5 + 0.5;\n let hit = plane_dist > 0 &&\n ray_dist > 0 &&\n ray_dist < closest.dist &&\n all((uv > vec2f()) & (uv < vec2f(1)));\n return HitInfo(\n select(closest.dist, ray_dist, hit),\n select(closest.quad, quad, hit),\n select(closest.pos, pos, hit),\n select(closest.uv, uv, hit),\n );\n}\n\n// raytrace finds the closest intersecting quad for the given ray\nfn raytrace(ray : Ray) -> HitInfo {\n var hit = HitInfo();\n hit.dist = 1e20;\n hit.quad = kNoHit;\n for (var quad = 0u; quad < arrayLength(&quads); quad++) {\n hit = intersect_ray_quad(ray, quad, hit);\n }\n return hit;\n}\n\n// A psuedo random number. Initialized with init_rand(), updated with rand().\nvar rnd : vec3u;\n\n// Initializes the random number generator.\nfn init_rand(invocation_id : vec3u) {\n const A = vec3(1741651 * 1009,\n 140893 * 1609 * 13,\n 6521 * 983 * 7 * 2);\n rnd = (invocation_id * A) ^ common_uniforms.seed;\n}\n\n// Returns a random number between 0 and 1.\nfn rand() -> f32 {\n const C = vec3(60493 * 9377,\n 11279 * 2539 * 23,\n 7919 * 631 * 5 * 3);\n\n rnd = (rnd * C) ^ (rnd.yzx >> vec3(4u));\n return f32(rnd.x ^ rnd.y) / f32(0xffffffff);\n}\n\n// Returns a random point within a unit sphere centered at (0,0,0).\nfn rand_unit_sphere() -> vec3f {\n var u = rand();\n var v = rand();\n var theta = u * 2.0 * pi;\n var phi = acos(2.0 * v - 1.0);\n var r = pow(rand(), 1.0/3.0);\n var sin_theta = sin(theta);\n var cos_theta = cos(theta);\n var sin_phi = sin(phi);\n var cos_phi = cos(phi);\n var x = r * sin_phi * sin_theta;\n var y = r * sin_phi * cos_theta;\n var z = r * cos_phi;\n return vec3f(x, y, z);\n}\n\nfn rand_concentric_disk() -> vec2f {\n let u = vec2f(rand(), rand());\n let uOffset = 2.f * u - vec2f(1, 1);\n\n if (uOffset.x == 0 && uOffset.y == 0){\n return vec2f(0, 0);\n }\n\n var theta = 0.0;\n var r = 0.0;\n if (abs(uOffset.x) > abs(uOffset.y)) {\n r = uOffset.x;\n theta = (pi / 4) * (uOffset.y / uOffset.x);\n } else {\n r = uOffset.y;\n theta = (pi / 2) - (pi / 4) * (uOffset.x / uOffset.y);\n }\n return r * vec2f(cos(theta), sin(theta));\n}\n\nfn rand_cosine_weighted_hemisphere() -> vec3f {\n let d = rand_concentric_disk();\n let z = sqrt(max(0.0, 1.0 - d.x * d.x - d.y * d.y));\n return vec3f(d.x, d.y, z);\n}\n",l=t(6416);function m(e){let n=1/l.R3.lenSq(e);return l.R3.mul(l.R3.fromValues(n,n,n),e)}function f(e){let n=l.R3.fromValues(Math.cos(e.rotation)*(e.width/2),0,Math.sin(e.rotation)*(e.depth/2)),t=l.R3.fromValues(0,e.height/2,0),a=l.R3.fromValues(Math.sin(e.rotation)*(e.width/2),0,-Math.cos(e.rotation)*(e.depth/2)),i=e.color instanceof Array?e.color:Array(6).fill(e.color),o=n=>"concave"===e.type?n:l.R3.negate(n);return[{center:l.R3.add(e.center,n),right:o(l.R3.negate(a)),up:t,color:i[r.PositiveX]},{center:l.R3.add(e.center,t),right:o(n),up:l.R3.negate(a),color:i[r.PositiveY]},{center:l.R3.add(e.center,a),right:o(n),up:t,color:i[r.PositiveZ]},{center:l.R3.sub(e.center,n),right:o(a),up:t,color:i[r.NegativeX]},{center:l.R3.sub(e.center,t),right:o(n),up:a,color:i[r.NegativeY]},{center:l.R3.sub(e.center,a),right:o(l.R3.negate(n)),up:t,color:i[r.NegativeZ]}]}(a=r||(r={}))[a.PositiveX=0]="PositiveX",a[a.PositiveY=1]="PositiveY",a[a.PositiveZ=2]="PositiveZ",a[a.NegativeX=3]="NegativeX",a[a.NegativeY=4]="NegativeY",a[a.NegativeZ=5]="NegativeZ";let p={center:l.R3.fromValues(0,9.95,0),right:l.R3.fromValues(1,0,0),up:l.R3.fromValues(0,0,1),color:l.R3.fromValues(5,5,5),emissive:1};class h{constructor(e){this.quads=[...f({center:l.R3.fromValues(0,5,0),width:10,height:10,depth:10,rotation:0,color:[l.R3.fromValues(0,.5,0),l.R3.fromValues(.5,.5,.5),l.R3.fromValues(.5,.5,.5),l.R3.fromValues(.5,0,0),l.R3.fromValues(.5,.5,.5),l.R3.fromValues(.5,.5,.5)],type:"concave"}),...f({center:l.R3.fromValues(1.5,1.5,1),width:3,height:3,depth:3,rotation:.3,color:l.R3.fromValues(.8,.8,.8),type:"convex"}),...f({center:l.R3.fromValues(-2,3,-2),width:3,height:6,depth:3,rotation:-.4,color:l.R3.fromValues(.8,.8,.8),type:"convex"}),p],this.lightCenter=p.center,this.lightWidth=2*l.R3.len(p.right),this.lightHeight=2*l.R3.len(p.up);let n=e.createBuffer({size:64*this.quads.length,usage:GPUBufferUsage.STORAGE,mappedAtCreation:!0}),t=new Float32Array(n.getMappedRange()),a=new Float32Array(40*this.quads.length),r=new Uint32Array(9*this.quads.length),i=0,o=0,s=0,u=0,c=0;for(let d=0;d x\n const x = vec3.fromValues(\n Math.cos(params.rotation) * (params.width / 2),\n 0,\n Math.sin(params.rotation) * (params.depth / 2)\n );\n const y = vec3.fromValues(0, params.height / 2, 0);\n const z = vec3.fromValues(\n Math.sin(params.rotation) * (params.width / 2),\n 0,\n -Math.cos(params.rotation) * (params.depth / 2)\n );\n const colors =\n params.color instanceof Array\n ? params.color\n : new Array(6).fill(params.color);\n const sign = (v: Vec3) => {\n return params.type === 'concave' ? v : vec3.negate(v);\n };\n return [\n {\n // PositiveX\n center: vec3.add(params.center, x),\n right: sign(vec3.negate(z)),\n up: y,\n color: colors[CubeFace.PositiveX],\n },\n {\n // PositiveY\n center: vec3.add(params.center, y),\n right: sign(x),\n up: vec3.negate(z),\n color: colors[CubeFace.PositiveY],\n },\n {\n // PositiveZ\n center: vec3.add(params.center, z),\n right: sign(x),\n up: y,\n color: colors[CubeFace.PositiveZ],\n },\n {\n // NegativeX\n center: vec3.sub(params.center, x),\n right: sign(z),\n up: y,\n color: colors[CubeFace.NegativeX],\n },\n {\n // NegativeY\n center: vec3.sub(params.center, y),\n right: sign(x),\n up: z,\n color: colors[CubeFace.NegativeY],\n },\n {\n // NegativeZ\n center: vec3.sub(params.center, z),\n right: sign(vec3.negate(x)),\n up: y,\n color: colors[CubeFace.NegativeZ],\n },\n ];\n}\n\nconst light: Quad = {\n center: vec3.fromValues(0, 9.95, 0),\n right: vec3.fromValues(1, 0, 0),\n up: vec3.fromValues(0, 0, 1),\n color: vec3.fromValues(5.0, 5.0, 5.0),\n emissive: 1.0,\n};\n\n/**\n * Scene holds the cornell-box scene information.\n */\nexport default class Scene {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n readonly vertexCount: number;\n readonly indexCount: number;\n readonly vertices: GPUBuffer;\n readonly indices: GPUBuffer;\n readonly vertexBufferLayout: GPUVertexBufferLayout[];\n readonly quadBuffer: GPUBuffer;\n readonly quads = [\n ...box({\n center: vec3.fromValues(0, 5, 0),\n width: 10,\n height: 10,\n depth: 10,\n rotation: 0,\n color: [\n vec3.fromValues(0.0, 0.5, 0.0), // PositiveX\n vec3.fromValues(0.5, 0.5, 0.5), // PositiveY\n vec3.fromValues(0.5, 0.5, 0.5), // PositiveZ\n vec3.fromValues(0.5, 0.0, 0.0), // NegativeX\n vec3.fromValues(0.5, 0.5, 0.5), // NegativeY\n vec3.fromValues(0.5, 0.5, 0.5), // NegativeZ\n ],\n type: 'concave',\n }),\n ...box({\n center: vec3.fromValues(1.5, 1.5, 1),\n width: 3,\n height: 3,\n depth: 3,\n rotation: 0.3,\n color: vec3.fromValues(0.8, 0.8, 0.8),\n type: 'convex',\n }),\n ...box({\n center: vec3.fromValues(-2, 3, -2),\n width: 3,\n height: 6,\n depth: 3,\n rotation: -0.4,\n color: vec3.fromValues(0.8, 0.8, 0.8),\n type: 'convex',\n }),\n light,\n ];\n readonly lightCenter = light.center;\n readonly lightWidth = vec3.len(light.right) * 2;\n readonly lightHeight = vec3.len(light.up) * 2;\n\n constructor(device: GPUDevice) {\n const quadStride = 16 * 4;\n const quadBuffer = device.createBuffer({\n size: quadStride * this.quads.length,\n usage: GPUBufferUsage.STORAGE,\n mappedAtCreation: true,\n });\n const quadData = new Float32Array(quadBuffer.getMappedRange());\n const vertexStride = 4 * 10;\n const vertexData = new Float32Array(this.quads.length * vertexStride);\n const indexData = new Uint32Array(this.quads.length * 9); // TODO: 6?\n let vertexCount = 0;\n let indexCount = 0;\n let quadDataOffset = 0;\n let vertexDataOffset = 0;\n let indexDataOffset = 0;\n for (let quadIdx = 0; quadIdx < this.quads.length; quadIdx++) {\n const quad = this.quads[quadIdx];\n const normal = vec3.normalize(vec3.cross(quad.right, quad.up));\n quadData[quadDataOffset++] = normal[0];\n quadData[quadDataOffset++] = normal[1];\n quadData[quadDataOffset++] = normal[2];\n quadData[quadDataOffset++] = -vec3.dot(normal, quad.center);\n\n const invRight = reciprocal(quad.right);\n quadData[quadDataOffset++] = invRight[0];\n quadData[quadDataOffset++] = invRight[1];\n quadData[quadDataOffset++] = invRight[2];\n quadData[quadDataOffset++] = -vec3.dot(invRight, quad.center);\n\n const invUp = reciprocal(quad.up);\n quadData[quadDataOffset++] = invUp[0];\n quadData[quadDataOffset++] = invUp[1];\n quadData[quadDataOffset++] = invUp[2];\n quadData[quadDataOffset++] = -vec3.dot(invUp, quad.center);\n\n quadData[quadDataOffset++] = quad.color[0];\n quadData[quadDataOffset++] = quad.color[1];\n quadData[quadDataOffset++] = quad.color[2];\n quadData[quadDataOffset++] = quad.emissive ?? 0;\n\n // a ----- b\n // | |\n // | m |\n // | |\n // c ----- d\n const a = vec3.add(vec3.sub(quad.center, quad.right), quad.up);\n const b = vec3.add(vec3.add(quad.center, quad.right), quad.up);\n const c = vec3.sub(vec3.sub(quad.center, quad.right), quad.up);\n const d = vec3.sub(vec3.add(quad.center, quad.right), quad.up);\n\n vertexData[vertexDataOffset++] = a[0];\n vertexData[vertexDataOffset++] = a[1];\n vertexData[vertexDataOffset++] = a[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 0; // uv.x\n vertexData[vertexDataOffset++] = 1; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n vertexData[vertexDataOffset++] = b[0];\n vertexData[vertexDataOffset++] = b[1];\n vertexData[vertexDataOffset++] = b[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 1; // uv.x\n vertexData[vertexDataOffset++] = 1; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n vertexData[vertexDataOffset++] = c[0];\n vertexData[vertexDataOffset++] = c[1];\n vertexData[vertexDataOffset++] = c[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 0; // uv.x\n vertexData[vertexDataOffset++] = 0; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n vertexData[vertexDataOffset++] = d[0];\n vertexData[vertexDataOffset++] = d[1];\n vertexData[vertexDataOffset++] = d[2];\n vertexData[vertexDataOffset++] = 1;\n vertexData[vertexDataOffset++] = 1; // uv.x\n vertexData[vertexDataOffset++] = 0; // uv.y\n vertexData[vertexDataOffset++] = quadIdx;\n vertexData[vertexDataOffset++] = quad.color[0] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[1] * (quad.emissive ?? 0);\n vertexData[vertexDataOffset++] = quad.color[2] * (quad.emissive ?? 0);\n\n indexData[indexDataOffset++] = vertexCount + 0; // a\n indexData[indexDataOffset++] = vertexCount + 2; // c\n indexData[indexDataOffset++] = vertexCount + 1; // b\n indexData[indexDataOffset++] = vertexCount + 1; // b\n indexData[indexDataOffset++] = vertexCount + 2; // c\n indexData[indexDataOffset++] = vertexCount + 3; // d\n indexCount += 6;\n vertexCount += 4;\n }\n\n quadBuffer.unmap();\n\n const vertices = device.createBuffer({\n size: vertexData.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(vertices.getMappedRange()).set(vertexData);\n vertices.unmap();\n\n const indices = device.createBuffer({\n size: indexData.byteLength,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n new Uint16Array(indices.getMappedRange()).set(indexData);\n indices.unmap();\n\n const vertexBufferLayout: GPUVertexBufferLayout[] = [\n {\n arrayStride: vertexStride,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0 * 4,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: 4 * 4,\n format: 'float32x3',\n },\n {\n // color\n shaderLocation: 2,\n offset: 7 * 4,\n format: 'float32x3',\n },\n ],\n },\n ];\n\n this.vertexCount = vertexCount;\n this.indexCount = indexCount;\n this.vertices = vertices;\n this.indices = indices;\n this.vertexBufferLayout = vertexBufferLayout;\n this.quadBuffer = quadBuffer;\n }\n}\n"};class g{update(e){let n=l._E.perspective(2*Math.PI/8,e.aspect,.5,100),t=e.rotateCamera?this.frame/1e3:0,a=l._E.lookAt(l.R3.fromValues(15*Math.sin(t),5,15*Math.cos(t)),l.R3.fromValues(0,5,0),l.R3.fromValues(0,1,0)),r=l._E.multiply(n,a),i=l._E.invert(r),o=new Float32Array(this.uniformBuffer.size/4),s=new Uint32Array(o.buffer);for(let u=0;u<16;u++)o[u]=r[u];for(let c=0;c<16;c++)o[c+16]=i[c];s[32]=4294967295*Math.random(),s[33]=4294967295*Math.random(),s[34]=4294967295*Math.random(),this.device.queue.writeBuffer(this.uniformBuffer,0,o.buffer,o.byteOffset,o.byteLength),this.frame++}constructor(e,n){this.wgsl=d,this.frame=0,this.device=e,this.uniformBuffer=e.createBuffer({label:"Common.uniformBuffer",size:144,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let t=e.createBindGroupLayout({label:"Common.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.VERTEX|GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}}]}),a=e.createBindGroup({label:"Common.bindGroup",layout:t,entries:[{binding:0,resource:{buffer:this.uniformBuffer,offset:0,size:this.uniformBuffer.size}},{binding:1,resource:{buffer:n,offset:0,size:n.size}}]});this.uniforms={bindGroupLayout:t,bindGroup:a}}}g.sourceInfo={name:"src/sample/cornell/common.ts".substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport commonWGSL from './common.wgsl';\n\n/**\n * Common holds the shared WGSL between the shaders, including the common uniform buffer.\n */\nexport default class Common {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n /** The WGSL of the common shader */\n readonly wgsl = commonWGSL;\n /** The common uniform buffer bind group and layout */\n readonly uniforms: {\n bindGroupLayout: GPUBindGroupLayout;\n bindGroup: GPUBindGroup;\n };\n\n private readonly device: GPUDevice;\n private readonly uniformBuffer: GPUBuffer;\n\n private frame = 0;\n\n constructor(device: GPUDevice, quads: GPUBuffer) {\n this.device = device;\n this.uniformBuffer = device.createBuffer({\n label: 'Common.uniformBuffer',\n size:\n 0 + //\n 4 * 16 + // mvp\n 4 * 16 + // inv_mvp\n 4 * 4, // seed\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Common.bindGroupLayout',\n entries: [\n {\n // common_uniforms\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE,\n buffer: { type: 'uniform' },\n },\n {\n // quads\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type: 'read-only-storage' },\n },\n ],\n });\n\n const bindGroup = device.createBindGroup({\n label: 'Common.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // common_uniforms\n binding: 0,\n resource: {\n buffer: this.uniformBuffer,\n offset: 0,\n size: this.uniformBuffer.size,\n },\n },\n {\n // quads\n binding: 1,\n resource: {\n buffer: quads,\n offset: 0,\n size: quads.size,\n },\n },\n ],\n });\n\n this.uniforms = { bindGroupLayout, bindGroup };\n }\n\n /** Updates the uniform buffer data */\n update(params: { rotateCamera: boolean; aspect: number }) {\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 8,\n params.aspect,\n 0.5,\n 100\n );\n\n const viewRotation = params.rotateCamera ? this.frame / 1000 : 0;\n\n const viewMatrix = mat4.lookAt(\n vec3.fromValues(\n Math.sin(viewRotation) * 15,\n 5,\n Math.cos(viewRotation) * 15\n ),\n vec3.fromValues(0, 5, 0),\n vec3.fromValues(0, 1, 0)\n );\n const mvp = mat4.multiply(projectionMatrix, viewMatrix);\n const invMVP = mat4.invert(mvp);\n\n const uniformDataF32 = new Float32Array(this.uniformBuffer.size / 4);\n const uniformDataU32 = new Uint32Array(uniformDataF32.buffer);\n for (let i = 0; i < 16; i++) {\n uniformDataF32[i] = mvp[i];\n }\n for (let i = 0; i < 16; i++) {\n uniformDataF32[i + 16] = invMVP[i];\n }\n uniformDataU32[32] = 0xffffffff * Math.random();\n uniformDataU32[33] = 0xffffffff * Math.random();\n uniformDataU32[34] = 0xffffffff * Math.random();\n\n this.device.queue.writeBuffer(\n this.uniformBuffer,\n 0,\n uniformDataF32.buffer,\n uniformDataF32.byteOffset,\n uniformDataF32.byteLength\n );\n\n this.frame++;\n }\n}\n"};class v{run(e){this.accumulationMean+=this.kPhotonsPerFrame*this.kPhotonEnergy/this.kTotalLightmapTexels;let n=1/this.accumulationMean,t=this.accumulationMean>2*this.kAccumulationMeanMax?.5:1;this.accumulationMean*=t;let a=new Float32Array(this.uniformBuffer.size/4);a[0]=n,a[1]=t,a[2]=this.scene.lightWidth,a[3]=this.scene.lightHeight,a[4]=this.scene.lightCenter[0],a[5]=this.scene.lightCenter[1],a[6]=this.scene.lightCenter[2],this.device.queue.writeBuffer(this.uniformBuffer,0,a.buffer,a.byteOffset,a.byteLength);let r=e.beginComputePass();r.setBindGroup(0,this.common.uniforms.bindGroup),r.setBindGroup(1,this.bindGroup),r.setPipeline(this.radiosityPipeline),r.dispatchWorkgroups(this.kWorkgroupsPerFrame),r.setPipeline(this.accumulationToLightmapPipeline),r.dispatchWorkgroups(Math.ceil(v.lightmapWidth/this.kAccumulationToLightmapWorkgroupSizeX),Math.ceil(v.lightmapHeight/this.kAccumulationToLightmapWorkgroupSizeY),this.lightmap.depthOrArrayLayers),r.end()}constructor(e,n,t){this.kPhotonsPerWorkgroup=256,this.kWorkgroupsPerFrame=1024,this.kPhotonsPerFrame=this.kPhotonsPerWorkgroup*this.kWorkgroupsPerFrame,this.kPhotonEnergy=1e5,this.kAccumulationToLightmapWorkgroupSizeX=16,this.kAccumulationToLightmapWorkgroupSizeY=16,this.accumulationMean=0,this.kAccumulationMeanMax=268435456,this.device=e,this.common=n,this.scene=t,this.lightmap=e.createTexture({label:"Radiosity.lightmap",size:{width:v.lightmapWidth,height:v.lightmapHeight,depthOrArrayLayers:t.quads.length},format:v.lightmapFormat,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.STORAGE_BINDING}),this.accumulationBuffer=e.createBuffer({label:"Radiosity.accumulationBuffer",size:v.lightmapWidth*v.lightmapHeight*t.quads.length*16,usage:GPUBufferUsage.STORAGE}),this.kTotalLightmapTexels=v.lightmapWidth*v.lightmapHeight*t.quads.length,this.uniformBuffer=e.createBuffer({label:"Radiosity.uniformBuffer",size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let a=e.createBindGroupLayout({label:"Radiosity.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:v.lightmapFormat,viewDimension:"2d-array"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}}]});this.bindGroup=e.createBindGroup({label:"Radiosity.bindGroup",layout:a,entries:[{binding:0,resource:{buffer:this.accumulationBuffer,size:this.accumulationBuffer.size}},{binding:1,resource:this.lightmap.createView()},{binding:2,resource:{buffer:this.uniformBuffer,size:this.uniformBuffer.size}}]});let r=e.createShaderModule({code:o+n.wgsl}),i=e.createPipelineLayout({label:"Radiosity.accumulatePipelineLayout",bindGroupLayouts:[n.uniforms.bindGroupLayout,a]});this.radiosityPipeline=e.createComputePipeline({label:"Radiosity.radiosityPipeline",layout:i,compute:{module:r,entryPoint:"radiosity",constants:{PhotonsPerWorkgroup:this.kPhotonsPerWorkgroup,PhotonEnergy:this.kPhotonEnergy}}}),this.accumulationToLightmapPipeline=e.createComputePipeline({label:"Radiosity.accumulationToLightmapPipeline",layout:i,compute:{module:r,entryPoint:"accumulation_to_lightmap",constants:{AccumulationToLightmapWorkgroupSizeX:this.kAccumulationToLightmapWorkgroupSizeX,AccumulationToLightmapWorkgroupSizeY:this.kAccumulationToLightmapWorkgroupSizeY}}})}}v.sourceInfo={name:"src/sample/cornell/radiosity.ts".substring(19),contents:"import Common from './common';\nimport radiosityWGSL from './radiosity.wgsl';\nimport Scene from './scene';\n\n/**\n * Radiosity computes lightmaps, calculated by software raytracing of light in\n * the scene.\n */\nexport default class Radiosity {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n // The output lightmap format and dimensions\n static readonly lightmapFormat = 'rgba16float';\n static readonly lightmapWidth = 256;\n static readonly lightmapHeight = 256;\n\n // The output lightmap.\n readonly lightmap: GPUTexture;\n\n // Number of photons emitted per workgroup.\n // This is equal to the workgroup size (one photon per invocation)\n private readonly kPhotonsPerWorkgroup = 256;\n // Number of radiosity workgroups dispatched per frame.\n private readonly kWorkgroupsPerFrame = 1024;\n private readonly kPhotonsPerFrame =\n this.kPhotonsPerWorkgroup * this.kWorkgroupsPerFrame;\n // Maximum value that can be added to the 'accumulation' buffer, per photon,\n // across all texels.\n private readonly kPhotonEnergy = 100000;\n // The total number of lightmap texels for all quads.\n private readonly kTotalLightmapTexels;\n\n private readonly kAccumulationToLightmapWorkgroupSizeX = 16;\n private readonly kAccumulationToLightmapWorkgroupSizeY = 16;\n\n private readonly device: GPUDevice;\n private readonly common: Common;\n private readonly scene: Scene;\n private readonly radiosityPipeline: GPUComputePipeline;\n private readonly accumulationToLightmapPipeline: GPUComputePipeline;\n private readonly bindGroup: GPUBindGroup;\n private readonly accumulationBuffer: GPUBuffer;\n private readonly uniformBuffer: GPUBuffer;\n\n // The 'accumulation' buffer average value\n private accumulationMean = 0;\n\n // The maximum value of 'accumulationAverage' before all values in\n // 'accumulation' are reduced to avoid integer overflows.\n private readonly kAccumulationMeanMax = 0x10000000;\n\n constructor(device: GPUDevice, common: Common, scene: Scene) {\n this.device = device;\n this.common = common;\n this.scene = scene;\n this.lightmap = device.createTexture({\n label: 'Radiosity.lightmap',\n size: {\n width: Radiosity.lightmapWidth,\n height: Radiosity.lightmapHeight,\n depthOrArrayLayers: scene.quads.length,\n },\n format: Radiosity.lightmapFormat,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,\n });\n this.accumulationBuffer = device.createBuffer({\n label: 'Radiosity.accumulationBuffer',\n size:\n Radiosity.lightmapWidth *\n Radiosity.lightmapHeight *\n scene.quads.length *\n 16,\n usage: GPUBufferUsage.STORAGE,\n });\n this.kTotalLightmapTexels =\n Radiosity.lightmapWidth * Radiosity.lightmapHeight * scene.quads.length;\n this.uniformBuffer = device.createBuffer({\n label: 'Radiosity.uniformBuffer',\n size: 8 * 4, // 8 x f32\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Radiosity.bindGroupLayout',\n entries: [\n {\n // accumulation buffer\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type: 'storage' },\n },\n {\n // lightmap\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n storageTexture: {\n access: 'write-only',\n format: Radiosity.lightmapFormat,\n viewDimension: '2d-array',\n },\n },\n {\n // radiosity_uniforms\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type: 'uniform' },\n },\n ],\n });\n this.bindGroup = device.createBindGroup({\n label: 'Radiosity.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // accumulation buffer\n binding: 0,\n resource: {\n buffer: this.accumulationBuffer,\n size: this.accumulationBuffer.size,\n },\n },\n {\n // lightmap\n binding: 1,\n resource: this.lightmap.createView(),\n },\n {\n // radiosity_uniforms\n binding: 2,\n resource: {\n buffer: this.uniformBuffer,\n size: this.uniformBuffer.size,\n },\n },\n ],\n });\n\n const mod = device.createShaderModule({\n code: radiosityWGSL + common.wgsl,\n });\n const pipelineLayout = device.createPipelineLayout({\n label: 'Radiosity.accumulatePipelineLayout',\n bindGroupLayouts: [common.uniforms.bindGroupLayout, bindGroupLayout],\n });\n\n this.radiosityPipeline = device.createComputePipeline({\n label: 'Radiosity.radiosityPipeline',\n layout: pipelineLayout,\n compute: {\n module: mod,\n entryPoint: 'radiosity',\n constants: {\n PhotonsPerWorkgroup: this.kPhotonsPerWorkgroup,\n PhotonEnergy: this.kPhotonEnergy,\n },\n },\n });\n\n this.accumulationToLightmapPipeline = device.createComputePipeline({\n label: 'Radiosity.accumulationToLightmapPipeline',\n layout: pipelineLayout,\n compute: {\n module: mod,\n entryPoint: 'accumulation_to_lightmap',\n constants: {\n AccumulationToLightmapWorkgroupSizeX:\n this.kAccumulationToLightmapWorkgroupSizeX,\n AccumulationToLightmapWorkgroupSizeY:\n this.kAccumulationToLightmapWorkgroupSizeY,\n },\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n // Calculate the new mean value for the accumulation buffer\n this.accumulationMean +=\n (this.kPhotonsPerFrame * this.kPhotonEnergy) / this.kTotalLightmapTexels;\n\n // Calculate the 'accumulation' -> 'lightmap' scale factor from 'accumulationMean'\n const accumulationToLightmapScale = 1 / this.accumulationMean;\n // If 'accumulationMean' is greater than 'kAccumulationMeanMax', then reduce\n // the 'accumulation' buffer values to prevent u32 overflow.\n const accumulationBufferScale =\n this.accumulationMean > 2 * this.kAccumulationMeanMax ? 0.5 : 1;\n this.accumulationMean *= accumulationBufferScale;\n\n // Update the radiosity uniform buffer data.\n const uniformDataF32 = new Float32Array(this.uniformBuffer.size / 4);\n uniformDataF32[0] = accumulationToLightmapScale;\n uniformDataF32[1] = accumulationBufferScale;\n uniformDataF32[2] = this.scene.lightWidth;\n uniformDataF32[3] = this.scene.lightHeight;\n uniformDataF32[4] = this.scene.lightCenter[0];\n uniformDataF32[5] = this.scene.lightCenter[1];\n uniformDataF32[6] = this.scene.lightCenter[2];\n this.device.queue.writeBuffer(\n this.uniformBuffer,\n 0,\n uniformDataF32.buffer,\n uniformDataF32.byteOffset,\n uniformDataF32.byteLength\n );\n\n // Dispatch the radiosity workgroups\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setBindGroup(0, this.common.uniforms.bindGroup);\n passEncoder.setBindGroup(1, this.bindGroup);\n passEncoder.setPipeline(this.radiosityPipeline);\n passEncoder.dispatchWorkgroups(this.kWorkgroupsPerFrame);\n\n // Then copy the 'accumulation' data to 'lightmap'\n passEncoder.setPipeline(this.accumulationToLightmapPipeline);\n passEncoder.dispatchWorkgroups(\n Math.ceil(\n Radiosity.lightmapWidth / this.kAccumulationToLightmapWorkgroupSizeX\n ),\n Math.ceil(\n Radiosity.lightmapHeight / this.kAccumulationToLightmapWorkgroupSizeY\n ),\n this.lightmap.depthOrArrayLayers\n );\n passEncoder.end();\n }\n}\n"},v.lightmapFormat="rgba16float",v.lightmapWidth=256,v.lightmapHeight=256;class b{run(e){let n=e.beginRenderPass(this.renderPassDescriptor);n.setPipeline(this.pipeline),n.setVertexBuffer(0,this.scene.vertices),n.setIndexBuffer(this.scene.indices,"uint16"),n.setBindGroup(0,this.common.uniforms.bindGroup),n.setBindGroup(1,this.bindGroup),n.drawIndexed(this.scene.indexCount),n.end()}constructor(e,n,t,a,r){this.common=n,this.scene=t;let i=e.createTexture({label:"RasterizerRenderer.depthTexture",size:[r.width,r.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT});this.renderPassDescriptor={label:"RasterizerRenderer.renderPassDescriptor",colorAttachments:[{view:r.createView(),clearValue:[.1,.2,.3,1],loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:i.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}};let o=e.createBindGroupLayout({label:"RasterizerRenderer.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,texture:{viewDimension:"2d-array"}},{binding:1,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,sampler:{}}]});this.bindGroup=e.createBindGroup({label:"RasterizerRenderer.bindGroup",layout:o,entries:[{binding:0,resource:a.lightmap.createView()},{binding:1,resource:e.createSampler({addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",magFilter:"linear",minFilter:"linear"})}]});let u=e.createShaderModule({label:"RasterizerRenderer.module",code:s+n.wgsl});this.pipeline=e.createRenderPipeline({label:"RasterizerRenderer.pipeline",layout:e.createPipelineLayout({bindGroupLayouts:[n.uniforms.bindGroupLayout,o]}),vertex:{module:u,entryPoint:"vs_main",buffers:t.vertexBufferLayout},fragment:{module:u,entryPoint:"fs_main",targets:[{format:r.format}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}})}}b.sourceInfo={name:"src/sample/cornell/rasterizer.ts".substring(19),contents:"import rasterizerWGSL from './rasterizer.wgsl';\n\nimport Common from './common';\nimport Radiosity from './radiosity';\nimport Scene from './scene';\n\n/**\n * Rasterizer renders the scene using a regular raserization graphics pipeline.\n */\nexport default class Rasterizer {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n private readonly common: Common;\n private readonly scene: Scene;\n private readonly renderPassDescriptor: GPURenderPassDescriptor;\n private readonly pipeline: GPURenderPipeline;\n private readonly bindGroup: GPUBindGroup;\n\n constructor(\n device: GPUDevice,\n common: Common,\n scene: Scene,\n radiosity: Radiosity,\n framebuffer: GPUTexture\n ) {\n this.common = common;\n this.scene = scene;\n\n const depthTexture = device.createTexture({\n label: 'RasterizerRenderer.depthTexture',\n size: [framebuffer.width, framebuffer.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n this.renderPassDescriptor = {\n label: 'RasterizerRenderer.renderPassDescriptor',\n colorAttachments: [\n {\n view: framebuffer.createView(),\n clearValue: [0.1, 0.2, 0.3, 1],\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'RasterizerRenderer.bindGroupLayout',\n entries: [\n {\n // lightmap\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n texture: { viewDimension: '2d-array' },\n },\n {\n // sampler\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n sampler: {},\n },\n ],\n });\n\n this.bindGroup = device.createBindGroup({\n label: 'RasterizerRenderer.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // lightmap\n binding: 0,\n resource: radiosity.lightmap.createView(),\n },\n {\n // sampler\n binding: 1,\n resource: device.createSampler({\n addressModeU: 'clamp-to-edge',\n addressModeV: 'clamp-to-edge',\n magFilter: 'linear',\n minFilter: 'linear',\n }),\n },\n ],\n });\n\n const mod = device.createShaderModule({\n label: 'RasterizerRenderer.module',\n code: rasterizerWGSL + common.wgsl,\n });\n\n this.pipeline = device.createRenderPipeline({\n label: 'RasterizerRenderer.pipeline',\n layout: device.createPipelineLayout({\n bindGroupLayouts: [common.uniforms.bindGroupLayout, bindGroupLayout],\n }),\n vertex: {\n module: mod,\n entryPoint: 'vs_main',\n buffers: scene.vertexBufferLayout,\n },\n fragment: {\n module: mod,\n entryPoint: 'fs_main',\n targets: [{ format: framebuffer.format }],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n const passEncoder = commandEncoder.beginRenderPass(\n this.renderPassDescriptor\n );\n passEncoder.setPipeline(this.pipeline);\n passEncoder.setVertexBuffer(0, this.scene.vertices);\n passEncoder.setIndexBuffer(this.scene.indices, 'uint16');\n passEncoder.setBindGroup(0, this.common.uniforms.bindGroup);\n passEncoder.setBindGroup(1, this.bindGroup);\n passEncoder.drawIndexed(this.scene.indexCount);\n passEncoder.end();\n }\n}\n"};class y{run(e){let n=e.beginComputePass();n.setBindGroup(0,this.bindGroup),n.setPipeline(this.pipeline),n.dispatchWorkgroups(Math.ceil(this.width/this.kWorkgroupSizeX),Math.ceil(this.height/this.kWorkgroupSizeY)),n.end()}constructor(e,n,t,a){this.kWorkgroupSizeX=16,this.kWorkgroupSizeY=16,this.width=t.width,this.height=t.height;let r=e.createBindGroupLayout({label:"Tonemapper.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,texture:{viewDimension:"2d"}},{binding:1,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:a.format,viewDimension:"2d"}}]});this.bindGroup=e.createBindGroup({label:"Tonemapper.bindGroup",layout:r,entries:[{binding:0,resource:t.createView()},{binding:1,resource:a.createView()}]});let i=e.createShaderModule({code:c.replace("{OUTPUT_FORMAT}",a.format)+n.wgsl}),o=e.createPipelineLayout({label:"Tonemap.pipelineLayout",bindGroupLayouts:[r]});this.pipeline=e.createComputePipeline({label:"Tonemap.pipeline",layout:o,compute:{module:i,entryPoint:"main",constants:{WorkgroupSizeX:this.kWorkgroupSizeX,WorkgroupSizeY:this.kWorkgroupSizeY}}})}}y.sourceInfo={name:"src/sample/cornell/tonemapper.ts".substring(19),contents:"import Common from './common';\nimport tonemapperWGSL from './tonemapper.wgsl';\n\n/**\n * Tonemapper implements a tonemapper to convert a linear-light framebuffer to\n * a gamma-correct, tonemapped framebuffer used for presentation.\n */\nexport default class Tonemapper {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n private readonly bindGroup: GPUBindGroup;\n private readonly pipeline: GPUComputePipeline;\n private readonly width: number;\n private readonly height: number;\n private readonly kWorkgroupSizeX = 16;\n private readonly kWorkgroupSizeY = 16;\n\n constructor(\n device: GPUDevice,\n common: Common,\n input: GPUTexture,\n output: GPUTexture\n ) {\n this.width = input.width;\n this.height = input.height;\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Tonemapper.bindGroupLayout',\n entries: [\n {\n // input\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n texture: {\n viewDimension: '2d',\n },\n },\n {\n // output\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n storageTexture: {\n access: 'write-only',\n format: output.format,\n viewDimension: '2d',\n },\n },\n ],\n });\n this.bindGroup = device.createBindGroup({\n label: 'Tonemapper.bindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n // input\n binding: 0,\n resource: input.createView(),\n },\n {\n // output\n binding: 1,\n resource: output.createView(),\n },\n ],\n });\n\n const mod = device.createShaderModule({\n code:\n tonemapperWGSL.replace('{OUTPUT_FORMAT}', output.format) + common.wgsl,\n });\n const pipelineLayout = device.createPipelineLayout({\n label: 'Tonemap.pipelineLayout',\n bindGroupLayouts: [bindGroupLayout],\n });\n\n this.pipeline = device.createComputePipeline({\n label: 'Tonemap.pipeline',\n layout: pipelineLayout,\n compute: {\n module: mod,\n entryPoint: 'main',\n constants: {\n WorkgroupSizeX: this.kWorkgroupSizeX,\n WorkgroupSizeY: this.kWorkgroupSizeY,\n },\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setBindGroup(0, this.bindGroup);\n passEncoder.setPipeline(this.pipeline);\n passEncoder.dispatchWorkgroups(\n Math.ceil(this.width / this.kWorkgroupSizeX),\n Math.ceil(this.height / this.kWorkgroupSizeY)\n );\n passEncoder.end();\n }\n}\n"};class x{run(e){let n=e.beginComputePass();n.setPipeline(this.pipeline),n.setBindGroup(0,this.common.uniforms.bindGroup),n.setBindGroup(1,this.bindGroup),n.dispatchWorkgroups(Math.ceil(this.framebuffer.width/this.kWorkgroupSizeX),Math.ceil(this.framebuffer.height/this.kWorkgroupSizeY)),n.end()}constructor(e,n,t,a){this.kWorkgroupSizeX=16,this.kWorkgroupSizeY=16,this.common=n,this.framebuffer=a;let r=e.createBindGroupLayout({label:"Raytracer.bindGroupLayout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,texture:{viewDimension:"2d-array"}},{binding:1,visibility:GPUShaderStage.FRAGMENT|GPUShaderStage.COMPUTE,sampler:{}},{binding:2,visibility:GPUShaderStage.COMPUTE,storageTexture:{access:"write-only",format:a.format,viewDimension:"2d"}}]});this.bindGroup=e.createBindGroup({label:"rendererBindGroup",layout:r,entries:[{binding:0,resource:t.lightmap.createView()},{binding:1,resource:e.createSampler({addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",addressModeW:"clamp-to-edge",magFilter:"linear",minFilter:"linear"})},{binding:2,resource:a.createView()}]}),this.pipeline=e.createComputePipeline({label:"raytracerPipeline",layout:e.createPipelineLayout({bindGroupLayouts:[n.uniforms.bindGroupLayout,r]}),compute:{module:e.createShaderModule({code:u+n.wgsl}),entryPoint:"main",constants:{WorkgroupSizeX:this.kWorkgroupSizeX,WorkgroupSizeY:this.kWorkgroupSizeY}}})}}x.sourceInfo={name:"src/sample/cornell/raytracer.ts".substring(19),contents:"import raytracerWGSL from './raytracer.wgsl';\n\nimport Common from './common';\nimport Radiosity from './radiosity';\n\n/**\n * Raytracer renders the scene using a software ray-tracing compute pipeline.\n */\nexport default class Raytracer {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n private readonly common: Common;\n private readonly framebuffer: GPUTexture;\n private readonly pipeline: GPUComputePipeline;\n private readonly bindGroup: GPUBindGroup;\n\n private readonly kWorkgroupSizeX = 16;\n private readonly kWorkgroupSizeY = 16;\n\n constructor(\n device: GPUDevice,\n common: Common,\n radiosity: Radiosity,\n framebuffer: GPUTexture\n ) {\n this.common = common;\n this.framebuffer = framebuffer;\n const bindGroupLayout = device.createBindGroupLayout({\n label: 'Raytracer.bindGroupLayout',\n entries: [\n {\n // lightmap\n binding: 0,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n texture: { viewDimension: '2d-array' },\n },\n {\n // sampler\n binding: 1,\n visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,\n sampler: {},\n },\n {\n // framebuffer\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n storageTexture: {\n access: 'write-only',\n format: framebuffer.format,\n viewDimension: '2d',\n },\n },\n ],\n });\n\n this.bindGroup = device.createBindGroup({\n label: 'rendererBindGroup',\n layout: bindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: radiosity.lightmap.createView(),\n },\n {\n binding: 1,\n resource: device.createSampler({\n addressModeU: 'clamp-to-edge',\n addressModeV: 'clamp-to-edge',\n addressModeW: 'clamp-to-edge',\n magFilter: 'linear',\n minFilter: 'linear',\n }),\n },\n {\n binding: 2,\n resource: framebuffer.createView(),\n },\n ],\n });\n\n this.pipeline = device.createComputePipeline({\n label: 'raytracerPipeline',\n layout: device.createPipelineLayout({\n bindGroupLayouts: [common.uniforms.bindGroupLayout, bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: raytracerWGSL + common.wgsl,\n }),\n entryPoint: 'main',\n constants: {\n WorkgroupSizeX: this.kWorkgroupSizeX,\n WorkgroupSizeY: this.kWorkgroupSizeY,\n },\n },\n });\n }\n\n run(commandEncoder: GPUCommandEncoder) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(this.pipeline);\n passEncoder.setBindGroup(0, this.common.uniforms.bindGroup);\n passEncoder.setBindGroup(1, this.bindGroup);\n passEncoder.dispatchWorkgroups(\n Math.ceil(this.framebuffer.width / this.kWorkgroupSizeX),\n Math.ceil(this.framebuffer.height / this.kWorkgroupSizeY)\n );\n passEncoder.end();\n }\n}\n"};var P="src/sample/cornell/main.ts";let G=async e=>{let{canvas:n,pageState:t,gui:a}=e,r=navigator.gpu.getPreferredCanvasFormat(),i="bgra8unorm"===r?["bgra8unorm-storage"]:[],o=await navigator.gpu.requestAdapter();for(let s of i)if(!o.features.has(s))throw Error("sample requires ".concat(s,", but is not supported by the adapter"));let u=await o.requestDevice({requiredFeatures:i});if(!t.active)return;let c={renderer:"rasterizer",rotateCamera:!0};a.add(c,"renderer",["rasterizer","raytracer"]),a.add(c,"rotateCamera",!0);let d=window.devicePixelRatio;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let l=n.getContext("webgpu");l.configure({device:u,format:r,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.STORAGE_BINDING,alphaMode:"premultiplied"});let m=u.createTexture({label:"framebuffer",size:[n.width,n.height],format:"rgba16float",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.TEXTURE_BINDING}),f=new h(u),p=new g(u,f.quadBuffer),P=new v(u,p,f),G=new b(u,p,f,P,m),_=new x(u,p,P,m);requestAnimationFrame(function e(){if(!t.active)return;let a=l.getCurrentTexture(),r=u.createCommandEncoder();switch(p.update({rotateCamera:c.rotateCamera,aspect:n.width/n.height}),P.run(r),c.renderer){case"rasterizer":G.run(r);break;case"raytracer":_.run(r)}let i=new y(u,p,m,a);i.run(r),u.queue.submit([r.finish()]),requestAnimationFrame(e)})},_=()=>(0,i.Tl)({name:"Cornell box",description:"A classic Cornell box, using a lightmap generated using software ray-tracing.",gui:!0,init:G,sources:[{name:P.substring(19),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport radiosityWGSL from './radiosity.wgsl';\nimport rasterizerWGSL from './rasterizer.wgsl';\nimport raytracerWGSL from './raytracer.wgsl';\nimport tonemapperWGSL from './tonemapper.wgsl';\nimport commonWGSL from './common.wgsl';\nimport Scene from './scene';\nimport Common from './common';\nimport Radiosity from './radiosity';\nimport Rasterizer from './rasterizer';\nimport Tonemapper from './tonemapper';\nimport Raytracer from './raytracer';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n const requiredFeatures: GPUFeatureName[] =\n presentationFormat === 'bgra8unorm' ? ['bgra8unorm-storage'] : [];\n const adapter = await navigator.gpu.requestAdapter();\n for (const feature of requiredFeatures) {\n if (!adapter.features.has(feature)) {\n throw new Error(\n `sample requires ${feature}, but is not supported by the adapter`\n );\n }\n }\n const device = await adapter.requestDevice({ requiredFeatures });\n\n if (!pageState.active) return;\n\n const params: {\n renderer: 'rasterizer' | 'raytracer';\n rotateCamera: boolean;\n } = {\n renderer: 'rasterizer',\n rotateCamera: true,\n };\n\n gui.add(params, 'renderer', ['rasterizer', 'raytracer']);\n gui.add(params, 'rotateCamera', true);\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n context.configure({\n device,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.STORAGE_BINDING,\n alphaMode: 'premultiplied',\n });\n\n const framebuffer = device.createTexture({\n label: 'framebuffer',\n size: [canvas.width, canvas.height],\n format: 'rgba16float',\n usage:\n GPUTextureUsage.RENDER_ATTACHMENT |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.TEXTURE_BINDING,\n });\n\n const scene = new Scene(device);\n const common = new Common(device, scene.quadBuffer);\n const radiosity = new Radiosity(device, common, scene);\n const rasterizer = new Rasterizer(\n device,\n common,\n scene,\n radiosity,\n framebuffer\n );\n const raytracer = new Raytracer(device, common, radiosity, framebuffer);\n\n function frame() {\n if (!pageState.active) {\n // Sample is no longer the active page.\n return;\n }\n\n const canvasTexture = context.getCurrentTexture();\n const commandEncoder = device.createCommandEncoder();\n\n common.update({\n rotateCamera: params.rotateCamera,\n aspect: canvas.width / canvas.height,\n });\n radiosity.run(commandEncoder);\n\n switch (params.renderer) {\n case 'rasterizer': {\n rasterizer.run(commandEncoder);\n break;\n }\n case 'raytracer': {\n raytracer.run(commandEncoder);\n break;\n }\n }\n\n const tonemapper = new Tonemapper(\n device,\n common,\n framebuffer,\n canvasTexture\n );\n tonemapper.run(commandEncoder);\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst CornellBox: () => JSX.Element = () =>\n makeSample({\n name: 'Cornell box',\n description:\n 'A classic Cornell box, using a lightmap generated using software ray-tracing.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n Common.sourceInfo,\n Scene.sourceInfo,\n Radiosity.sourceInfo,\n Rasterizer.sourceInfo,\n Raytracer.sourceInfo,\n Tonemapper.sourceInfo,\n {\n name: './radiosity.wgsl',\n contents: radiosityWGSL,\n editable: true,\n },\n {\n name: './rasterizer.wgsl',\n contents: rasterizerWGSL,\n editable: true,\n },\n {\n name: './raytracer.wgsl',\n contents: raytracerWGSL,\n editable: true,\n },\n {\n name: './tonemapper.wgsl',\n contents: tonemapperWGSL,\n editable: true,\n },\n {\n name: './common.wgsl',\n contents: commonWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default CornellBox;\n"},g.sourceInfo,h.sourceInfo,v.sourceInfo,b.sourceInfo,x.sourceInfo,y.sourceInfo,{name:"./radiosity.wgsl",contents:o,editable:!0},{name:"./rasterizer.wgsl",contents:s,editable:!0},{name:"./raytracer.wgsl",contents:u,editable:!0},{name:"./tonemapper.wgsl",contents:c,editable:!0},{name:"./common.wgsl",contents:d,editable:!0}],filename:P});var S=_},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]); \ No newline at end of file diff --git a/_next/static/chunks/878.d6c6986090d24b0a.js b/_next/static/chunks/878.bf1bacaa90dd5ec7.js similarity index 66% rename from _next/static/chunks/878.d6c6986090d24b0a.js rename to _next/static/chunks/878.bf1bacaa90dd5ec7.js index a9efc779..63da8fd4 100644 --- a/_next/static/chunks/878.d6c6986090d24b0a.js +++ b/_next/static/chunks/878.bf1bacaa90dd5ec7.js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[878],{5671:function(e,t,n){"use strict";n.d(t,{Tl:function(){return m},hu:function(){return p}});var a=n(5893),i=n(9008),r=n.n(i),o=n(1163),s=n(7294),c=n(9147),l=n.n(c);n(7319);let u=e=>{let t=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:t,contents:i}=e;return{name:t,...function(e){let t;let i=null;{i=document.createElement("div");let r=n(4631);t=r(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(n){return(0,a.jsx)("div",{...n,children:(0,a.jsx)("div",{ref(n){i&&n&&(n.appendChild(i),t.setOption("value",e))}})})}}}(i)}}),e.sources),c=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let t=n(4376);return new t.GUI({autoPlace:!1})}},[]),m=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let t=n(2792);return new t}},[]),h=(0,o.useRouter)(),d=h.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,g]=(0,s.useState)(null),[v,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(d?x(d[1]):x(i[0].name),u&&c.current)for(c.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();p&&m.current&&(p.dom.style.position="absolute",p.showPanel(1),m.current.appendChild(p.dom));let n={active:!0},a=()=>{n.active=!1};try{let r=t.current;if(!r)throw Error("The canvas is not available");let o=e.init({canvas:r,pageState:n,gui:u,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(r(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),f?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(f)})]}):null]}),(0,a.jsxs)("div",{className:l().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,a.jsx)("canvas",{ref:t})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:l().sourceFileNav,children:(0,a.jsx)("ul",{children:i.map((e,t)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){x(e.name)},children:e.name})},t))})}),i.map((e,t)=>(0,a.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":v==e.name},t))]})]})},m=e=>(0,a.jsx)(u,{...e});function p(e,t){if(!e)throw Error(t)}},4655:function(e,t,n){"use strict";n.d(t,{Ax:function(){return r},MO:function(){return o},O$:function(){return a},v8:function(){return i},zS:function(){return s}});let a=40,i=0,r=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},3878:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return f}});var a=n(6416),i=n(5671),r=n(4655),o="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n\n@group(0) @binding(0) var uniforms : Uniforms;\n@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4f,\n @location(0) fragUV : vec2f,\n}\n\n@vertex\nfn vertex_main(\n @location(0) position : vec4f,\n @location(1) uv : vec2f\n) -> VertexOutput {\n return VertexOutput(uniforms.modelViewProjectionMatrix * position, uv);\n}\n\n@fragment\nfn fragment_main(@location(0) fragUV: vec2f) -> @location(0) vec4f {\n return textureSample(myTexture, mySampler, fragUV);\n}\n";let s={name:"src/sample/cameras/camera.ts".substring(19),contents:"// Note: The code in this file does not use the 'dst' output parameter of functions in the\n// 'wgpu-matrix' library, so produces many temporary vectors and matrices.\n// This is intentional, as this sample prefers readability over performance.\nimport { Mat4, Vec3, Vec4, mat4, vec3 } from 'wgpu-matrix';\nimport Input from './input';\n\n// Information about this file, used by the sample UI\nexport const cameraSourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n};\n\n// Common interface for camera implementations\nexport default interface Camera {\n // update updates the camera using the user-input and returns the view matrix.\n update(delta_time: number, input: Input): Mat4;\n\n // The camera matrix.\n // This is the inverse of the view matrix.\n matrix: Mat4;\n // Alias to column vector 0 of the camera matrix.\n right: Vec4;\n // Alias to column vector 1 of the camera matrix.\n up: Vec4;\n // Alias to column vector 2 of the camera matrix.\n back: Vec4;\n // Alias to column vector 3 of the camera matrix.\n position: Vec4;\n}\n\n// The common functionality between camera implementations\nclass CameraBase {\n // The camera matrix\n private matrix_ = new Float32Array([\n 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,\n ]);\n\n // The calculated view matrix\n private readonly view_ = mat4.create();\n\n // Aliases to column vectors of the matrix\n private right_ = new Float32Array(this.matrix_.buffer, 4 * 0, 4);\n private up_ = new Float32Array(this.matrix_.buffer, 4 * 4, 4);\n private back_ = new Float32Array(this.matrix_.buffer, 4 * 8, 4);\n private position_ = new Float32Array(this.matrix_.buffer, 4 * 12, 4);\n\n // Returns the camera matrix\n get matrix() {\n return this.matrix_;\n }\n // Assigns `mat` to the camera matrix\n set matrix(mat: Mat4) {\n mat4.copy(mat, this.matrix_);\n }\n\n // Returns the camera view matrix\n get view() {\n return this.view_;\n }\n // Assigns `mat` to the camera view\n set view(mat: Mat4) {\n mat4.copy(mat, this.view_);\n }\n\n // Returns column vector 0 of the camera matrix\n get right() {\n return this.right_;\n }\n // Assigns `vec` to the first 3 elements of column vector 0 of the camera matrix\n set right(vec: Vec3) {\n vec3.copy(vec, this.right_);\n }\n\n // Returns column vector 1 of the camera matrix\n get up() {\n return this.up_;\n }\n // Assigns `vec` to the first 3 elements of column vector 1 of the camera matrix\n set up(vec: Vec3) {\n vec3.copy(vec, this.up_);\n }\n\n // Returns column vector 2 of the camera matrix\n get back() {\n return this.back_;\n }\n // Assigns `vec` to the first 3 elements of column vector 2 of the camera matrix\n set back(vec: Vec3) {\n vec3.copy(vec, this.back_);\n }\n\n // Returns column vector 3 of the camera matrix\n get position() {\n return this.position_;\n }\n // Assigns `vec` to the first 3 elements of column vector 3 of the camera matrix\n set position(vec: Vec3) {\n vec3.copy(vec, this.position_);\n }\n}\n\n// WASDCamera is a camera implementation that behaves similar to first-person-shooter PC games.\nexport class WASDCamera extends CameraBase implements Camera {\n // The camera absolute pitch angle\n private pitch = 0;\n // The camera absolute yaw angle\n private yaw = 0;\n\n // The movement veloicty\n private readonly velocity_ = vec3.create();\n\n // Speed multiplier for camera movement\n movementSpeed = 10;\n\n // Speed multiplier for camera rotation\n rotationSpeed = 1;\n\n // Movement velocity drag coeffient [0 .. 1]\n // 0: Continues forever\n // 1: Instantly stops moving\n frictionCoefficient = 0.99;\n\n // Returns velocity vector\n get velocity() {\n return this.velocity_;\n }\n // Assigns `vec` to the velocity vector\n set velocity(vec: Vec3) {\n vec3.copy(vec, this.velocity_);\n }\n\n // Construtor\n constructor(options?: {\n // The initial position of the camera\n position?: Vec3;\n // The initial target of the camera\n target?: Vec3;\n }) {\n super();\n if (options && (options.position || options.target)) {\n const position = options.position ?? vec3.create(0, 0, -5);\n const target = options.target ?? vec3.create(0, 0, 0);\n const forward = vec3.normalize(vec3.sub(target, position));\n this.recalculateAngles(forward);\n this.position = position;\n }\n }\n\n // Returns the camera matrix\n get matrix() {\n return super.matrix;\n }\n\n // Assigns `mat` to the camera matrix, and recalcuates the camera angles\n set matrix(mat: Mat4) {\n super.matrix = mat;\n this.recalculateAngles(this.back);\n }\n\n update(deltaTime: number, input: Input): Mat4 {\n const sign = (positive: boolean, negative: boolean) =>\n (positive ? 1 : 0) - (negative ? 1 : 0);\n\n // Apply the delta rotation to the pitch and yaw angles\n this.yaw -= input.analog.x * deltaTime * this.rotationSpeed;\n this.pitch -= input.analog.y * deltaTime * this.rotationSpeed;\n\n // Wrap yaw between [0\xb0 .. 360\xb0], just to prevent large accumulation.\n this.yaw = mod(this.yaw, Math.PI * 2);\n // Clamp pitch between [-90\xb0 .. +90\xb0] to prevent somersaults.\n this.pitch = clamp(this.pitch, -Math.PI / 2, Math.PI / 2);\n\n // Save the current position, as we're about to rebuild the camera matrix.\n const position = vec3.copy(this.position);\n\n // Reconstruct the camera's rotation, and store into the camera matrix.\n super.matrix = mat4.rotateX(mat4.rotationY(this.yaw), this.pitch);\n\n // Calculate the new target velocity\n const digital = input.digital;\n const deltaRight = sign(digital.right, digital.left);\n const deltaUp = sign(digital.up, digital.down);\n const targetVelocity = vec3.create();\n const deltaBack = sign(digital.backward, digital.forward);\n vec3.addScaled(targetVelocity, this.right, deltaRight, targetVelocity);\n vec3.addScaled(targetVelocity, this.up, deltaUp, targetVelocity);\n vec3.addScaled(targetVelocity, this.back, deltaBack, targetVelocity);\n vec3.normalize(targetVelocity, targetVelocity);\n vec3.mulScalar(targetVelocity, this.movementSpeed, targetVelocity);\n\n // Mix new target velocity\n this.velocity = lerp(\n targetVelocity,\n this.velocity,\n Math.pow(1 - this.frictionCoefficient, deltaTime)\n );\n\n // Integrate velocity to calculate new position\n this.position = vec3.addScaled(position, this.velocity, deltaTime);\n\n // Invert the camera matrix to build the view matrix\n this.view = mat4.invert(this.matrix);\n return this.view;\n }\n\n // Recalculates the yaw and pitch values from a directional vector\n recalculateAngles(dir: Vec3) {\n this.yaw = Math.atan2(dir[0], dir[2]);\n this.pitch = -Math.asin(dir[1]);\n }\n}\n\n// ArcballCamera implements a basic orbiting camera around the world origin\nexport class ArcballCamera extends CameraBase implements Camera {\n // The camera distance from the target\n private distance = 0;\n\n // The current angular velocity\n private angularVelocity = 0;\n\n // The current rotation axis\n private axis_ = vec3.create();\n\n // Returns the rotation axis\n get axis() {\n return this.axis_;\n }\n // Assigns `vec` to the rotation axis\n set axis(vec: Vec3) {\n vec3.copy(vec, this.axis_);\n }\n\n // Speed multiplier for camera rotation\n rotationSpeed = 1;\n\n // Speed multiplier for camera zoom\n zoomSpeed = 0.1;\n\n // Rotation velocity drag coeffient [0 .. 1]\n // 0: Spins forever\n // 1: Instantly stops spinning\n frictionCoefficient = 0.999;\n\n // Construtor\n constructor(options?: {\n // The initial position of the camera\n position?: Vec3;\n }) {\n super();\n if (options && options.position) {\n this.position = options.position;\n this.distance = vec3.len(this.position);\n this.back = vec3.normalize(this.position);\n this.recalcuateRight();\n this.recalcuateUp();\n }\n }\n\n // Returns the camera matrix\n get matrix() {\n return super.matrix;\n }\n\n // Assigns `mat` to the camera matrix, and recalcuates the distance\n set matrix(mat: Mat4) {\n super.matrix = mat;\n this.distance = vec3.len(this.position);\n }\n\n update(deltaTime: number, input: Input): Mat4 {\n const epsilon = 0.0000001;\n\n if (input.analog.touching) {\n // Currently being dragged.\n this.angularVelocity = 0;\n } else {\n // Dampen any existing angular velocity\n this.angularVelocity *= Math.pow(1 - this.frictionCoefficient, deltaTime);\n }\n\n // Calculate the movement vector\n const movement = vec3.create();\n vec3.addScaled(movement, this.right, input.analog.x, movement);\n vec3.addScaled(movement, this.up, -input.analog.y, movement);\n\n // Cross the movement vector with the view direction to calculate the rotation axis x magnitude\n const crossProduct = vec3.cross(movement, this.back);\n\n // Calculate the magnitude of the drag\n const magnitude = vec3.len(crossProduct);\n\n if (magnitude > epsilon) {\n // Normalize the crossProduct to get the rotation axis\n this.axis = vec3.scale(crossProduct, 1 / magnitude);\n\n // Remember the current angular velocity. This is used when the touch is released for a fling.\n this.angularVelocity = magnitude * this.rotationSpeed;\n }\n\n // The rotation around this.axis to apply to the camera matrix this update\n const rotationAngle = this.angularVelocity * deltaTime;\n if (rotationAngle > epsilon) {\n // Rotate the matrix around axis\n // Note: The rotation is not done as a matrix-matrix multiply as the repeated multiplications\n // will quickly introduce substantial error into the matrix.\n this.back = vec3.normalize(rotate(this.back, this.axis, rotationAngle));\n this.recalcuateRight();\n this.recalcuateUp();\n }\n\n // recalculate `this.position` from `this.back` considering zoom\n if (input.analog.zoom !== 0) {\n this.distance *= 1 + input.analog.zoom * this.zoomSpeed;\n }\n this.position = vec3.scale(this.back, this.distance);\n\n // Invert the camera matrix to build the view matrix\n this.view = mat4.invert(this.matrix);\n return this.view;\n }\n\n // Assigns `this.right` with the cross product of `this.up` and `this.back`\n recalcuateRight() {\n this.right = vec3.normalize(vec3.cross(this.up, this.back));\n }\n\n // Assigns `this.up` with the cross product of `this.back` and `this.right`\n recalcuateUp() {\n this.up = vec3.normalize(vec3.cross(this.back, this.right));\n }\n}\n\n// Returns `x` clamped between [`min` .. `max`]\nfunction clamp(x: number, min: number, max: number): number {\n return Math.min(Math.max(x, min), max);\n}\n\n// Returns `x` float-modulo `div`\nfunction mod(x: number, div: number): number {\n return x - Math.floor(Math.abs(x) / div) * div * Math.sign(x);\n}\n\n// Returns `vec` rotated `angle` radians around `axis`\nfunction rotate(vec: Vec3, axis: Vec3, angle: number): Vec3 {\n return vec3.transformMat4Upper3x3(vec, mat4.rotation(axis, angle));\n}\n\n// Returns the linear interpolation between 'a' and 'b' using 's'\nfunction lerp(a: Vec3, b: Vec3, s: number): Vec3 {\n return vec3.addScaled(a, vec3.sub(b, a), s);\n}\n"};class c{get matrix(){return this.matrix_}set matrix(e){a._E.copy(e,this.matrix_)}get view(){return this.view_}set view(e){a._E.copy(e,this.view_)}get right(){return this.right_}set right(e){a.R3.copy(e,this.right_)}get up(){return this.up_}set up(e){a.R3.copy(e,this.up_)}get back(){return this.back_}set back(e){a.R3.copy(e,this.back_)}get position(){return this.position_}set position(e){a.R3.copy(e,this.position_)}constructor(){this.matrix_=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]),this.view_=a._E.create(),this.right_=new Float32Array(this.matrix_.buffer,0,4),this.up_=new Float32Array(this.matrix_.buffer,16,4),this.back_=new Float32Array(this.matrix_.buffer,32,4),this.position_=new Float32Array(this.matrix_.buffer,48,4)}}class l extends c{get velocity(){return this.velocity_}set velocity(e){a.R3.copy(e,this.velocity_)}get matrix(){return super.matrix}set matrix(e){super.matrix=e,this.recalculateAngles(this.back)}update(e,t){var n,i,r,o;let s=(e,t)=>(e?1:0)-(t?1:0);this.yaw-=t.analog.x*e*this.rotationSpeed,this.pitch-=t.analog.y*e*this.rotationSpeed,this.yaw=(n=this.yaw)-Math.floor(Math.abs(n)/(i=2*Math.PI))*i*Math.sign(n),this.pitch=Math.min(Math.max(this.pitch,-Math.PI/2),Math.PI/2);let c=a.R3.copy(this.position);super.matrix=a._E.rotateX(a._E.rotationY(this.yaw),this.pitch);let l=t.digital,u=s(l.right,l.left),m=s(l.up,l.down),p=a.R3.create(),h=s(l.backward,l.forward);return a.R3.addScaled(p,this.right,u,p),a.R3.addScaled(p,this.up,m,p),a.R3.addScaled(p,this.back,h,p),a.R3.normalize(p,p),a.R3.mulScalar(p,this.movementSpeed,p),this.velocity=(r=this.velocity,o=Math.pow(1-this.frictionCoefficient,e),a.R3.addScaled(p,a.R3.sub(r,p),o)),this.position=a.R3.addScaled(c,this.velocity,e),this.view=a._E.invert(this.matrix),this.view}recalculateAngles(e){this.yaw=Math.atan2(e[0],e[2]),this.pitch=-Math.asin(e[1])}constructor(e){if(super(),this.pitch=0,this.yaw=0,this.velocity_=a.R3.create(),this.movementSpeed=10,this.rotationSpeed=1,this.frictionCoefficient=.99,e&&(e.position||e.target)){var t,n;let i=null!==(t=e.position)&&void 0!==t?t:a.R3.create(0,0,-5),r=null!==(n=e.target)&&void 0!==n?n:a.R3.create(0,0,0),o=a.R3.normalize(a.R3.sub(r,i));this.recalculateAngles(o),this.position=i}}}class u extends c{get axis(){return this.axis_}set axis(e){a.R3.copy(e,this.axis_)}get matrix(){return super.matrix}set matrix(e){super.matrix=e,this.distance=a.R3.len(this.position)}update(e,t){var n,i;t.analog.touching?this.angularVelocity=0:this.angularVelocity*=Math.pow(1-this.frictionCoefficient,e);let r=a.R3.create();a.R3.addScaled(r,this.right,t.analog.x,r),a.R3.addScaled(r,this.up,-t.analog.y,r);let o=a.R3.cross(r,this.back),s=a.R3.len(o);s>1e-7&&(this.axis=a.R3.scale(o,1/s),this.angularVelocity=s*this.rotationSpeed);let c=this.angularVelocity*e;return c>1e-7&&(this.back=a.R3.normalize((n=this.back,i=this.axis,a.R3.transformMat4Upper3x3(n,a._E.rotation(i,c)))),this.recalcuateRight(),this.recalcuateUp()),0!==t.analog.zoom&&(this.distance*=1+t.analog.zoom*this.zoomSpeed),this.position=a.R3.scale(this.back,this.distance),this.view=a._E.invert(this.matrix),this.view}recalcuateRight(){this.right=a.R3.normalize(a.R3.cross(this.up,this.back))}recalcuateUp(){this.up=a.R3.normalize(a.R3.cross(this.back,this.right))}constructor(e){super(),this.distance=0,this.angularVelocity=0,this.axis_=a.R3.create(),this.rotationSpeed=1,this.zoomSpeed=.1,this.frictionCoefficient=.999,e&&e.position&&(this.position=e.position,this.distance=a.R3.len(this.position),this.back=a.R3.normalize(this.position),this.recalcuateRight(),this.recalcuateUp())}}let m={name:"src/sample/cameras/input.ts".substring(19),contents:"// Information about this file, used by the sample UI\nexport const inputSourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n};\n\n// Input holds as snapshot of input state\nexport default interface Input {\n // Digital input (e.g keyboard state)\n readonly digital: {\n readonly forward: boolean;\n readonly backward: boolean;\n readonly left: boolean;\n readonly right: boolean;\n readonly up: boolean;\n readonly down: boolean;\n };\n // Analog input (e.g mouse, touchscreen)\n readonly analog: {\n readonly x: number;\n readonly y: number;\n readonly zoom: number;\n readonly touching: boolean;\n };\n}\n\n// InputHandler is a function that when called, returns the current Input state.\nexport type InputHandler = () => Input;\n\n// createInputHandler returns an InputHandler by attaching event handlers to the window.\nexport function createInputHandler(window: Window): InputHandler {\n const digital = {\n forward: false,\n backward: false,\n left: false,\n right: false,\n up: false,\n down: false,\n };\n const analog = {\n x: 0,\n y: 0,\n zoom: 0,\n };\n let mouseDown = false;\n\n const setDigital = (e: KeyboardEvent, value: boolean) => {\n switch (e.code) {\n case 'KeyW':\n digital.forward = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'KeyS':\n digital.backward = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'KeyA':\n digital.left = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'KeyD':\n digital.right = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'Space':\n digital.up = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'ShiftLeft':\n case 'ControlLeft':\n case 'KeyC':\n digital.down = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n }\n };\n\n window.addEventListener('keydown', (e) => setDigital(e, true));\n window.addEventListener('keyup', (e) => setDigital(e, false));\n window.addEventListener('mousedown', () => {\n mouseDown = true;\n });\n window.addEventListener('mouseup', () => {\n mouseDown = false;\n });\n window.addEventListener('mousemove', (e) => {\n mouseDown = (e.buttons & 1) !== 0;\n if (mouseDown) {\n analog.x += e.movementX;\n analog.y += e.movementY;\n }\n });\n window.addEventListener(\n 'wheel',\n (e) => {\n mouseDown = (e.buttons & 1) !== 0;\n if (mouseDown) {\n // The scroll value varies substantially between user agents / browsers.\n // Just use the sign.\n analog.zoom += Math.sign(e.deltaY);\n e.preventDefault();\n e.stopPropagation();\n }\n },\n { passive: false }\n );\n\n return () => {\n const out = {\n digital,\n analog: {\n x: analog.x,\n y: analog.y,\n zoom: analog.zoom,\n touching: mouseDown,\n },\n };\n // Clear the analog values, as these accumulate.\n analog.x = 0;\n analog.y = 0;\n analog.zoom = 0;\n return out;\n };\n}\n"};var p="src/sample/cameras/main.ts";let h=async e=>{let t,{canvas:i,pageState:s,gui:c}=e;if(!s.active)return;let m=function(e){let t={forward:!1,backward:!1,left:!1,right:!1,up:!1,down:!1},n={x:0,y:0,zoom:0},a=!1,i=(e,n)=>{switch(e.code){case"KeyW":t.forward=n,e.preventDefault(),e.stopPropagation();break;case"KeyS":t.backward=n,e.preventDefault(),e.stopPropagation();break;case"KeyA":t.left=n,e.preventDefault(),e.stopPropagation();break;case"KeyD":t.right=n,e.preventDefault(),e.stopPropagation();break;case"Space":t.up=n,e.preventDefault(),e.stopPropagation();break;case"ShiftLeft":case"ControlLeft":case"KeyC":t.down=n,e.preventDefault(),e.stopPropagation()}};return e.addEventListener("keydown",e=>i(e,!0)),e.addEventListener("keyup",e=>i(e,!1)),e.addEventListener("mousedown",()=>{a=!0}),e.addEventListener("mouseup",()=>{a=!1}),e.addEventListener("mousemove",e=>{(a=(1&e.buttons)!=0)&&(n.x+=e.movementX,n.y+=e.movementY)}),e.addEventListener("wheel",e=>{(a=(1&e.buttons)!=0)&&(n.zoom+=Math.sign(e.deltaY),e.preventDefault(),e.stopPropagation())},{passive:!1}),()=>{let e={digital:t,analog:{x:n.x,y:n.y,zoom:n.zoom,touching:a}};return n.x=0,n.y=0,n.zoom=0,e}}(window),p=a.R3.create(3,2,5),h={arcball:new u({position:p}),WASD:new l({position:p})},d={type:"arcball"},f=d.type;c.add(d,"type",["arcball","WASD"]).onChange(()=>{let e=d.type;h[e].matrix=h[f].matrix,f=e});let g=await navigator.gpu.requestAdapter(),v=await g.requestDevice(),x=i.getContext("webgpu"),b=window.devicePixelRatio||1;i.width=i.clientWidth*b,i.height=i.clientHeight*b;let w=navigator.gpu.getPreferredCanvasFormat();x.configure({device:v,format:w,alphaMode:"premultiplied"});let y=v.createBuffer({size:r.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(y.getMappedRange()).set(r.zS),y.unmap();let _=v.createRenderPipeline({layout:"auto",vertex:{module:v.createShaderModule({code:o}),entryPoint:"vertex_main",buffers:[{arrayStride:r.O$,attributes:[{shaderLocation:0,offset:r.v8,format:"float32x4"},{shaderLocation:1,offset:r.Ax,format:"float32x2"}]}]},fragment:{module:v.createShaderModule({code:o}),entryPoint:"fragment_main",targets:[{format:w}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),S=v.createTexture({size:[i.width,i.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),C=v.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let R=await fetch(new n.U(n(5685)).toString()),T=await createImageBitmap(await R.blob());t=v.createTexture({size:[T.width,T.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),v.queue.copyExternalImageToTexture({source:T},{texture:t},[T.width,T.height])}let P=v.createSampler({magFilter:"linear",minFilter:"linear"}),A=v.createBindGroup({layout:_.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:C}},{binding:1,resource:P},{binding:2,resource:t.createView()}]}),V={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:S.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},M=i.width/i.height,E=a._E.perspective(2*Math.PI/5,M,1,100),k=a._E.create(),U=Date.now();requestAnimationFrame(function e(){let t=Date.now(),n=(t-U)/1e3;if(U=t,!s.active)return;let i=function(e){let t=h[d.type],n=t.update(e,m());return a._E.multiply(E,n,k),k}(n);v.queue.writeBuffer(C,0,i.buffer,i.byteOffset,i.byteLength),V.colorAttachments[0].view=x.getCurrentTexture().createView();let o=v.createCommandEncoder(),c=o.beginRenderPass(V);c.setPipeline(_),c.setBindGroup(0,A),c.setVertexBuffer(0,y),c.draw(r.MO),c.end(),v.queue.submit([o.finish()]),requestAnimationFrame(e)})},d=()=>(0,i.Tl)({name:"Cameras",description:"This example provides example camera implementations",gui:!0,init:h,sources:[{name:p.substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\nimport cubeWGSL from './cube.wgsl';\nimport { ArcballCamera, WASDCamera, cameraSourceInfo } from './camera';\nimport { createInputHandler, inputSourceInfo } from './input';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n if (!pageState.active) {\n return;\n }\n\n // The input handler\n const inputHandler = createInputHandler(window);\n\n // The camera types\n const initialCameraPosition = vec3.create(3, 2, 5);\n const cameras = {\n arcball: new ArcballCamera({ position: initialCameraPosition }),\n WASD: new WASDCamera({ position: initialCameraPosition }),\n };\n\n // GUI parameters\n const params: { type: 'arcball' | 'WASD' } = {\n type: 'arcball',\n };\n\n // Callback handler for camera mode\n let oldCameraType = params.type;\n gui.add(params, 'type', ['arcball', 'WASD']).onChange(() => {\n // Copy the camera matrix from old to new\n const newCameraType = params.type;\n cameras[newCameraType].matrix = cameras[oldCameraType].matrix;\n oldCameraType = newCameraType;\n });\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio || 1;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: cubeWGSL,\n }),\n entryPoint: 'vertex_main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: cubeWGSL,\n }),\n entryPoint: 'fragment_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the image and upload it into a GPUTexture.\n let cubeTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/Di-3d.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n cubeTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubeTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getModelViewProjectionMatrix(deltaTime: number) {\n const camera = cameras[params.type];\n const viewMatrix = camera.update(deltaTime, inputHandler());\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n return modelViewProjectionMatrix as Float32Array;\n }\n\n let lastFrameMS = Date.now();\n\n function frame() {\n const now = Date.now();\n const deltaTime = (now - lastFrameMS) / 1000;\n lastFrameMS = now;\n\n if (!pageState.active) {\n // Sample is no longer the active page.\n return;\n }\n\n const modelViewProjection = getModelViewProjectionMatrix(deltaTime);\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjection.buffer,\n modelViewProjection.byteOffset,\n modelViewProjection.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst TexturedCube: () => JSX.Element = () =>\n makeSample({\n name: 'Cameras',\n description: 'This example provides example camera implementations',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n cameraSourceInfo,\n inputSourceInfo,\n {\n name: '../../shaders/cube.wgsl',\n contents: cubeWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default TexturedCube;\n"},s,m,{name:"../../shaders/cube.wgsl",contents:o,editable:!0},{name:"../../meshes/cube.ts",contents:n(2448).Z}],filename:p});var f=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,t){"use strict";t.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},5685:function(e,t,n){"use strict";e.exports=n.p+"static/assets/img/Di-3d.ba319100a0ec2120.png"}}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[878],{5671:function(e,t,n){"use strict";n.d(t,{Tl:function(){return m},hu:function(){return p}});var a=n(5893),i=n(9008),r=n.n(i),o=n(1163),s=n(7294),c=n(9147),l=n.n(c);n(7319);let u=e=>{let t=(0,s.useRef)(null),i=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:t,contents:i}=e;return{name:t,...function(e){let t;let i=null;{i=document.createElement("div");let r=n(4631);t=r(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(n){return(0,a.jsx)("div",{...n,children:(0,a.jsx)("div",{ref(n){i&&n&&(n.appendChild(i),t.setOption("value",e))}})})}}}(i)}}),e.sources),c=(0,s.useRef)(null),u=(0,s.useMemo)(()=>{if(e.gui){let t=n(4376);return new t.GUI({autoPlace:!1})}},[]),m=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let t=n(2792);return new t}},[]),h=(0,o.useRouter)(),d=h.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,g]=(0,s.useState)(null),[v,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(d?x(d[1]):x(i[0].name),u&&c.current)for(c.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();p&&m.current&&(p.dom.style.position="absolute",p.showPanel(1),m.current.appendChild(p.dom));let n={active:!0},a=()=>{n.active=!1};try{let r=t.current;if(!r)throw Error("The canvas is not available");let o=e.init({canvas:r,pageState:n,gui:u,stats:p});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(s){console.error(s),g(s)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(r(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),f?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(f)})]}):null]}),(0,a.jsxs)("div",{className:l().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,a.jsx)("canvas",{ref:t})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:l().sourceFileNav,children:(0,a.jsx)("ul",{children:i.map((e,t)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){x(e.name)},children:e.name})},t))})}),i.map((e,t)=>(0,a.jsx)(e.Container,{className:l().sourceFileContainer,"data-active":v==e.name},t))]})]})},m=e=>(0,a.jsx)(u,{...e});function p(e,t){if(!e)throw Error(t)}},4655:function(e,t,n){"use strict";n.d(t,{Ax:function(){return r},MO:function(){return o},O$:function(){return a},v8:function(){return i},zS:function(){return s}});let a=40,i=0,r=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},3878:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return f}});var a=n(6416),i=n(5671),r=n(4655),o="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n\n@group(0) @binding(0) var uniforms : Uniforms;\n@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4f,\n @location(0) fragUV : vec2f,\n}\n\n@vertex\nfn vertex_main(\n @location(0) position : vec4f,\n @location(1) uv : vec2f\n) -> VertexOutput {\n return VertexOutput(uniforms.modelViewProjectionMatrix * position, uv);\n}\n\n@fragment\nfn fragment_main(@location(0) fragUV: vec2f) -> @location(0) vec4f {\n return textureSample(myTexture, mySampler, fragUV);\n}\n";let s={name:"src/sample/cameras/camera.ts".substring(19),contents:"// Note: The code in this file does not use the 'dst' output parameter of functions in the\n// 'wgpu-matrix' library, so produces many temporary vectors and matrices.\n// This is intentional, as this sample prefers readability over performance.\nimport { Mat4, Vec3, Vec4, mat4, vec3 } from 'wgpu-matrix';\nimport Input from './input';\n\n// Information about this file, used by the sample UI\nexport const cameraSourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n};\n\n// Common interface for camera implementations\nexport default interface Camera {\n // update updates the camera using the user-input and returns the view matrix.\n update(delta_time: number, input: Input): Mat4;\n\n // The camera matrix.\n // This is the inverse of the view matrix.\n matrix: Mat4;\n // Alias to column vector 0 of the camera matrix.\n right: Vec4;\n // Alias to column vector 1 of the camera matrix.\n up: Vec4;\n // Alias to column vector 2 of the camera matrix.\n back: Vec4;\n // Alias to column vector 3 of the camera matrix.\n position: Vec4;\n}\n\n// The common functionality between camera implementations\nclass CameraBase {\n // The camera matrix\n private matrix_ = new Float32Array([\n 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,\n ]);\n\n // The calculated view matrix\n private readonly view_ = mat4.create();\n\n // Aliases to column vectors of the matrix\n private right_ = new Float32Array(this.matrix_.buffer, 4 * 0, 4);\n private up_ = new Float32Array(this.matrix_.buffer, 4 * 4, 4);\n private back_ = new Float32Array(this.matrix_.buffer, 4 * 8, 4);\n private position_ = new Float32Array(this.matrix_.buffer, 4 * 12, 4);\n\n // Returns the camera matrix\n get matrix() {\n return this.matrix_;\n }\n // Assigns `mat` to the camera matrix\n set matrix(mat: Mat4) {\n mat4.copy(mat, this.matrix_);\n }\n\n // Returns the camera view matrix\n get view() {\n return this.view_;\n }\n // Assigns `mat` to the camera view\n set view(mat: Mat4) {\n mat4.copy(mat, this.view_);\n }\n\n // Returns column vector 0 of the camera matrix\n get right() {\n return this.right_;\n }\n // Assigns `vec` to the first 3 elements of column vector 0 of the camera matrix\n set right(vec: Vec3) {\n vec3.copy(vec, this.right_);\n }\n\n // Returns column vector 1 of the camera matrix\n get up() {\n return this.up_;\n }\n // Assigns `vec` to the first 3 elements of column vector 1 of the camera matrix\n set up(vec: Vec3) {\n vec3.copy(vec, this.up_);\n }\n\n // Returns column vector 2 of the camera matrix\n get back() {\n return this.back_;\n }\n // Assigns `vec` to the first 3 elements of column vector 2 of the camera matrix\n set back(vec: Vec3) {\n vec3.copy(vec, this.back_);\n }\n\n // Returns column vector 3 of the camera matrix\n get position() {\n return this.position_;\n }\n // Assigns `vec` to the first 3 elements of column vector 3 of the camera matrix\n set position(vec: Vec3) {\n vec3.copy(vec, this.position_);\n }\n}\n\n// WASDCamera is a camera implementation that behaves similar to first-person-shooter PC games.\nexport class WASDCamera extends CameraBase implements Camera {\n // The camera absolute pitch angle\n private pitch = 0;\n // The camera absolute yaw angle\n private yaw = 0;\n\n // The movement veloicty\n private readonly velocity_ = vec3.create();\n\n // Speed multiplier for camera movement\n movementSpeed = 10;\n\n // Speed multiplier for camera rotation\n rotationSpeed = 1;\n\n // Movement velocity drag coeffient [0 .. 1]\n // 0: Continues forever\n // 1: Instantly stops moving\n frictionCoefficient = 0.99;\n\n // Returns velocity vector\n get velocity() {\n return this.velocity_;\n }\n // Assigns `vec` to the velocity vector\n set velocity(vec: Vec3) {\n vec3.copy(vec, this.velocity_);\n }\n\n // Construtor\n constructor(options?: {\n // The initial position of the camera\n position?: Vec3;\n // The initial target of the camera\n target?: Vec3;\n }) {\n super();\n if (options && (options.position || options.target)) {\n const position = options.position ?? vec3.create(0, 0, -5);\n const target = options.target ?? vec3.create(0, 0, 0);\n const forward = vec3.normalize(vec3.sub(target, position));\n this.recalculateAngles(forward);\n this.position = position;\n }\n }\n\n // Returns the camera matrix\n get matrix() {\n return super.matrix;\n }\n\n // Assigns `mat` to the camera matrix, and recalcuates the camera angles\n set matrix(mat: Mat4) {\n super.matrix = mat;\n this.recalculateAngles(this.back);\n }\n\n update(deltaTime: number, input: Input): Mat4 {\n const sign = (positive: boolean, negative: boolean) =>\n (positive ? 1 : 0) - (negative ? 1 : 0);\n\n // Apply the delta rotation to the pitch and yaw angles\n this.yaw -= input.analog.x * deltaTime * this.rotationSpeed;\n this.pitch -= input.analog.y * deltaTime * this.rotationSpeed;\n\n // Wrap yaw between [0\xb0 .. 360\xb0], just to prevent large accumulation.\n this.yaw = mod(this.yaw, Math.PI * 2);\n // Clamp pitch between [-90\xb0 .. +90\xb0] to prevent somersaults.\n this.pitch = clamp(this.pitch, -Math.PI / 2, Math.PI / 2);\n\n // Save the current position, as we're about to rebuild the camera matrix.\n const position = vec3.copy(this.position);\n\n // Reconstruct the camera's rotation, and store into the camera matrix.\n super.matrix = mat4.rotateX(mat4.rotationY(this.yaw), this.pitch);\n\n // Calculate the new target velocity\n const digital = input.digital;\n const deltaRight = sign(digital.right, digital.left);\n const deltaUp = sign(digital.up, digital.down);\n const targetVelocity = vec3.create();\n const deltaBack = sign(digital.backward, digital.forward);\n vec3.addScaled(targetVelocity, this.right, deltaRight, targetVelocity);\n vec3.addScaled(targetVelocity, this.up, deltaUp, targetVelocity);\n vec3.addScaled(targetVelocity, this.back, deltaBack, targetVelocity);\n vec3.normalize(targetVelocity, targetVelocity);\n vec3.mulScalar(targetVelocity, this.movementSpeed, targetVelocity);\n\n // Mix new target velocity\n this.velocity = lerp(\n targetVelocity,\n this.velocity,\n Math.pow(1 - this.frictionCoefficient, deltaTime)\n );\n\n // Integrate velocity to calculate new position\n this.position = vec3.addScaled(position, this.velocity, deltaTime);\n\n // Invert the camera matrix to build the view matrix\n this.view = mat4.invert(this.matrix);\n return this.view;\n }\n\n // Recalculates the yaw and pitch values from a directional vector\n recalculateAngles(dir: Vec3) {\n this.yaw = Math.atan2(dir[0], dir[2]);\n this.pitch = -Math.asin(dir[1]);\n }\n}\n\n// ArcballCamera implements a basic orbiting camera around the world origin\nexport class ArcballCamera extends CameraBase implements Camera {\n // The camera distance from the target\n private distance = 0;\n\n // The current angular velocity\n private angularVelocity = 0;\n\n // The current rotation axis\n private axis_ = vec3.create();\n\n // Returns the rotation axis\n get axis() {\n return this.axis_;\n }\n // Assigns `vec` to the rotation axis\n set axis(vec: Vec3) {\n vec3.copy(vec, this.axis_);\n }\n\n // Speed multiplier for camera rotation\n rotationSpeed = 1;\n\n // Speed multiplier for camera zoom\n zoomSpeed = 0.1;\n\n // Rotation velocity drag coeffient [0 .. 1]\n // 0: Spins forever\n // 1: Instantly stops spinning\n frictionCoefficient = 0.999;\n\n // Construtor\n constructor(options?: {\n // The initial position of the camera\n position?: Vec3;\n }) {\n super();\n if (options && options.position) {\n this.position = options.position;\n this.distance = vec3.len(this.position);\n this.back = vec3.normalize(this.position);\n this.recalcuateRight();\n this.recalcuateUp();\n }\n }\n\n // Returns the camera matrix\n get matrix() {\n return super.matrix;\n }\n\n // Assigns `mat` to the camera matrix, and recalcuates the distance\n set matrix(mat: Mat4) {\n super.matrix = mat;\n this.distance = vec3.len(this.position);\n }\n\n update(deltaTime: number, input: Input): Mat4 {\n const epsilon = 0.0000001;\n\n if (input.analog.touching) {\n // Currently being dragged.\n this.angularVelocity = 0;\n } else {\n // Dampen any existing angular velocity\n this.angularVelocity *= Math.pow(1 - this.frictionCoefficient, deltaTime);\n }\n\n // Calculate the movement vector\n const movement = vec3.create();\n vec3.addScaled(movement, this.right, input.analog.x, movement);\n vec3.addScaled(movement, this.up, -input.analog.y, movement);\n\n // Cross the movement vector with the view direction to calculate the rotation axis x magnitude\n const crossProduct = vec3.cross(movement, this.back);\n\n // Calculate the magnitude of the drag\n const magnitude = vec3.len(crossProduct);\n\n if (magnitude > epsilon) {\n // Normalize the crossProduct to get the rotation axis\n this.axis = vec3.scale(crossProduct, 1 / magnitude);\n\n // Remember the current angular velocity. This is used when the touch is released for a fling.\n this.angularVelocity = magnitude * this.rotationSpeed;\n }\n\n // The rotation around this.axis to apply to the camera matrix this update\n const rotationAngle = this.angularVelocity * deltaTime;\n if (rotationAngle > epsilon) {\n // Rotate the matrix around axis\n // Note: The rotation is not done as a matrix-matrix multiply as the repeated multiplications\n // will quickly introduce substantial error into the matrix.\n this.back = vec3.normalize(rotate(this.back, this.axis, rotationAngle));\n this.recalcuateRight();\n this.recalcuateUp();\n }\n\n // recalculate `this.position` from `this.back` considering zoom\n if (input.analog.zoom !== 0) {\n this.distance *= 1 + input.analog.zoom * this.zoomSpeed;\n }\n this.position = vec3.scale(this.back, this.distance);\n\n // Invert the camera matrix to build the view matrix\n this.view = mat4.invert(this.matrix);\n return this.view;\n }\n\n // Assigns `this.right` with the cross product of `this.up` and `this.back`\n recalcuateRight() {\n this.right = vec3.normalize(vec3.cross(this.up, this.back));\n }\n\n // Assigns `this.up` with the cross product of `this.back` and `this.right`\n recalcuateUp() {\n this.up = vec3.normalize(vec3.cross(this.back, this.right));\n }\n}\n\n// Returns `x` clamped between [`min` .. `max`]\nfunction clamp(x: number, min: number, max: number): number {\n return Math.min(Math.max(x, min), max);\n}\n\n// Returns `x` float-modulo `div`\nfunction mod(x: number, div: number): number {\n return x - Math.floor(Math.abs(x) / div) * div * Math.sign(x);\n}\n\n// Returns `vec` rotated `angle` radians around `axis`\nfunction rotate(vec: Vec3, axis: Vec3, angle: number): Vec3 {\n return vec3.transformMat4Upper3x3(vec, mat4.rotation(axis, angle));\n}\n\n// Returns the linear interpolation between 'a' and 'b' using 's'\nfunction lerp(a: Vec3, b: Vec3, s: number): Vec3 {\n return vec3.addScaled(a, vec3.sub(b, a), s);\n}\n"};class c{get matrix(){return this.matrix_}set matrix(e){a._E.copy(e,this.matrix_)}get view(){return this.view_}set view(e){a._E.copy(e,this.view_)}get right(){return this.right_}set right(e){a.R3.copy(e,this.right_)}get up(){return this.up_}set up(e){a.R3.copy(e,this.up_)}get back(){return this.back_}set back(e){a.R3.copy(e,this.back_)}get position(){return this.position_}set position(e){a.R3.copy(e,this.position_)}constructor(){this.matrix_=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]),this.view_=a._E.create(),this.right_=new Float32Array(this.matrix_.buffer,0,4),this.up_=new Float32Array(this.matrix_.buffer,16,4),this.back_=new Float32Array(this.matrix_.buffer,32,4),this.position_=new Float32Array(this.matrix_.buffer,48,4)}}class l extends c{get velocity(){return this.velocity_}set velocity(e){a.R3.copy(e,this.velocity_)}get matrix(){return super.matrix}set matrix(e){super.matrix=e,this.recalculateAngles(this.back)}update(e,t){var n,i,r,o;let s=(e,t)=>(e?1:0)-(t?1:0);this.yaw-=t.analog.x*e*this.rotationSpeed,this.pitch-=t.analog.y*e*this.rotationSpeed,this.yaw=(n=this.yaw)-Math.floor(Math.abs(n)/(i=2*Math.PI))*i*Math.sign(n),this.pitch=Math.min(Math.max(this.pitch,-Math.PI/2),Math.PI/2);let c=a.R3.copy(this.position);super.matrix=a._E.rotateX(a._E.rotationY(this.yaw),this.pitch);let l=t.digital,u=s(l.right,l.left),m=s(l.up,l.down),p=a.R3.create(),h=s(l.backward,l.forward);return a.R3.addScaled(p,this.right,u,p),a.R3.addScaled(p,this.up,m,p),a.R3.addScaled(p,this.back,h,p),a.R3.normalize(p,p),a.R3.mulScalar(p,this.movementSpeed,p),this.velocity=(r=this.velocity,o=Math.pow(1-this.frictionCoefficient,e),a.R3.addScaled(p,a.R3.sub(r,p),o)),this.position=a.R3.addScaled(c,this.velocity,e),this.view=a._E.invert(this.matrix),this.view}recalculateAngles(e){this.yaw=Math.atan2(e[0],e[2]),this.pitch=-Math.asin(e[1])}constructor(e){if(super(),this.pitch=0,this.yaw=0,this.velocity_=a.R3.create(),this.movementSpeed=10,this.rotationSpeed=1,this.frictionCoefficient=.99,e&&(e.position||e.target)){var t,n;let i=null!==(t=e.position)&&void 0!==t?t:a.R3.create(0,0,-5),r=null!==(n=e.target)&&void 0!==n?n:a.R3.create(0,0,0),o=a.R3.normalize(a.R3.sub(r,i));this.recalculateAngles(o),this.position=i}}}class u extends c{get axis(){return this.axis_}set axis(e){a.R3.copy(e,this.axis_)}get matrix(){return super.matrix}set matrix(e){super.matrix=e,this.distance=a.R3.len(this.position)}update(e,t){var n,i;t.analog.touching?this.angularVelocity=0:this.angularVelocity*=Math.pow(1-this.frictionCoefficient,e);let r=a.R3.create();a.R3.addScaled(r,this.right,t.analog.x,r),a.R3.addScaled(r,this.up,-t.analog.y,r);let o=a.R3.cross(r,this.back),s=a.R3.len(o);s>1e-7&&(this.axis=a.R3.scale(o,1/s),this.angularVelocity=s*this.rotationSpeed);let c=this.angularVelocity*e;return c>1e-7&&(this.back=a.R3.normalize((n=this.back,i=this.axis,a.R3.transformMat4Upper3x3(n,a._E.rotation(i,c)))),this.recalcuateRight(),this.recalcuateUp()),0!==t.analog.zoom&&(this.distance*=1+t.analog.zoom*this.zoomSpeed),this.position=a.R3.scale(this.back,this.distance),this.view=a._E.invert(this.matrix),this.view}recalcuateRight(){this.right=a.R3.normalize(a.R3.cross(this.up,this.back))}recalcuateUp(){this.up=a.R3.normalize(a.R3.cross(this.back,this.right))}constructor(e){super(),this.distance=0,this.angularVelocity=0,this.axis_=a.R3.create(),this.rotationSpeed=1,this.zoomSpeed=.1,this.frictionCoefficient=.999,e&&e.position&&(this.position=e.position,this.distance=a.R3.len(this.position),this.back=a.R3.normalize(this.position),this.recalcuateRight(),this.recalcuateUp())}}let m={name:"src/sample/cameras/input.ts".substring(19),contents:"// Information about this file, used by the sample UI\nexport const inputSourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n};\n\n// Input holds as snapshot of input state\nexport default interface Input {\n // Digital input (e.g keyboard state)\n readonly digital: {\n readonly forward: boolean;\n readonly backward: boolean;\n readonly left: boolean;\n readonly right: boolean;\n readonly up: boolean;\n readonly down: boolean;\n };\n // Analog input (e.g mouse, touchscreen)\n readonly analog: {\n readonly x: number;\n readonly y: number;\n readonly zoom: number;\n readonly touching: boolean;\n };\n}\n\n// InputHandler is a function that when called, returns the current Input state.\nexport type InputHandler = () => Input;\n\n// createInputHandler returns an InputHandler by attaching event handlers to the window.\nexport function createInputHandler(window: Window): InputHandler {\n const digital = {\n forward: false,\n backward: false,\n left: false,\n right: false,\n up: false,\n down: false,\n };\n const analog = {\n x: 0,\n y: 0,\n zoom: 0,\n };\n let mouseDown = false;\n\n const setDigital = (e: KeyboardEvent, value: boolean) => {\n switch (e.code) {\n case 'KeyW':\n digital.forward = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'KeyS':\n digital.backward = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'KeyA':\n digital.left = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'KeyD':\n digital.right = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'Space':\n digital.up = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n case 'ShiftLeft':\n case 'ControlLeft':\n case 'KeyC':\n digital.down = value;\n e.preventDefault();\n e.stopPropagation();\n break;\n }\n };\n\n window.addEventListener('keydown', (e) => setDigital(e, true));\n window.addEventListener('keyup', (e) => setDigital(e, false));\n window.addEventListener('mousedown', () => {\n mouseDown = true;\n });\n window.addEventListener('mouseup', () => {\n mouseDown = false;\n });\n window.addEventListener('mousemove', (e) => {\n mouseDown = (e.buttons & 1) !== 0;\n if (mouseDown) {\n analog.x += e.movementX;\n analog.y += e.movementY;\n }\n });\n window.addEventListener(\n 'wheel',\n (e) => {\n mouseDown = (e.buttons & 1) !== 0;\n if (mouseDown) {\n // The scroll value varies substantially between user agents / browsers.\n // Just use the sign.\n analog.zoom += Math.sign(e.deltaY);\n e.preventDefault();\n e.stopPropagation();\n }\n },\n { passive: false }\n );\n\n return () => {\n const out = {\n digital,\n analog: {\n x: analog.x,\n y: analog.y,\n zoom: analog.zoom,\n touching: mouseDown,\n },\n };\n // Clear the analog values, as these accumulate.\n analog.x = 0;\n analog.y = 0;\n analog.zoom = 0;\n return out;\n };\n}\n"};var p="src/sample/cameras/main.ts";let h=async e=>{let t,{canvas:i,pageState:s,gui:c}=e;if(!s.active)return;let m=function(e){let t={forward:!1,backward:!1,left:!1,right:!1,up:!1,down:!1},n={x:0,y:0,zoom:0},a=!1,i=(e,n)=>{switch(e.code){case"KeyW":t.forward=n,e.preventDefault(),e.stopPropagation();break;case"KeyS":t.backward=n,e.preventDefault(),e.stopPropagation();break;case"KeyA":t.left=n,e.preventDefault(),e.stopPropagation();break;case"KeyD":t.right=n,e.preventDefault(),e.stopPropagation();break;case"Space":t.up=n,e.preventDefault(),e.stopPropagation();break;case"ShiftLeft":case"ControlLeft":case"KeyC":t.down=n,e.preventDefault(),e.stopPropagation()}};return e.addEventListener("keydown",e=>i(e,!0)),e.addEventListener("keyup",e=>i(e,!1)),e.addEventListener("mousedown",()=>{a=!0}),e.addEventListener("mouseup",()=>{a=!1}),e.addEventListener("mousemove",e=>{(a=(1&e.buttons)!=0)&&(n.x+=e.movementX,n.y+=e.movementY)}),e.addEventListener("wheel",e=>{(a=(1&e.buttons)!=0)&&(n.zoom+=Math.sign(e.deltaY),e.preventDefault(),e.stopPropagation())},{passive:!1}),()=>{let e={digital:t,analog:{x:n.x,y:n.y,zoom:n.zoom,touching:a}};return n.x=0,n.y=0,n.zoom=0,e}}(window),p=a.R3.create(3,2,5),h={arcball:new u({position:p}),WASD:new l({position:p})},d={type:"arcball"},f=d.type;c.add(d,"type",["arcball","WASD"]).onChange(()=>{let e=d.type;h[e].matrix=h[f].matrix,f=e});let g=await navigator.gpu.requestAdapter(),v=await g.requestDevice(),x=i.getContext("webgpu"),b=window.devicePixelRatio;i.width=i.clientWidth*b,i.height=i.clientHeight*b;let w=navigator.gpu.getPreferredCanvasFormat();x.configure({device:v,format:w,alphaMode:"premultiplied"});let y=v.createBuffer({size:r.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(y.getMappedRange()).set(r.zS),y.unmap();let _=v.createRenderPipeline({layout:"auto",vertex:{module:v.createShaderModule({code:o}),entryPoint:"vertex_main",buffers:[{arrayStride:r.O$,attributes:[{shaderLocation:0,offset:r.v8,format:"float32x4"},{shaderLocation:1,offset:r.Ax,format:"float32x2"}]}]},fragment:{module:v.createShaderModule({code:o}),entryPoint:"fragment_main",targets:[{format:w}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),S=v.createTexture({size:[i.width,i.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),C=v.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let R=await fetch(new n.U(n(5685)).toString()),T=await createImageBitmap(await R.blob());t=v.createTexture({size:[T.width,T.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),v.queue.copyExternalImageToTexture({source:T},{texture:t},[T.width,T.height])}let P=v.createSampler({magFilter:"linear",minFilter:"linear"}),A=v.createBindGroup({layout:_.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:C}},{binding:1,resource:P},{binding:2,resource:t.createView()}]}),V={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:S.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},M=i.width/i.height,E=a._E.perspective(2*Math.PI/5,M,1,100),k=a._E.create(),U=Date.now();requestAnimationFrame(function e(){let t=Date.now(),n=(t-U)/1e3;if(U=t,!s.active)return;let i=function(e){let t=h[d.type],n=t.update(e,m());return a._E.multiply(E,n,k),k}(n);v.queue.writeBuffer(C,0,i.buffer,i.byteOffset,i.byteLength),V.colorAttachments[0].view=x.getCurrentTexture().createView();let o=v.createCommandEncoder(),c=o.beginRenderPass(V);c.setPipeline(_),c.setBindGroup(0,A),c.setVertexBuffer(0,y),c.draw(r.MO),c.end(),v.queue.submit([o.finish()]),requestAnimationFrame(e)})},d=()=>(0,i.Tl)({name:"Cameras",description:"This example provides example camera implementations",gui:!0,init:h,sources:[{name:p.substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\nimport cubeWGSL from './cube.wgsl';\nimport { ArcballCamera, WASDCamera, cameraSourceInfo } from './camera';\nimport { createInputHandler, inputSourceInfo } from './input';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n if (!pageState.active) {\n return;\n }\n\n // The input handler\n const inputHandler = createInputHandler(window);\n\n // The camera types\n const initialCameraPosition = vec3.create(3, 2, 5);\n const cameras = {\n arcball: new ArcballCamera({ position: initialCameraPosition }),\n WASD: new WASDCamera({ position: initialCameraPosition }),\n };\n\n // GUI parameters\n const params: { type: 'arcball' | 'WASD' } = {\n type: 'arcball',\n };\n\n // Callback handler for camera mode\n let oldCameraType = params.type;\n gui.add(params, 'type', ['arcball', 'WASD']).onChange(() => {\n // Copy the camera matrix from old to new\n const newCameraType = params.type;\n cameras[newCameraType].matrix = cameras[oldCameraType].matrix;\n oldCameraType = newCameraType;\n });\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: cubeWGSL,\n }),\n entryPoint: 'vertex_main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: cubeWGSL,\n }),\n entryPoint: 'fragment_main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n cullMode: 'back',\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the image and upload it into a GPUTexture.\n let cubeTexture: GPUTexture;\n {\n const response = await fetch(\n new URL('../../../assets/img/Di-3d.png', import.meta.url).toString()\n );\n const imageBitmap = await createImageBitmap(await response.blob());\n\n cubeTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubeTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getModelViewProjectionMatrix(deltaTime: number) {\n const camera = cameras[params.type];\n const viewMatrix = camera.update(deltaTime, inputHandler());\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n return modelViewProjectionMatrix as Float32Array;\n }\n\n let lastFrameMS = Date.now();\n\n function frame() {\n const now = Date.now();\n const deltaTime = (now - lastFrameMS) / 1000;\n lastFrameMS = now;\n\n if (!pageState.active) {\n // Sample is no longer the active page.\n return;\n }\n\n const modelViewProjection = getModelViewProjectionMatrix(deltaTime);\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjection.buffer,\n modelViewProjection.byteOffset,\n modelViewProjection.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst TexturedCube: () => JSX.Element = () =>\n makeSample({\n name: 'Cameras',\n description: 'This example provides example camera implementations',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n cameraSourceInfo,\n inputSourceInfo,\n {\n name: '../../shaders/cube.wgsl',\n contents: cubeWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default TexturedCube;\n"},s,m,{name:"../../shaders/cube.wgsl",contents:o,editable:!0},{name:"../../meshes/cube.ts",contents:n(2448).Z}],filename:p});var f=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,t){"use strict";t.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},5685:function(e,t,n){"use strict";e.exports=n.p+"static/assets/img/Di-3d.ba319100a0ec2120.png"}}]); \ No newline at end of file diff --git a/_next/static/chunks/webpack-52596f3636814f01.js b/_next/static/chunks/webpack-52596f3636814f01.js deleted file mode 100644 index b90be45d..00000000 --- a/_next/static/chunks/webpack-52596f3636814f01.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var e,t,r,n,a,o,f,i,u,c,d={},b={};function l(e){var t=b[e];if(void 0!==t)return t.exports;var r=b[e]={exports:{}},n=!0;try{d[e].call(r.exports,r,r.exports,l),n=!1}finally{n&&delete b[e]}return r.exports}l.m=d,e=[],l.O=function(t,r,n,a){if(r){a=a||0;for(var o=e.length;o>0&&e[o-1][2]>a;o--)e[o]=e[o-1];e[o]=[r,n,a];return}for(var f=1/0,o=0;o=a&&Object.keys(l.O).every(function(e){return l.O[e](r[u])})?r.splice(u--,1):(i=!1,a0&&e[f-1][2]>a;f--)e[f]=e[f-1];e[f]=[r,n,a];return}for(var o=1/0,f=0;f=a&&Object.keys(l.O).every(function(e){return l.O[e](r[u])})?r.splice(u--,1):(i=!1,aWebGPU Samples \ No newline at end of file +WebGPU Samples \ No newline at end of file diff --git a/samples/A-buffer.html b/samples/A-buffer.html index 584a2007..09a1b77a 100644 --- a/samples/A-buffer.html +++ b/samples/A-buffer.html @@ -10,6 +10,6 @@ } A-Buffer - WebGPU Samples

A-Buffer

See it on Github!

Demonstrates order independent transparency using a per-pixel + limiting memory usage (when required)."/>

\ No newline at end of file + limiting memory usage (when required).

\ No newline at end of file diff --git a/samples/animometer.html b/samples/animometer.html index 04b72abe..5d2a4d3a 100644 --- a/samples/animometer.html +++ b/samples/animometer.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Animometer - WebGPU Samples \ No newline at end of file + Animometer - WebGPU Samples \ No newline at end of file diff --git a/samples/bitonicSort.html b/samples/bitonicSort.html index f3f79e6b..826bd2e6 100644 --- a/samples/bitonicSort.html +++ b/samples/bitonicSort.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Bitonic Sort - WebGPU Samples

Bitonic Sort

See it on Github!

A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each invocation of the bitonic sort shader dispatches a workgroup containing elements/2 threads. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.

\ No newline at end of file + Bitonic Sort - WebGPU Samples

Bitonic Sort

See it on Github!

A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each invocation of the bitonic sort shader dispatches a workgroup containing elements/2 threads. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.

\ No newline at end of file diff --git a/samples/cameras.html b/samples/cameras.html index d1cebf20..94c848d6 100644 --- a/samples/cameras.html +++ b/samples/cameras.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Cameras - WebGPU Samples \ No newline at end of file + Cameras - WebGPU Samples \ No newline at end of file diff --git a/samples/computeBoids.html b/samples/computeBoids.html index 7cf24cb2..65c73f2b 100644 --- a/samples/computeBoids.html +++ b/samples/computeBoids.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Compute Boids - WebGPU Samples \ No newline at end of file + Compute Boids - WebGPU Samples \ No newline at end of file diff --git a/samples/cornell.html b/samples/cornell.html index de387744..fafb60ea 100644 --- a/samples/cornell.html +++ b/samples/cornell.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Cornell box - WebGPU Samples \ No newline at end of file + Cornell box - WebGPU Samples \ No newline at end of file diff --git a/samples/cubemap.html b/samples/cubemap.html index aa156d68..479d7185 100644 --- a/samples/cubemap.html +++ b/samples/cubemap.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Cubemap - WebGPU Samples \ No newline at end of file + Cubemap - WebGPU Samples \ No newline at end of file diff --git a/samples/deferredRendering.html b/samples/deferredRendering.html index 25ffe849..6169bafe 100644 --- a/samples/deferredRendering.html +++ b/samples/deferredRendering.html @@ -16,7 +16,7 @@ We also update light position in a compute shader, where further operations like tile/cluster culling could happen. The debug view shows the depth buffer on the left (flipped and scaled a bit to make it more visible), the normal G buffer in the middle, and the albedo G-buffer on the right side of the screen. - "/>

Deferred Rendering

See it on Github!

This example shows how to do deferred rendering with webgpu. + "/>

Deferred Rendering

See it on Github!

This example shows how to do deferred rendering with webgpu. Render geometry info to multiple targets in the gBuffers in the first pass. In this sample we have 2 gBuffers for normals and albedo, along with a depth texture. And then do the lighting in a second pass with per fragment data read from gBuffers so it's independent of scene complexity. @@ -24,4 +24,4 @@ We also update light position in a compute shader, where further operations like tile/cluster culling could happen. The debug view shows the depth buffer on the left (flipped and scaled a bit to make it more visible), the normal G buffer in the middle, and the albedo G-buffer on the right side of the screen. -

\ No newline at end of file +

\ No newline at end of file diff --git a/samples/fractalCube.html b/samples/fractalCube.html index 8999d66b..d3878534 100644 --- a/samples/fractalCube.html +++ b/samples/fractalCube.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Fractal Cube - WebGPU Samples \ No newline at end of file + Fractal Cube - WebGPU Samples \ No newline at end of file diff --git a/samples/gameOfLife.html b/samples/gameOfLife.html index a019ef47..5e551bdc 100644 --- a/samples/gameOfLife.html +++ b/samples/gameOfLife.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Conway's Game of Life - WebGPU Samples \ No newline at end of file + Conway's Game of Life - WebGPU Samples \ No newline at end of file diff --git a/samples/helloTriangle.html b/samples/helloTriangle.html index d33b29af..3ba794e0 100644 --- a/samples/helloTriangle.html +++ b/samples/helloTriangle.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Hello Triangle - WebGPU Samples \ No newline at end of file + Hello Triangle - WebGPU Samples \ No newline at end of file diff --git a/samples/helloTriangleMSAA.html b/samples/helloTriangleMSAA.html index f6c75546..99c64eb4 100644 --- a/samples/helloTriangleMSAA.html +++ b/samples/helloTriangleMSAA.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Hello Triangle MSAA - WebGPU Samples \ No newline at end of file + Hello Triangle MSAA - WebGPU Samples \ No newline at end of file diff --git a/samples/imageBlur.html b/samples/imageBlur.html index 7e592a3a..f655bee0 100644 --- a/samples/imageBlur.html +++ b/samples/imageBlur.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Image Blur - WebGPU Samples \ No newline at end of file + Image Blur - WebGPU Samples \ No newline at end of file diff --git a/samples/instancedCube.html b/samples/instancedCube.html index 68354311..d12e97aa 100644 --- a/samples/instancedCube.html +++ b/samples/instancedCube.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Instanced Cube - WebGPU Samples \ No newline at end of file + Instanced Cube - WebGPU Samples \ No newline at end of file diff --git a/samples/particles.html b/samples/particles.html index 59d63a87..baf9451d 100644 --- a/samples/particles.html +++ b/samples/particles.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Particles - WebGPU Samples \ No newline at end of file + Particles - WebGPU Samples \ No newline at end of file diff --git a/samples/renderBundles.html b/samples/renderBundles.html index f905530d..b3e11eda 100644 --- a/samples/renderBundles.html +++ b/samples/renderBundles.html @@ -11,7 +11,7 @@ Render Bundles - WebGPU Samples

Render Bundles

See it on Github!

This example shows how to use render bundles. It renders a large number of + of instancing to reduce draw overhead.)"/>

Render Bundles

See it on Github!

This example shows how to use render bundles. It renders a large number of meshes individually as a proxy for a more complex scene in order to demonstrate the reduction in JavaScript time spent to issue render commands. (Typically a scene like this would make use - of instancing to reduce draw overhead.)

\ No newline at end of file + of instancing to reduce draw overhead.)

\ No newline at end of file diff --git a/samples/resizeCanvas.html b/samples/resizeCanvas.html index 49edc2bd..40c5b59f 100644 --- a/samples/resizeCanvas.html +++ b/samples/resizeCanvas.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Resize Canvas - WebGPU Samples \ No newline at end of file + Resize Canvas - WebGPU Samples \ No newline at end of file diff --git a/samples/reversedZ.html b/samples/reversedZ.html index 16a7da21..2e2b65f6 100644 --- a/samples/reversedZ.html +++ b/samples/reversedZ.html @@ -17,7 +17,7 @@ Related reading: https://developer.nvidia.com/content/depth-precision-visualized https://thxforthefish.com/posts/reverse_z/ - "/>

Reversed Z

See it on Github!

This example shows the use of reversed z technique for better utilization of depth buffer precision. + "/>

Reversed Z

See it on Github!

This example shows the use of reversed z technique for better utilization of depth buffer precision. The left column uses regular method, while the right one uses reversed z technique. Both are using depth32float as their depth buffer format. A set of red and green planes are positioned very close to each other. Higher sets are placed further from camera (and are scaled for better visual purpose). @@ -26,4 +26,4 @@ Related reading: https://developer.nvidia.com/content/depth-precision-visualized https://thxforthefish.com/posts/reverse_z/ -

\ No newline at end of file +

\ No newline at end of file diff --git a/samples/rotatingCube.html b/samples/rotatingCube.html index c075f5bf..aeae3cc8 100644 --- a/samples/rotatingCube.html +++ b/samples/rotatingCube.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Rotating Cube - WebGPU Samples \ No newline at end of file + Rotating Cube - WebGPU Samples \ No newline at end of file diff --git a/samples/samplerParameters.html b/samples/samplerParameters.html index 7ad8f8cb..ca005b85 100644 --- a/samples/samplerParameters.html +++ b/samples/samplerParameters.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Sampler Parameters - WebGPU Samples

Sampler Parameters

See it on Github!

Visualizes what all the sampler parameters do. Shows a textured plane at various scales (rotated, head-on, in perspective, and in vanishing perspective). The bottom-right view shows the raw contents of the 4 mipmap levels of the test texture (16x16, 8x8, 4x4, and 2x2).

\ No newline at end of file + Sampler Parameters - WebGPU Samples

Sampler Parameters

See it on Github!

Visualizes what all the sampler parameters do. Shows a textured plane at various scales (rotated, head-on, in perspective, and in vanishing perspective). The bottom-right view shows the raw contents of the 4 mipmap levels of the test texture (16x16, 8x8, 4x4, and 2x2).

\ No newline at end of file diff --git a/samples/shadowMapping.html b/samples/shadowMapping.html index 246aba14..8bb36ba8 100644 --- a/samples/shadowMapping.html +++ b/samples/shadowMapping.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Shadow Mapping - WebGPU Samples \ No newline at end of file + Shadow Mapping - WebGPU Samples \ No newline at end of file diff --git a/samples/texturedCube.html b/samples/texturedCube.html index 150c2ae8..266dae15 100644 --- a/samples/texturedCube.html +++ b/samples/texturedCube.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Textured Cube - WebGPU Samples \ No newline at end of file + Textured Cube - WebGPU Samples \ No newline at end of file diff --git a/samples/twoCubes.html b/samples/twoCubes.html index 525e2771..ef4c84d6 100644 --- a/samples/twoCubes.html +++ b/samples/twoCubes.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Two Cubes - WebGPU Samples \ No newline at end of file + Two Cubes - WebGPU Samples \ No newline at end of file diff --git a/samples/videoUploading.html b/samples/videoUploading.html index 77ae2d33..fa42f435 100644 --- a/samples/videoUploading.html +++ b/samples/videoUploading.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Video Uploading - WebGPU Samples \ No newline at end of file + Video Uploading - WebGPU Samples \ No newline at end of file diff --git a/samples/videoUploadingWebCodecs.html b/samples/videoUploadingWebCodecs.html index 67ecf6b1..e8582a51 100644 --- a/samples/videoUploadingWebCodecs.html +++ b/samples/videoUploadingWebCodecs.html @@ -8,4 +8,4 @@ height: auto !important; overflow: visible !important; } - Video Uploading with WebCodecs - WebGPU Samples \ No newline at end of file + Video Uploading with WebCodecs - WebGPU Samples \ No newline at end of file diff --git a/samples/worker.html b/samples/worker.html index c0d2692a..ce76f766 100644 --- a/samples/worker.html +++ b/samples/worker.html @@ -10,6 +10,6 @@ } WebGPU in a Worker - WebGPU Samples

WebGPU in a Worker

See it on Github!

This example shows one method of using WebGPU in a web worker and presenting to + which is then transferred to the worker where all the WebGPU calls are made."/>

\ No newline at end of file + which is then transferred to the worker where all the WebGPU calls are made.

\ No newline at end of file