From 8ae0907fda414b6586627a877477d3e7faa43df8 Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Thu, 23 Mar 2023 12:53:03 +0100 Subject: [PATCH 1/8] 3d texture experiment - something works --- demo/3dt.html | 53 +++++++++++++++++++++++++++++++ src/repa-shader.js | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 demo/3dt.html diff --git a/demo/3dt.html b/demo/3dt.html new file mode 100644 index 0000000..c01e635 --- /dev/null +++ b/demo/3dt.html @@ -0,0 +1,53 @@ + + + + + <repa-shader> demo + + + + + + + +void main() { + vec2 uv = gl_FragCoord.xy / resolution.xy; + vec3 col = texture(tex_avatar, uv).rgb; + + col = texture(test3d, vec3(uv.xy, mouse.x)).rrr; + + float dist = distance(uv, mouse.xy); + float circle = smoothstep(.025, .026, dist) * .5 + .5; + vec4 acolor = vec4(col * circle, circle); + outColor = vec4(acolor); +} + +
+ +
+ + + + diff --git a/src/repa-shader.js b/src/repa-shader.js index 6c6244f..cf41e5d 100644 --- a/src/repa-shader.js +++ b/src/repa-shader.js @@ -16,6 +16,7 @@ const CHUNKS = { #define t time #define f frame precision highp float; +precision highp sampler3D; uniform vec2 resolution; uniform vec3 mouse; uniform vec3 orientation; @@ -280,6 +281,55 @@ class RepaShader extends HTMLElement { texElement: t, }); }); + + // TODO 3d texture experiment + let texture = this._gl.createTexture(); + this._gl.bindTexture(this._gl.TEXTURE_3D, texture); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MIN_FILTER, this._gl.NEAREST); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MAG_FILTER, this._gl.NEAREST); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE); + + this._gl.texImage3D( + this._gl.TEXTURE_3D, // target + 0, // level + this._gl.R8, // format - red8 (1byte) + 3, // width + 3, // height + 3, // depth + 0, // border + this._gl.RED, // format - red + this._gl.UNSIGNED_BYTE, // type - unsigned byte + new Uint8Array([ + 0, 0, 0, + 0, 127, 0, + 0, 0, 0, + + 0, 127, 0, + 127, 255, 127, + 0, 127, 0, + + 0, 0, 0, + 0, 127, 0, + 0, 0, 0, + + 127, 0, 127, + 0, 0, 0, + 127, 0, 127, + ]) // data + ); + + this._textures3d = []; + this._textures3d.push({ + texture, + texElement: { + name: 'test3d', + width: 3, + height: 3, + depth: 3, + }, + }); + // TODO end of 3d texture experiment } async reset(time) { @@ -351,6 +401,13 @@ class RepaShader extends HTMLElement { t.texElement.forceUpdate(); }); + // TODO 3d texture experiment + this._textures3d.forEach((t) => { + this._uniLocation[t.texElement.name] = this._gl.getUniformLocation(this.program, t.texElement.name); // texture + this._uniLocation[t.texElement.name+'_d'] = this._gl.getUniformLocation(this.program, t.texElement.name+'_d'); // dimensions + // TODO + }); + this._attLocation = this._gl.getAttribLocation(this.program, 'position'); this._mousePosition= [0, 0, 0]; this._orientation = [0, 0, 0]; @@ -408,6 +465,18 @@ class RepaShader extends HTMLElement { this._gl.uniform2fv(this._uniLocation[t.texElement.name+'_d'], [t.texElement.width || 1, t.texElement.height || 1]); }); + // TODO 3d texture experiment + this._textures3d.forEach((t, i) => { + this._gl.activeTexture(this._gl.TEXTURE0 + i + this.mrt + this._textures.length); + this._gl.bindTexture(this._gl.TEXTURE_3D, t.texture); + this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, 0); + + // TODO update, etc + + this._gl.uniform1i(this._uniLocation[t.texElement.name], i + this.mrt + this._textures.length); + this._gl.uniform3fv(this._uniLocation[t.texElement.name+'_d'], [t.texElement.width || 1, t.texElement.height || 1, t.texElement.depth || 1]); + }); + this._gl.drawArrays(this._gl.TRIANGLE_STRIP, 0, 4); // fill buffer @@ -522,6 +591,7 @@ void main() { } get postFS() { + // TODO 3d texture experiment return `#version 300 es precision mediump float; uniform sampler2D drawTexture; @@ -564,6 +634,13 @@ void main() { return ` uniform sampler2D ${t.texElement.name}; uniform vec2 ${t.texElement.name}_d; + `; + }).join('') + + // TODO 3d texture experiment + this._textures3d.map(t => { + return ` + uniform sampler3D ${t.texElement.name}; + uniform vec3 ${t.texElement.name}_d; `; }).join(''); } From 0fb709ff7c2e5656a241eade766e6029ae57447d Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Thu, 23 Mar 2023 13:47:51 +0100 Subject: [PATCH 2/8] 3d texture min size should be 16x16x16... --- src/repa-shader.js | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/repa-shader.js b/src/repa-shader.js index cf41e5d..f0190d0 100644 --- a/src/repa-shader.js +++ b/src/repa-shader.js @@ -289,34 +289,34 @@ class RepaShader extends HTMLElement { this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MAG_FILTER, this._gl.NEAREST); this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE); this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_R, this._gl.CLAMP_TO_EDGE); + // ??? + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_BASE_LEVEL, 0); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MAX_LEVEL, 0); + + let size = 32; + let t3data = new Uint8Array(size * size * size); + + for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + for (let k = 0; k < size; k++) { + let index = i * size * size + j * size + k; + t3data[index] = (i * j * k) % 255; + } + } + } this._gl.texImage3D( this._gl.TEXTURE_3D, // target 0, // level this._gl.R8, // format - red8 (1byte) - 3, // width - 3, // height - 3, // depth + size, // width + size, // height + size, // depth 0, // border this._gl.RED, // format - red this._gl.UNSIGNED_BYTE, // type - unsigned byte - new Uint8Array([ - 0, 0, 0, - 0, 127, 0, - 0, 0, 0, - - 0, 127, 0, - 127, 255, 127, - 0, 127, 0, - - 0, 0, 0, - 0, 127, 0, - 0, 0, 0, - - 127, 0, 127, - 0, 0, 0, - 127, 0, 127, - ]) // data + t3data // data ); this._textures3d = []; @@ -324,9 +324,9 @@ class RepaShader extends HTMLElement { texture, texElement: { name: 'test3d', - width: 3, - height: 3, - depth: 3, + width: size, + height: size, + depth: size, }, }); // TODO end of 3d texture experiment From e31e7e39c308837b869ce3a698f30425e53203c6 Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Sat, 25 Mar 2023 20:17:23 +0100 Subject: [PATCH 3/8] 3d texture related refactor --- demo/3dt.html | 3 +- src/repa-shader.js | 78 +++++++++++++-------------------------------- src/repa-texture.js | 39 +++++++++++++++++++++-- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/demo/3dt.html b/demo/3dt.html index c01e635..428ecb0 100644 --- a/demo/3dt.html +++ b/demo/3dt.html @@ -25,11 +25,12 @@ + void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; vec3 col = texture(tex_avatar, uv).rgb; - col = texture(test3d, vec3(uv.xy, mouse.x)).rrr; + col *= texture(test3d, vec3(uv.xy, mouse.x)).rrr; float dist = distance(uv, mouse.xy); float circle = smoothstep(.025, .026, dist) * .5 + .5; diff --git a/src/repa-shader.js b/src/repa-shader.js index f0190d0..0aa6c47 100644 --- a/src/repa-shader.js +++ b/src/repa-shader.js @@ -263,8 +263,9 @@ class RepaShader extends HTMLElement { _collectTextures() { this._textures = []; + this._textures3d = []; - this.querySelectorAll('repa-texture').forEach(t => { + this.querySelectorAll('repa-texture:not([t3d])').forEach(t => { const texture = this._gl.createTexture(); this._gl.bindTexture(this._gl.TEXTURE_2D, texture); @@ -282,54 +283,22 @@ class RepaShader extends HTMLElement { }); }); - // TODO 3d texture experiment - let texture = this._gl.createTexture(); - this._gl.bindTexture(this._gl.TEXTURE_3D, texture); - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MIN_FILTER, this._gl.NEAREST); - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MAG_FILTER, this._gl.NEAREST); - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE); - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE); - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_R, this._gl.CLAMP_TO_EDGE); - // ??? - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_BASE_LEVEL, 0); - this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MAX_LEVEL, 0); + this.querySelectorAll('repa-texture[t3d]').forEach(t => { + let texture = this._gl.createTexture(); + this._gl.bindTexture(this._gl.TEXTURE_3D, texture); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MIN_FILTER, this._getFilter(t.minFilter)); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_MAG_FILTER, this._getFilter(t.magFilter)); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_S, this._getWrap(t.wrapS)); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_T, this._getWrap(t.wrapT)); + this._gl.texParameteri(this._gl.TEXTURE_3D, this._gl.TEXTURE_WRAP_R, this._getWrap(t.wrapR)); - let size = 32; - let t3data = new Uint8Array(size * size * size); + this._gl.texImage3D(this._gl.TEXTURE_3D, 0, this._gl.RGBA, 1, 1, 1, 0, this._gl.RGBA, this._gl.UNSIGNED_BYTE, new Uint8Array([64, 255, 128, 255])); - for (let i = 0; i < size; i++) { - for (let j = 0; j < size; j++) { - for (let k = 0; k < size; k++) { - let index = i * size * size + j * size + k; - t3data[index] = (i * j * k) % 255; - } - } - } - - this._gl.texImage3D( - this._gl.TEXTURE_3D, // target - 0, // level - this._gl.R8, // format - red8 (1byte) - size, // width - size, // height - size, // depth - 0, // border - this._gl.RED, // format - red - this._gl.UNSIGNED_BYTE, // type - unsigned byte - t3data // data - ); - - this._textures3d = []; - this._textures3d.push({ - texture, - texElement: { - name: 'test3d', - width: size, - height: size, - depth: size, - }, + this._textures3d.push({ + texture, + texElement: t + }); }); - // TODO end of 3d texture experiment } async reset(time) { @@ -375,8 +344,6 @@ class RepaShader extends HTMLElement { return; } - // TODO sound? - if (this._program) { this._gl.deleteProgram(this._program); } @@ -401,11 +368,10 @@ class RepaShader extends HTMLElement { t.texElement.forceUpdate(); }); - // TODO 3d texture experiment this._textures3d.forEach((t) => { this._uniLocation[t.texElement.name] = this._gl.getUniformLocation(this.program, t.texElement.name); // texture this._uniLocation[t.texElement.name+'_d'] = this._gl.getUniformLocation(this.program, t.texElement.name+'_d'); // dimensions - // TODO + t.texElement.forceUpdate(); }); this._attLocation = this._gl.getAttribLocation(this.program, 'position'); @@ -465,13 +431,17 @@ class RepaShader extends HTMLElement { this._gl.uniform2fv(this._uniLocation[t.texElement.name+'_d'], [t.texElement.width || 1, t.texElement.height || 1]); }); - // TODO 3d texture experiment this._textures3d.forEach((t, i) => { this._gl.activeTexture(this._gl.TEXTURE0 + i + this.mrt + this._textures.length); this._gl.bindTexture(this._gl.TEXTURE_3D, t.texture); - this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, 0); - // TODO update, etc + // update if needed + if (t.texElement.shouldUpdate) { + const format = this._getFormat(t.texElement.format); + this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, 0); + + this._gl.texImage3D(this._gl.TEXTURE_3D, 0, format, t.texElement.width, t.texElement.height, t.texElement.depth, 0, format, this._gl.UNSIGNED_BYTE, t.texElement.update()); + } this._gl.uniform1i(this._uniLocation[t.texElement.name], i + this.mrt + this._textures.length); this._gl.uniform3fv(this._uniLocation[t.texElement.name+'_d'], [t.texElement.width || 1, t.texElement.height || 1, t.texElement.depth || 1]); @@ -591,7 +561,6 @@ void main() { } get postFS() { - // TODO 3d texture experiment return `#version 300 es precision mediump float; uniform sampler2D drawTexture; @@ -636,7 +605,6 @@ void main() { uniform vec2 ${t.texElement.name}_d; `; }).join('') + - // TODO 3d texture experiment this._textures3d.map(t => { return ` uniform sampler3D ${t.texElement.name}; diff --git a/src/repa-texture.js b/src/repa-texture.js index dedc752..ea65665 100644 --- a/src/repa-texture.js +++ b/src/repa-texture.js @@ -33,7 +33,7 @@ class RepaTexture extends HTMLElement { } static get observedAttributes() { - return ['src', 'type', 'mag-filter', 'min-filter', 'filter', 'wrap-s', 'wrap-t', 'wrap', 'format']; + return ['src', 'type', 'mag-filter', 'min-filter', 'filter', 'wrap-s', 'wrap-t', 'wrap-r', 'wrap', 'format']; } attributeChangedCallback(name, oldValue, newValue) { @@ -86,8 +86,29 @@ class RepaTexture extends HTMLElement { this._forceUpdate = true; } else if (this.textContent) { this.content = JSON.parse(this.textContent); + } else if (this.t3d) { // TODO 3d texture experiment + let size = 32; + this._width = size; + this._height = size; + this._depth = size; + + let t3data = new Uint8Array(size * size * size); + + for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + for (let k = 0; k < size; k++) { + let index = i * size * size + j * size + k; + t3data[index] = (i * j * k) % 255; + } + } + } + + this._content = t3data; + this._forceUpdate = true; + this._format = 'luminance'; + this.ready = true; } else { - this.logger.error('Source cannot be loaded'); + this.logger.error('Texture content cannot be loaded!'); } } @@ -212,8 +233,12 @@ class RepaTexture extends HTMLElement { return null; } + get t3d() { + return this.hasAttribute('t3d'); + } + get flipY() { - return this.type !== 'raw'; + return !this.t3d && this.type !== 'raw'; } setContent(data) { @@ -334,6 +359,10 @@ class RepaTexture extends HTMLElement { return this._height || this.ref?.videoHeight || this.ref?.height || 0; } + get depth() { + return this._depth || this.ref?.depth || 0; + } + get magFilter() { return this._filter || this.getAttribute('mag-filter') || this.getAttribute('filter') || 'linear'; } @@ -350,6 +379,10 @@ class RepaTexture extends HTMLElement { return this.getAttribute('wrap-t') || this.getAttribute('wrap') || 'clamp-to-edge'; } + get wrapR() { + return this.getAttribute('wrap-r') || this.getAttribute('wrap') || 'clamp-to-edge'; + } + get format() { return this._format || this.getAttribute('format') || 'rgba'; } From 73e88916e96a8a27cace7ef70097af68e1e6f26f Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Tue, 28 Mar 2023 18:09:41 +0200 Subject: [PATCH 4/8] ts/jsdoc experiment --- src/repa-shader.js | 45 ++++++++++++++++++++++++++++++++++++++++++++- tsconfig.json | 13 +++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tsconfig.json diff --git a/src/repa-shader.js b/src/repa-shader.js index 0aa6c47..0e58208 100644 --- a/src/repa-shader.js +++ b/src/repa-shader.js @@ -1,3 +1,10 @@ +// @ts-check + +/** + * createLogger - creates a logger function + * + * @param {string[]} pfx - logger prefix + */ const createLogger = pfx => { return { info: (...args) => console.info(...pfx, ...args), @@ -56,6 +63,9 @@ class RepaShader extends HTMLElement { this.attachShadow({ mode: 'open' }); this.logger = createLogger(["%c[repa-shader]", "background: #282828; color: #b8bb26"]); this._snippets = {}; + this._postProgram = null; + /** @type {WebGL2RenderingContext} */ + this._gl = null; } connectedCallback() { @@ -67,7 +77,7 @@ class RepaShader extends HTMLElement { if (!this._gl) { const glopts = {alpha: this.hasAttribute('alpha'), preserveDrawingBuffer: true}; - this._gl = this._target.getContext('webgl2', glopts); + this._gl = this._target.getContext('webgl2', glopts); // @ts-ignore if (!this._gl) { this.logger.error("WebGL2 not supported"); return; @@ -101,6 +111,12 @@ class RepaShader extends HTMLElement { // TODO stop animation } + /** + * render - loads the source if not provided and renders the shader + * + * @param {string} [source] - fragment shader source + * @param {Number} [time] - timestamp to render for + */ async render(source, time) { if (!source) { source = await this.getFragmentShaderSource(); @@ -109,6 +125,9 @@ class RepaShader extends HTMLElement { this.reset(time); } + /** + * @return {string} + */ get snippetPrefix() { if (this.hasAttribute('snippet-prefix')) { return this.getAttribute('snippet-prefix'); @@ -124,6 +143,11 @@ class RepaShader extends HTMLElement { return path + '/snippets'; } + /** + * loadSnippet - loads a snippet (prepending `snippetPrefix`) + * + * @param {string} name - snippet script name + */ async loadSnippet(name) { let url = name; if (!url.startsWith('http')) { @@ -139,6 +163,12 @@ class RepaShader extends HTMLElement { this._snippets[name] = text; } + /** + * getSnippet - returns a snippet (loading it if necessary) + * + * @param {string} name + * @return {string} - snippet source + */ async getSnippet(name) { if (!this._snippets[name]) { await this.loadSnippet(name); @@ -147,6 +177,11 @@ class RepaShader extends HTMLElement { return this._snippets[name]; } + /** + * _getSnippets - load all the snippets from the `snippets` attribute + * + * @return {} - resolves when all snippets are loaded + */ async _getSnippets() { if (!this.hasAttribute('snippets')) { return ''; @@ -158,6 +193,9 @@ class RepaShader extends HTMLElement { return await Promise.all(promises).then(snippets => snippets.join('\n')); } + /** + * _resizeTarget - resizes the current target (and the GL viewport) canvas based on its current size + */ _resizeTarget() { const {width, height} = this._target.getBoundingClientRect(); this._target.width = width; @@ -165,6 +203,11 @@ class RepaShader extends HTMLElement { this._gl.viewport(0, 0, width, height); } + /** + * _onOrientationEvent - handles orientation events + * + * @param {Event} e + */ _onOrientationEvent(e) { this._orientation = [e.alpha, e.beta, e.gamma]; } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0b7125b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "include": ["src/**/*"], + + "compilerOptions": { + "allowJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "dist", + "declarationMap": true, + "module": "ES2020", + "lib": ["ES2020", "DOM"] + } +} From 96f41ea6b310e7d5b3d108154817ca4c3838ac1f Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Fri, 31 Mar 2023 18:42:12 +0200 Subject: [PATCH 5/8] 3d texture from image --- TODO.md | 4 ++++ demo/3dt.html | 2 +- demo/3dt.png | Bin 0 -> 4148 bytes src/repa-texture.js | 6 +++--- 4 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 demo/3dt.png diff --git a/TODO.md b/TODO.md index 3047747..ca8ceb1 100644 --- a/TODO.md +++ b/TODO.md @@ -1,2 +1,6 @@ - fix mouse, add button, drag +- 3d texture + - format + - inner format + - data from external script diff --git a/demo/3dt.html b/demo/3dt.html index 428ecb0..8bdf00a 100644 --- a/demo/3dt.html +++ b/demo/3dt.html @@ -25,7 +25,7 @@ - + void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; vec3 col = texture(tex_avatar, uv).rgb; diff --git a/demo/3dt.png b/demo/3dt.png new file mode 100644 index 0000000000000000000000000000000000000000..c42bd6afa27cee094d1b621e8fdd2d20d933f055 GIT binary patch literal 4148 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 Wf9UYSp?8~jucvLK)u7?@{C@ysVfH-$ literal 0 HcmV?d00001 diff --git a/src/repa-texture.js b/src/repa-texture.js index ea65665..68ff306 100644 --- a/src/repa-texture.js +++ b/src/repa-texture.js @@ -352,15 +352,15 @@ class RepaTexture extends HTMLElement { } get width() { - return this._width || this.ref?.videoWidth || this.ref?.width || 0; + return +(this._width || this.getAttribute("width") || this.ref?.videoWidth || this.ref?.width || 0); } get height() { - return this._height || this.ref?.videoHeight || this.ref?.height || 0; + return +(this._height || this.getAttribute("height") || this.ref?.videoHeight || this.ref?.height || 0); } get depth() { - return this._depth || this.ref?.depth || 0; + return +(this._depth || this.getAttribute("depth") || this.ref?.depth || 0); } get magFilter() { From 0d5187a310beb63fab01d3b89646c68ebbdc70b5 Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Wed, 5 Apr 2023 14:01:47 +0200 Subject: [PATCH 6/8] texture content setting refactor, 3d shader example --- TODO.md | 2 ++ demo/3dt.fs | 44 ++++++++++++++++++++++++++++++++ demo/{index.html => simple.html} | 0 index.html | 19 ++++++++++++++ src/repa-shader.js | 1 - src/repa-texture.js | 19 +++++++------- 6 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 demo/3dt.fs rename demo/{index.html => simple.html} (100%) create mode 100644 index.html diff --git a/TODO.md b/TODO.md index ca8ceb1..43df663 100644 --- a/TODO.md +++ b/TODO.md @@ -4,3 +4,5 @@ - format - inner format - data from external script + +- jsdoc diff --git a/demo/3dt.fs b/demo/3dt.fs new file mode 100644 index 0000000..846e76e --- /dev/null +++ b/demo/3dt.fs @@ -0,0 +1,44 @@ +#define STEPSIZE .1 +#define DENSCALE .1 + +void main() { + // Compute the pixel's position in view space. + vec2 fragCoord = gl_FragCoord.xy / resolution.xy; + vec3 viewPos = vec3((fragCoord * 2.0 - 1.0), 0.5); + viewPos.y *= -1.0; // Flip Y axis to match WebGL convention. + + vec3 camPos = vec3(.5 + m.x * .5, .5 + m.y * .5, -.25); + vec3 camDir = vec3(1., 1., 1.); + + // Convert the pixel's position to world space. + vec3 worldPos = camPos + viewPos * length(camDir); + + // Compute the ray direction in world space. + vec3 rayDir = normalize(worldPos - camPos); + + // Initialize the color and transparency values. + vec4 color = vec4(0.0); + float alpha = 0.0; + + // Perform the ray-marching loop. + for (float t = 0.0; t < 2.0; t += STEPSIZE) { + // Compute the position along the ray. + vec3 pos = camPos + rayDir * t; + + // Sample the density at the current position. + float density = texture(test3d, pos).x * DENSCALE; + + // Accumulate the color and transparency values. + vec4 sampleColor = vec4(1.0, 0.5, 0.2, 1.0); + color += (1.0 - alpha) * sampleColor * density; + alpha += (1.0 - alpha) * density; + + // Stop marching if the transparency reaches 1.0. + if (alpha >= 1.0) { + break; + } + } + + // Output the final color and transparency. + o = vec4(color.rgb, alpha); +} diff --git a/demo/index.html b/demo/simple.html similarity index 100% rename from demo/index.html rename to demo/simple.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..df5abde --- /dev/null +++ b/index.html @@ -0,0 +1,19 @@ + + + + + <repa-shader> demo + + +

repa-shader demos

+ + + diff --git a/src/repa-shader.js b/src/repa-shader.js index 0e58208..e584e41 100644 --- a/src/repa-shader.js +++ b/src/repa-shader.js @@ -383,7 +383,6 @@ class RepaShader extends HTMLElement { const msg = this._gl.getProgramInfoLog(program); this.logger.error("Program link error: ", msg); // TODO error callback - program = null; return; } diff --git a/src/repa-texture.js b/src/repa-texture.js index 68ff306..b716750 100644 --- a/src/repa-texture.js +++ b/src/repa-texture.js @@ -85,7 +85,7 @@ class RepaTexture extends HTMLElement { this.ready = true; this._forceUpdate = true; } else if (this.textContent) { - this.content = JSON.parse(this.textContent); + this.simpleContent(JSON.parse(this.textContent)); } else if (this.t3d) { // TODO 3d texture experiment let size = 32; this._width = size; @@ -241,23 +241,24 @@ class RepaTexture extends HTMLElement { return !this.t3d && this.type !== 'raw'; } - setContent(data) { + simpleContent(data) { + this._format = 'luminance'; this._width = data[0].length; this._height = data.length; - this._content = new Uint8Array(this._width * this._height); + const content = new Uint8Array(this._width * this._height); data.forEach((row, y) => { - this._content.set(row, y * this._width); + content.set(row, y * this._width); }); + + this.content = content; } set content(data) { this.ready = true; - this._type = 'raw'; - this._format = 'luminance'; this._forceUpdate = true; - this.setContent(data); + this._content = data; } get content() { @@ -306,9 +307,9 @@ class RepaTexture extends HTMLElement { analyser.getByteFrequencyData(this._freqData); analyser.getByteTimeDomainData(this._timeData); - this.setContent([this._freqData, this._timeData]); + this.simpleContent([this._freqData, this._timeData]); } else { - this.setContent([[255, 128, 64, 32, 16, 8, 4, 2], [2, 4, 8, 16, 32, 64, 128, 255]]); + this.simpleContent([[255, 128, 64, 32, 16, 8, 4, 2], [2, 4, 8, 16, 32, 64, 128, 255]]); } return this._content; From 731d783e0bc79ac00847138f5452a57a53e1776b Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Wed, 5 Apr 2023 15:39:39 +0200 Subject: [PATCH 7/8] generated texture example --- demo/3dt.html | 22 ++++++++++++++++++++++ src/repa-shader.js | 14 ++++++++++++-- src/repa-texture.js | 31 +++++++++---------------------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/demo/3dt.html b/demo/3dt.html index 8bdf00a..879078d 100644 --- a/demo/3dt.html +++ b/demo/3dt.html @@ -26,11 +26,13 @@ + void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; vec3 col = texture(tex_avatar, uv).rgb; col *= texture(test3d, vec3(uv.xy, mouse.x)).rrr; + col *= texture(generated, vec3(uv.xy, mouse.y)).rgb; float dist = distance(uv, mouse.xy); float circle = smoothstep(.025, .026, dist) * .5 + .5; @@ -49,6 +51,26 @@ updateButton.addEventListener('click', () => { const shader = document.querySelector('repa-shader'); shader.render(fsinput.value); }); + +setTimeout(() => { + // generate texture data + const generated3DT = document.querySelector('repa-texture[name="generated"]'); + const size = 32; + const t3data = new Uint8Array(size * size * size * 4); + for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + for (let k = 0; k < size; k++) { + let index = i * size * size + j * size + k; + t3data[index*4] = i * 4 % 255; + t3data[index*4+1] = j * 4 % 255; + t3data[index*4+2] = k * 4 % 255; + t3data[index*4+3] = 255; + } + } + } + + generated3DT.content = t3data; +}, 100); diff --git a/src/repa-shader.js b/src/repa-shader.js index e584e41..0b89058 100644 --- a/src/repa-shader.js +++ b/src/repa-shader.js @@ -304,6 +304,10 @@ class RepaShader extends HTMLElement { return (format && this._gl[format.toUpperCase().replaceAll('-', '_')]) || this._gl.RGBA; } + _getType(type) { + return (type && this._gl[type.toUpperCase().replaceAll('-', '_')]) || this._gl.UNSIGNED_BYTE; + } + _collectTextures() { this._textures = []; this._textures3d = []; @@ -464,9 +468,12 @@ class RepaShader extends HTMLElement { // update if needed if (t.texElement.shouldUpdate) { const format = this._getFormat(t.texElement.format); + const internalFormat = this._getFormat(t.texElement.internalFormat); + const type = this._getType(t.texElement.dataType); + this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, t.texElement.flipY); - this._gl.texImage2D(this._gl.TEXTURE_2D, 0, format, t.texElement.width, t.texElement.height, 0, format, this._gl.UNSIGNED_BYTE, t.texElement.update()); + this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalFormat, t.texElement.width, t.texElement.height, 0, format, type, t.texElement.update()); } this._gl.uniform1i(this._uniLocation[t.texElement.name], i + this.mrt); @@ -480,9 +487,12 @@ class RepaShader extends HTMLElement { // update if needed if (t.texElement.shouldUpdate) { const format = this._getFormat(t.texElement.format); + const internalFormat = this._getFormat(t.texElement.internalFormat); + const type = this._getType(t.texElement.dataType); + this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, 0); - this._gl.texImage3D(this._gl.TEXTURE_3D, 0, format, t.texElement.width, t.texElement.height, t.texElement.depth, 0, format, this._gl.UNSIGNED_BYTE, t.texElement.update()); + this._gl.texImage3D(this._gl.TEXTURE_3D, 0, internalFormat, t.texElement.width, t.texElement.height, t.texElement.depth, 0, format, type, t.texElement.update()); } this._gl.uniform1i(this._uniLocation[t.texElement.name], i + this.mrt + this._textures.length); diff --git a/src/repa-texture.js b/src/repa-texture.js index b716750..38040cf 100644 --- a/src/repa-texture.js +++ b/src/repa-texture.js @@ -86,29 +86,8 @@ class RepaTexture extends HTMLElement { this._forceUpdate = true; } else if (this.textContent) { this.simpleContent(JSON.parse(this.textContent)); - } else if (this.t3d) { // TODO 3d texture experiment - let size = 32; - this._width = size; - this._height = size; - this._depth = size; - - let t3data = new Uint8Array(size * size * size); - - for (let i = 0; i < size; i++) { - for (let j = 0; j < size; j++) { - for (let k = 0; k < size; k++) { - let index = i * size * size + j * size + k; - t3data[index] = (i * j * k) % 255; - } - } - } - - this._content = t3data; - this._forceUpdate = true; - this._format = 'luminance'; - this.ready = true; } else { - this.logger.error('Texture content cannot be loaded!'); + this.logger.warn('Texture content cannot be loaded!'); } } @@ -388,6 +367,14 @@ class RepaTexture extends HTMLElement { return this._format || this.getAttribute('format') || 'rgba'; } + get internalFormat() { + return this._internalFormat || this.getAttribute('internal-format') || this.format; + } + + get dataType() { + return this._dataType || this.getAttribute('data-type') || 'unsigned-byte'; + } + get name() { if (!this._name) { let name = this.getAttribute('name'); From a6b7df05414a04b61b2b6d298016c5534ca23f46 Mon Sep 17 00:00:00 2001 From: Gyuri Horak Date: Wed, 5 Apr 2023 15:42:55 +0200 Subject: [PATCH 8/8] todo update --- TODO.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/TODO.md b/TODO.md index 43df663..7429db2 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,2 @@ - fix mouse, add button, drag - -- 3d texture - - format - - inner format - - data from external script - - jsdoc