diff --git a/README.md b/README.md index c9858f9e..3a57f8e5 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,12 @@ await points.init(renderPasses); You can pass a Compute Shader only, or a Vertex and Fragment together only. This way you can have a Compute Shader without visual output, create calculations and return their response values, or a regular Render Pipeline without Compute Shader calculations. +There's also three extra parameters in the RenderPass, these are to dispatch the workgroups for each dimension (x, y, z): + +```js +new RenderPass(vert1, frag1, compute1, 800, 800, 1); +``` + # Create your custom Shader project 1. Copy the `/examples/base/` and place it where you want to store your project. 2. Rename folder. diff --git a/examples/circleblur/compute.js b/examples/circleblur/compute.js index dbfcdd45..e69a0711 100644 --- a/examples/circleblur/compute.js +++ b/examples/circleblur/compute.js @@ -4,7 +4,7 @@ const compute = /*wgsl*/` ${clearMix} -const workgroupSize = 8; +const workgroupSize = 1; //'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup' @@ -15,42 +15,27 @@ fn main( @builtin(local_invocation_id) LocalInvocationID: vec3 ) { - let filterDim = 128u; - let blockDim = 128u; - let flipValue = 0u; + // let filterDim = 128u; + // let blockDim = 128u; + // let flipValue = 0u; - let filterOffset : u32 = (filterDim - 1u) / 2u; - let dims : vec2 = textureDimensions(feedbackTexture, 0); + // let filterOffset : u32 = (filterDim - 1u) / 2u; - let baseIndex = vec2( - WorkGroupID.xy * vec2(blockDim, 4u) + - LocalInvocationID.xy * vec2(4u, 1u) - ) - vec2(i32(filterOffset), 0); + // let baseIndex = vec2( + // WorkGroupID.xy * vec2(blockDim, 4u) + + // LocalInvocationID.xy * vec2(4u, 1u) + // ) - vec2(i32(filterOffset), 0); // ---------------------------------------------- - let numColumns:f32 = f32(dims.x); - let numRows:f32 = f32(dims.y); - let numColumnsPiece:i32 = i32(numColumns / f32(workgroupSize)); - let numRowsPiece:i32 = i32(numRows / f32(workgroupSize)); - for (var indexColumns:i32 = 0; indexColumns < numColumnsPiece; indexColumns++) { - let x:f32 = f32(WorkGroupID.x) * f32(numColumnsPiece) + f32(indexColumns); - let ux = u32(x); - let nx = x / numColumns; - for (var indexRows:i32 = 0; indexRows < numRowsPiece; indexRows++) { - - let y:f32 = f32(WorkGroupID.y) * f32(numRowsPiece) + f32(indexRows); - let uy = u32(y); - let ny = y / numRows; - - var rgba = textureSampleLevel(feedbackTexture,feedbackSampler, vec2(x,y), 0.0); - - rgba = clearMix(rgba, 1.01) + vec4(1.,0.,0., .5); - - textureStore(outputTex, vec2(ux,uy), rgba); - } - } + var rgba = textureSampleLevel( + feedbackTexture,feedbackSampler, + vec2(f32(GlobalId.x), f32(GlobalId.y)), + 0.0 + ); + rgba = clearMix(rgba, 1.01) + vec4(1.,0.,0., .5); + textureStore(outputTex, GlobalId.xy, rgba); } `; diff --git a/examples/circleblur/index.js b/examples/circleblur/index.js index a6e8d4d4..d5088067 100644 --- a/examples/circleblur/index.js +++ b/examples/circleblur/index.js @@ -1,10 +1,12 @@ import vert from './vert.js'; import compute from './compute.js'; import frag from './frag.js'; +import { RenderPass } from '../../src/absulit.points.module.js'; const circleblur = { - vert, - compute, - frag, + renderPasses: [ + new RenderPass(null, null, compute, 800, 800, 1), + new RenderPass(vert, frag, null, 8, 1, 1) + ], init: async points => { points.addSampler('feedbackSampler'); points.addTexture2d('feedbackTexture', true); diff --git a/examples/dithering3/compute.js b/examples/dithering3_1/compute.js similarity index 95% rename from examples/dithering3/compute.js rename to examples/dithering3_1/compute.js index a9e6ba61..33172a8a 100644 --- a/examples/dithering3/compute.js +++ b/examples/dithering3_1/compute.js @@ -1,4 +1,4 @@ -import { brightness } from './../../src/core/color.js'; +import { brightness } from '../../src/core/color.js'; const compute = /*wgsl*/` diff --git a/examples/dithering3/frag.js b/examples/dithering3_1/frag.js similarity index 100% rename from examples/dithering3/frag.js rename to examples/dithering3_1/frag.js diff --git a/examples/dithering3/index.js b/examples/dithering3_1/index.js similarity index 91% rename from examples/dithering3/index.js rename to examples/dithering3_1/index.js index de5677be..9486b077 100644 --- a/examples/dithering3/index.js +++ b/examples/dithering3_1/index.js @@ -16,7 +16,7 @@ const dithering3 = { await points.addTextureImage('image', './../img/absulit_800x800.jpg'); points.addBindingTexture('outputTex', 'computeTexture'); points.addLayers(2); - points.addStorage('variables', 1, 'Variable', 2, false, ShaderType.COMPUTE); + points.addStorage('variables', 1, 'Variable', 1, false, ShaderType.COMPUTE); }, update: points => { diff --git a/examples/dithering3/vert.js b/examples/dithering3_1/vert.js similarity index 100% rename from examples/dithering3/vert.js rename to examples/dithering3_1/vert.js diff --git a/examples/dithering3_2/compute.js b/examples/dithering3_2/compute.js new file mode 100644 index 00000000..6d3e0bca --- /dev/null +++ b/examples/dithering3_2/compute.js @@ -0,0 +1,81 @@ +import { brightness } from '../../src/core/color.js'; + +const compute = /*wgsl*/` + +struct Variable{ + init: i32 +} + +${brightness} + +const workgroupSize = 1; + +@compute @workgroup_size(workgroupSize,workgroupSize,1) +fn main( + @builtin(global_invocation_id) GlobalId: vec3, + @builtin(workgroup_id) WorkGroupID: vec3, + @builtin(local_invocation_id) LocalInvocationID: vec3 +) { + //-------------------------------------------------- + let dims = textureDimensions(image); + + var layerIndex = 0; + if(variables.init == 0){ + + let pointIndex = i32(GlobalId.y + (GlobalId.x * dims.x)); + + var point = textureLoad(image, GlobalId.yx, 0); // image + // var point = textureLoad(image, GlobalId.yx); // video + layers[0][pointIndex] = point; + layers[1][pointIndex] = point; + + // variables.init = 1; + }else{ + layerIndex = 1; + } + + //-------------------------------------------------- + + let pointIndex = i32(GlobalId.x + (GlobalId.y * dims.y)); + + var point = layers[layerIndex][pointIndex]; + let b = brightness(point); + var newBrightness = 0.; + if(b > .5){ + newBrightness = 1.; + } + + let quant_error = b - newBrightness; + let distance = 1; + let distanceU = u32(distance); + let distanceF = f32(distance); + point = vec4(newBrightness); + + let pointP = &layers[layerIndex][pointIndex]; + (*pointP) = point; + + + let pointIndexC = i32(GlobalId.x + ((GlobalId.y+distanceU) * dims.y)); + var rightPoint = layers[layerIndex][pointIndexC]; + rightPoint = vec4(brightness(rightPoint) + (.5 * quant_error * params.sliderB)); + + let pointPC = &layers[layerIndex][pointIndexC]; + (*pointPC) = rightPoint; + + + let pointIndexR = i32((GlobalId.y+distanceU) + (GlobalId.x * dims.x)); + var bottomPoint = layers[layerIndex][pointIndexR]; + bottomPoint = vec4(brightness(bottomPoint) + (.5 * quant_error)); + + let pointPR = &layers[layerIndex][pointIndexR]; + (*pointPR) = bottomPoint; + + point = layers[layerIndex][pointIndex]; + let positionU = GlobalId.xy; + textureStore(outputTex, positionU, point); + storageBarrier(); + // workgroupBarrier(); +} +`; + +export default compute; diff --git a/examples/dithering3_2/frag.js b/examples/dithering3_2/frag.js new file mode 100644 index 00000000..d6c48df1 --- /dev/null +++ b/examples/dithering3_2/frag.js @@ -0,0 +1,63 @@ +import { snoise } from '../../src/core/noise2d.js'; +import { getClosestColorInPalette, orderedDithering, orderedDithering_threshold_map } from '../../src/core/effects.js'; +import { texturePosition } from '../../src/core/image.js'; +import { fnusin } from '../../src/core/animation.js'; + +const frag = /*wgsl*/` +struct Variable{ + init: i32 +} + +${fnusin} +${snoise} +${getClosestColorInPalette} +${orderedDithering} +${texturePosition} + +${orderedDithering_threshold_map} + +const numPaletteItems = 21; +const getClosestColorInPalette_palette = array< vec4, numPaletteItems>( + vec4(255./255, 69./255, 0, 1.), + vec4(255./255, 168./255, 0, 1.), + vec4(255./255, 214./255, 53./255, 1.), + vec4(0, 204./255, 120./255, 1.), + vec4(126./255, 237./255, 86./255, 1.), + vec4(0./255, 117./255, 111./255, 1.), + vec4(0./255, 158./255, 170./255, 1.), + vec4(36./255, 80./255, 164./255, 1.), + vec4(54./255, 144./255, 234./255, 1.), + vec4(81./255, 233./255, 244./255, 1.), + vec4(73./255, 58./255, 193./255, 1.), + vec4(106./255, 92./255, 255./255, 1.), + vec4(129./255, 30./255, 159./255, 1.), + vec4(180./255, 74./255, 192./255, 1.), + vec4(255./255, 56./255, 129./255, 1.), + vec4(255./255, 153./255, 170./255, 1.), + vec4(109./255, 72./255, 48./255, 1.), + vec4(156./255, 105./255, 38./255, 1.), + vec4(0, 0, 0, 1.), + vec4(137./255, 141./255, 144./255, 1.), + vec4(212./255, 215./255, 217./255, 1.), +); + + +@fragment +fn main( + @location(0) color: vec4, + @location(1) uv: vec2, + @location(2) ratio: vec2, + @location(3) uvRatio: vec2, + @location(4) mouse: vec2, + @builtin(position) position: vec4 + ) -> @location(0) vec4 { + + //let imageUV = (uv / f + vec2(0, .549 ) ) * vec2(1,-1 * dimsRatio) * ratio.y / params.sliderA; + //var point = textureSample(computeTexture, imageSampler, imageUV); //* .998046; + var point = texturePosition(computeTexture, imageSampler, vec2(0.), uv / params.sliderA, false); //* .998046; + + return point; +} +`; + +export default frag; diff --git a/examples/dithering3_2/index.js b/examples/dithering3_2/index.js new file mode 100644 index 00000000..f16e3349 --- /dev/null +++ b/examples/dithering3_2/index.js @@ -0,0 +1,26 @@ +import vert from './vert.js'; +import compute from './compute.js'; +import frag from './frag.js'; +import { RenderPass, ShaderType } from '../../src/absulit.points.module.js'; +const dithering3 = { + renderPasses: [ + new RenderPass(vert, frag, compute, 800, 800) + ], + init: async points => { + points.addSampler('imageSampler', null); + // await points.addTextureImage('image', './../img/carmen_lyra_423x643.jpg'); + // await points.addTextureImage('image', './../img/old_king_800x00.jpg'); + // await points.addTextureWebcam('image'); + // await points.addTextureImage('image', './../img/angel_600x600.jpg'); + // await points.addTextureImage('image', './../img/gratia_800x800.jpg'); + await points.addTextureImage('image', './../img/absulit_800x800.jpg'); + points.addBindingTexture('outputTex', 'computeTexture'); + points.addLayers(2); + points.addStorage('variables', 1, 'Variable', 1, false, ShaderType.COMPUTE); + }, + update: points => { + + } +} + +export default dithering3; \ No newline at end of file diff --git a/examples/dithering3_2/vert.js b/examples/dithering3_2/vert.js new file mode 100644 index 00000000..d1fe1d1f --- /dev/null +++ b/examples/dithering3_2/vert.js @@ -0,0 +1,19 @@ +const vert = /*wgsl*/` + +struct Variable{ + init: i32 +} + +@vertex +fn main( + @location(0) position: vec4, + @location(1) color: vec4, + @location(2) uv: vec2, + @builtin(vertex_index) vertexIndex: u32 +) -> Fragment { + + return defaultVertexBody(position, color, uv); +} +`; + +export default vert; diff --git a/examples/main.js b/examples/main.js index 532ba0dc..05404347 100644 --- a/examples/main.js +++ b/examples/main.js @@ -41,7 +41,7 @@ gui.add(stats2, 'visible').name('Show Stats').onChange(value => setStatsVisibili let isFullscreenData = { 'isFullscreen': false }; let fullscreenCheck = gui.add(isFullscreenData, 'isFullscreen').name('Fullscreen').onChange(value => points.fullscreen = value); -document.addEventListener("fullscreenchange", e => { +document.addEventListener('fullscreenchange', e => { let isFullscreen = window.innerWidth == screen.width && window.innerHeight == screen.height; isFullscreenData.isFullscreen = isFullscreen; fullscreenCheck.updateDisplay(); @@ -62,7 +62,8 @@ const shaderProjects = [ { name: 'Demo 6', path: './demo_6/index.js' }, { name: 'Dithering 1', path: './dithering1/index.js' }, { name: 'Dithering 2', path: './dithering2/index.js' }, - { name: 'Dithering 3', path: './dithering3/index.js' }, + { name: 'Dithering 3 - 1', path: './dithering3_1/index.js' }, + { name: 'Dithering 3 - 2', path: './dithering3_2/index.js' }, { name: 'Dithering 4', path: './dithering4/index.js' }, { name: 'Image Scale 1', path: './imagescale1/index.js' }, { name: 'Image Texture 1', path: './imagetexture1/index.js' }, @@ -147,6 +148,13 @@ const recordingOptions = [ started: false, controller: null }, + { + nameStopped: 'Download PNG Image', + fn: function (e) { + let image = document.getElementById('gl-canvas').toDataURL().replace('image/png', 'image/octet-stream'); + window.location.href = image; + }, + }, ]; recordingOptions.forEach(recordingOption => { diff --git a/examples/random2/compute.js b/examples/random2/compute.js index 4a6e2b9a..d0dd69dd 100644 --- a/examples/random2/compute.js +++ b/examples/random2/compute.js @@ -8,41 +8,15 @@ fn main( @builtin(workgroup_id) WorkGroupID: vec3, @builtin(local_invocation_id) LocalInvocationID: vec3 ) { - - let dims = textureDimensions(feedbackTexture); - let numColumns:f32 = f32(dims.x); - let numRows:f32 = f32(dims.y); - - let numColumnsPiece:i32 = i32(numColumns / f32(workgroupSize)); - let numRowsPiece:i32 = i32(numRows / f32(workgroupSize)); - - //-------------------------------------------------- - for (var indexColumns:i32 = 0; indexColumns < numColumnsPiece; indexColumns++) { - let x:f32 = f32(WorkGroupID.x) * f32(numColumnsPiece) + f32(indexColumns); - let ux = u32(x); - // let ix = i32(x); - // let nx = x / numColumns; - for (var indexRows:i32 = 0; indexRows < numRowsPiece; indexRows++) { - - let y:f32 = f32(WorkGroupID.y) * f32(numRowsPiece) + f32(indexRows); - let uy = u32(y); - // let iy = i32(y); - // let ny = y / numRows; - // let uv = vec2(nx,ny); - - let pointIndex = i32(y + (x * numColumns)); - let c = rands[pointIndex]; - - let positionU = vec2(ux,uy); - textureStore(outputTex, positionU, vec4(c)); - storageBarrier(); - } - } + let pointIndex = i32(GlobalId.y + (GlobalId.x * dims.x)); + let c = rands[pointIndex]; + textureStore(outputTex, GlobalId.xy, vec4(c)); + storageBarrier(); } `; diff --git a/examples/random2/index.js b/examples/random2/index.js index 360aa97c..e9ffd1e5 100644 --- a/examples/random2/index.js +++ b/examples/random2/index.js @@ -1,10 +1,11 @@ import vert from './vert.js'; import compute from './compute.js'; import frag from './frag.js'; +import { RenderPass } from '../../src/absulit.points.module.js'; const random2 = { - vert, - compute, - frag, + renderPasses: [ + new RenderPass(vert, frag, compute, 800, 800) + ], init: async points => { points.addUniform('randNumber', 0); points.addUniform('randNumber2', 0); diff --git a/examples/random3/compute.js b/examples/random3/compute.js index 496b814f..53675adb 100644 --- a/examples/random3/compute.js +++ b/examples/random3/compute.js @@ -9,7 +9,7 @@ ${rand} ${RGBAFromHSV} ${fnusin} -const workgroupSize = 8; +const workgroupSize = 1; @compute @workgroup_size(workgroupSize,workgroupSize,1) fn main( @@ -21,40 +21,27 @@ fn main( let numColumns:f32 = params.screenWidth; let numRows:f32 = params.screenHeight; - let numColumnsPiece:i32 = i32(numColumns / f32(workgroupSize)); - let numRowsPiece:i32 = i32(numRows / f32(workgroupSize)); - - for (var indexColumns:i32 = 0; indexColumns < numColumnsPiece; indexColumns++) { - let x:f32 = f32(WorkGroupID.x) * f32(numColumnsPiece) + f32(indexColumns); - let ux = u32(x); - let ix = i32(x); - let nx = x / numColumns; - for (var indexRows:i32 = 0; indexRows < numRowsPiece; indexRows++) { - - let y:f32 = f32(WorkGroupID.y) * f32(numRowsPiece) + f32(indexRows); - let uy = u32(y); - let iy = i32(y); - let ny = y / numRows; - - rand_seed.x += f32(WorkGroupID.x); - rand_seed.y += f32(WorkGroupID.y); - - seed += i32(WorkGroupID.x + WorkGroupID.y); - - let randNumber = rand(); - rand_seed.y += randNumber + fract(params.sliderA); - var v = 0.; - if(randNumber < .5){ - v = 1.; - } - - // textureStore(outputTex, vec2(ux,uy), vec4(randNumber)); - // textureStore(outputTex, vec2(ux,uy), RGBAFromHSV(randNumber, 1, 1)); - // textureStore(outputTex, vec2(ux,uy), RGBAFromHSV( fnusin(randNumber), 1, 1)); - // textureStore(outputTex, vec2(ux,uy), vec4( fnusin(randNumber))); - textureStore(outputTex, vec2(ux,uy), vec4( fract(randNumber + fnusin(1)))); - } + rand_seed.x += f32(WorkGroupID.x); + rand_seed.y += f32(WorkGroupID.y); + + seed += i32(WorkGroupID.x + WorkGroupID.y); + + let randNumber = rand(); + rand_seed.y += randNumber + fract(params.sliderA); + var v = 0.; + if(randNumber < .5){ + v = 1.; } + + // textureStore(outputTex, GlobalId.xy, vec4(randNumber)); + // textureStore(outputTex, GlobalId.xy, RGBAFromHSV(randNumber, 1, 1)); + // textureStore(outputTex, GlobalId.xy, RGBAFromHSV( fnusin(randNumber), 1, 1)); + // textureStore(outputTex, GlobalId.xy, vec4( fnusin(randNumber))); + + textureStore(outputTex, GlobalId.xy, vec4( fract(randNumber + fnusin(1)))); + // textureStore(outputTex, WorkGroupID.xy, vec4( fract(randNumber + fnusin(1)))); + // textureStore(outputTex, LocalInvocationID.xy, vec4( fract(randNumber + fnusin(1)))); + } `; diff --git a/examples/random3/index.js b/examples/random3/index.js index ed686906..9d7cb854 100644 --- a/examples/random3/index.js +++ b/examples/random3/index.js @@ -1,10 +1,13 @@ import vert from './vert.js'; import compute from './compute.js'; import frag from './frag.js'; +import { RenderPass } from '../../src/absulit.points.module.js'; + const random3 = { - vert, - compute, - frag, + + renderPasses: [ + new RenderPass(vert, frag, compute, 800, 800) + ], init: async points => { points.addSampler('feedbackSampler'); points.addTexture2d('feedbackTexture', true); diff --git a/examples/shapes1/compute.js b/examples/shapes1/compute.js index f468fbe7..81e78fa0 100644 --- a/examples/shapes1/compute.js +++ b/examples/shapes1/compute.js @@ -1,8 +1,8 @@ const compute = /*wgsl*/` -const workgroupSize = 8; +const workgroupSize = 1; -@compute @workgroup_size(8,8,1) +@compute @workgroup_size(workgroupSize,workgroupSize,1) fn main( @builtin(global_invocation_id) GlobalId: vec3, @builtin(workgroup_id) WorkGroupID: vec3, @@ -12,12 +12,10 @@ fn main( let numPoints = u32(params.numPoints); // list of points for the sine wave - for(var k:u32; k < numPoints; k++){ - let fk = f32(k); - let point = &points[k]; - (*point).x = fk / params.numPoints; - (*point).y = sin( ((*point).x * 32) + time) * .1; - } + let fk = f32(GlobalId.x); + let point = &points[GlobalId.x]; + (*point).x = fk / params.numPoints; + (*point).y = sin( ((*point).x * 32) + time) * .1; } `; diff --git a/examples/shapes1/index.js b/examples/shapes1/index.js index a7fdc855..b25f8730 100644 --- a/examples/shapes1/index.js +++ b/examples/shapes1/index.js @@ -1,10 +1,11 @@ import vert from './vert.js'; import compute from './compute.js'; import frag from './frag.js'; +import { RenderPass } from '../../src/absulit.points.module.js'; const shapes1 = { - vert, - compute, - frag, + renderPasses: [ + new RenderPass(vert, frag, compute, 128, 1, 1) + ], init: async points => { const numPoints = 128; points.addUniform('numPoints', numPoints); diff --git a/examples/shapes2/compute.js b/examples/shapes2/compute.js index 58bd5db2..21c4f8c6 100644 --- a/examples/shapes2/compute.js +++ b/examples/shapes2/compute.js @@ -1,3 +1,4 @@ +import { fnusin } from '../../src/core/animation.js'; import { clearAlpha, soften4, soften8 } from '../../src/core/effects.js'; import { sdfCircle, sdfLine2, sdfSegment } from '../../src/core/sdf.js'; @@ -9,6 +10,7 @@ ${clearAlpha} ${sdfSegment} ${sdfLine2} ${sdfCircle} +${fnusin} struct Colors{ items: array< vec4, 800*800 > @@ -49,20 +51,16 @@ fn getColorsAround4Layer(position: vec2, distance: u32) -> array< vec4, @builtin(workgroup_id) WorkGroupID: vec3, @builtin(local_invocation_id) LocalInvocationID: vec3 ) { - let time = params.time; - let numColumns:f32 = params.screenWidth; let numRows:f32 = params.screenHeight; - let numColumnsPiece:i32 = i32(numColumns / f32(workgroupSize)); - let numRowsPiece:i32 = i32(numRows / f32(workgroupSize)); var x = 450.; var y = 450.; @@ -82,50 +80,37 @@ fn main( var rgba = vec4(0.); var colorsAround = array< vec4, 4 >(); - for (var indexColumns:i32 = 0; indexColumns < numColumnsPiece; indexColumns++) { - let x:f32 = f32(WorkGroupID.x) * f32(numColumnsPiece) + f32(indexColumns); - let ux = u32(x); - let ix = i32(x); - let nx = x / numColumns; - for (var indexRows:i32 = 0; indexRows < numRowsPiece; indexRows++) { - - let y:f32 = f32(WorkGroupID.y) * f32(numRowsPiece) + f32(indexRows); - let uy = u32(y); - let iy = i32(y); - let ny = y / numRows; - let uv = vec2(nx,ny); - - let positionU = vec2(ux,uy); - - let uIndex = getPointsIndex(positionU); - // let rgba = &points[uIndex]; - // let a = sin(uv.x * params.time); - // (*rgba) = vec4(a * uv.x, 1-uv.y, a, 1); - - rgba = points[uIndex]; - colorsAround = getColorsAround4Layer(positionU, 1); - let rgbaP = &points[uIndex]; - - (*rgbaP) = soften4(rgba, colorsAround, 1.); - rgba = points[uIndex]; - (*rgbaP) = clearAlpha(rgba, 1.01); - let sdf = sdfCircle(vec2(.3,.3), .1, 0., uv); - (*rgbaP) += sdf; - - - rgba = points[uIndex]; - - - textureStore(outputTex, positionU, rgba); - } + let nx = f32(GlobalId.x) / numColumns; + let ny = f32(GlobalId.y) / numRows; + let uv = vec2(nx,ny); + let positionU = GlobalId.xy; + + let uIndex = getPointsIndex(positionU); + // let rgba = &points[uIndex]; + // let a = sin(uv.x * params.time); + // (*rgba) = vec4(a * uv.x, 1-uv.y, a, 1); + + rgba = points[uIndex]; + colorsAround = getColorsAround4Layer(positionU, 1); + let rgbaP = &points[uIndex]; + + (*rgbaP) = soften4(rgba, colorsAround, 1.); + rgba = points[uIndex]; + (*rgbaP) = clearAlpha(rgba, 1000.01); + if(rgba.a > 0){ + rgba -= .4; } + (*rgbaP) = rgba; + let sdf = sdfCircle(vec2(1.,1.) * fnusin(1), .01, .2, uv); + (*rgbaP) += sdf; + rgba = points[uIndex]; - + textureStore(outputTex, positionU, rgba); } `; diff --git a/examples/shapes2/index.js b/examples/shapes2/index.js index 89d3c1f9..ea29331b 100644 --- a/examples/shapes2/index.js +++ b/examples/shapes2/index.js @@ -1,10 +1,11 @@ import vert from './vert.js'; import compute from './compute.js'; import frag from './frag.js'; +import { RenderPass } from '../../src/absulit.points.module.js'; const shapes2 = { - vert, - compute, - frag, + renderPasses: [ + new RenderPass(vert, frag, compute, 800, 800, 1) + ], init: async points => { const numPoints = 800*800; points.addUniform('numPoints', numPoints); diff --git a/src/absulit.points.module.js b/src/absulit.points.module.js index 2fe56996..744f04d3 100644 --- a/src/absulit.points.module.js +++ b/src/absulit.points.module.js @@ -32,7 +32,7 @@ export class RenderPass { * @param {String} fragmentShader WGSL Fragment Shader in a String. * @param {String} computeShader WGSL Compute Shader in a String. */ - constructor(vertexShader, fragmentShader, computeShader) { + constructor(vertexShader, fragmentShader, computeShader, workgroupCountX, workgroupCountY, workgroupCountZ) { this._vertexShader = vertexShader; this._computeShader = computeShader; this._fragmentShader = fragmentShader; @@ -56,6 +56,10 @@ export class RenderPass { this._hasFragmentShader = !!this._fragmentShader; this._hasVertexAndFragmentShader = this._hasVertexShader && this._hasFragmentShader; + + this._workgroupCountX = workgroupCountX || 8; + this._workgroupCountY = workgroupCountY || 8; + this._workgroupCountZ = workgroupCountZ || 1; } get internal() { @@ -129,6 +133,18 @@ export class RenderPass { get hasVertexAndFragmentShader() { return this._hasVertexAndFragmentShader; } + + get workgroupCountX() { + return this._workgroupCountX; + } + + get workgroupCountY() { + return this._workgroupCountY; + } + + get workgroupCountZ() { + return this._workgroupCountZ; + } } export class VertexBufferInfo { @@ -243,17 +259,20 @@ export default class Points { window.addEventListener('resize', this._resizeCanvasToFitWindow, false); document.addEventListener("fullscreenchange", e => { - let isFullscreen = window.innerWidth == screen.width && window.innerHeight == screen.height; + let isFullscreen = !!document.fullscreenElement; this._fullscreen = isFullscreen; if (!isFullscreen && !this._fitWindow) { this._resizeCanvasToDefault(); } + if (!isFullscreen) { + this.fitWindow = this._lastFitWindow; + } }); } this._fullscreen = false; this._fitWindow = false; - + this._lastFitWindow = false; // _readStorage should only be read once this._readStorageCopied = false; @@ -727,15 +746,11 @@ export default class Points { let dynamicStructParams = ''; this._uniforms.forEach(variable => { - dynamicStructParams += /*wgsl*/`${variable.name}:f32, \n\t\t\t\t\t`; + dynamicStructParams += /*wgsl*/`${variable.name}:f32, \n\t`; }); if (this._uniforms.length) { - dynamicStructParams = /*wgsl*/` - struct Params { - ${dynamicStructParams} - } - \n`; + dynamicStructParams = /*wgsl*/`struct Params {\n\t${dynamicStructParams}\n}\n`; } renderPass.hasVertexShader && (dynamicGroupBindingsVertex += dynamicStructParams); @@ -1180,7 +1195,7 @@ export default class Points { } if (this._storage.length) { - this._storage.forEach((storageItem, index) => { + this._storage.forEach(storageItem => { let internalCheck = internal == storageItem.internal; if (!storageItem.shaderType && internalCheck || storageItem.shaderType == shaderType && internalCheck) { entries.push( @@ -1318,7 +1333,7 @@ export default class Points { entries.push( { label: 'binding texture 2', - binding: bindingIndex, // this does not increase, must match the previous block + binding: bindingIndex++, resource: bindingTexture.texture.createView(), type: { name: 'texture', @@ -1427,7 +1442,11 @@ export default class Points { if (this._uniforms.length) { passEncoder.setBindGroup(0, renderPass.computeBindGroup); } - passEncoder.dispatchWorkgroups(8, 8, 1); + passEncoder.dispatchWorkgroups( + renderPass.workgroupCountX, + renderPass.workgroupCountY, + renderPass.workgroupCountZ + ); passEncoder.end(); } }); @@ -1583,6 +1602,8 @@ export default class Points { set fullscreen(value) { if (value) { + this._lastFitWindow = this._fitWindow; + this.fitWindow = value; this._canvas.requestFullscreen().catch(err => { throw `Error attempting to enable fullscreen mode: ${err.message} (${err.name})`; });