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'; }