I am following the pixel distortion effect https://tympanus.net/Development/DistortedPixels/. But screens with less than certain screen size, my texture is not visible, don’t know why ? And this screen size limit increases as I enhance my image size taken. I think the issue is in texture2D in fragment shaders because if I just put any vec4 color, then the plane is visible for all screen sizes. Also weird thing is that if I resize, then it is visible for all screen sizes. But if I reload the page with screen size less than limit, then it is not visible at all. Below is my code. Any help is appreciated
import * as THREE from "three";
const fragment = `
uniform float time;
uniform float progress;
uniform sampler2D uDataTexture;
uniform sampler2D uTexture;
uniform vec4 resolution;
varying vec2 vUv;
varying vec3 vPosition;
float PI = 3.141592653589793238;
void main() {
vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
vec4 color = texture2D(uTexture,newUV);
vec4 offset = texture2D(uDataTexture,vUv);
// gl_FragColor = vec4(vUv,0.0,1.);
gl_FragColor = texture2D(uTexture,newUV - 0.02*offset.rg);
}
`;
const vertex = `
uniform float time;
varying vec2 vUv;
varying vec3 vPosition;
uniform vec2 pixels;
float PI = 3.141592653589793238;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`;
function clamp(number, min, max) {
return Math.max(min, Math.min(number, max));
}
export default class Sketch {
constructor(options) {
this.scene = new THREE.Scene();
this.container = options.dom;
this.img = this.container.querySelector("img");
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.width, this.height);
this.renderer.setClearColor(0xffffff, 0);
this.renderer.physicallyCorrectLights = true;
this.renderer.domElement.style.position = "absolute";
this.renderer.domElement.style.top = "0";
this.renderer.domElement.style.left = "0";
this.container.appendChild(this.renderer.domElement);
var frustumSize = 1;
var aspect = window.innerWidth / window.innerHeight;
this.camera = new THREE.OrthographicCamera(
frustumSize / -2,
frustumSize / 2,
frustumSize / 2,
frustumSize / -2,
-1000,
1000
);
// this.camera = new THREE.PerspectiveCamera(
// 75,
// this.width / this.height,
// 0.1,
// 1000
// );
// this.controls = new OrbitControls(this.camera, this.renderer.domElement);
// this.controls.update();
this.camera.position.set(0, 0, 0.75);
this.time = 0;
this.mouse = {
x: 0,
y: 0,
prevX: 0,
prevY: 0,
vX: 0,
vY: 0,
};
this.isPlaying = true;
this.settings();
this.addObjects();
this.resize();
this.render();
this.setupResize();
this.mouseEvents();
}
getValue(val) {
return parseFloat(this.container.getAttribute("data-" + val));
}
mouseEvents() {
window.addEventListener("mousemove", (e) => {
this.mouse.x = e.clientX / this.width;
this.mouse.y = e.clientY / this.height;
this.mouse.vX = this.mouse.x - this.mouse.prevX;
this.mouse.vY = this.mouse.y - this.mouse.prevY;
this.mouse.prevX = this.mouse.x;
this.mouse.prevY = this.mouse.y;
});
}
settings() {
let that = this;
this.settings = {
grid: this.getValue("grid") || 34,
mouse: this.getValue("mouse") || 0.25,
strength: this.getValue("strength") || 1,
relaxation: this.getValue("relaxation") || 0.9,
};
}
setupResize() {
window.addEventListener("resize", this.resize.bind(this));
}
resize() {
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer.setSize(this.width, this.height);
this.camera.aspect = this.width / this.height;
// image cover
this.imageAspect = 1 / 1.5;
let a1;
let a2;
if (this.height / this.width > this.imageAspect) {
a1 = (this.width / this.height) * this.imageAspect;
a2 = 1;
} else {
a1 = 1;
a2 = this.height / this.width / this.imageAspect;
}
this.material.uniforms.resolution.value.x = this.width;
this.material.uniforms.resolution.value.y = this.height;
this.material.uniforms.resolution.value.z = a1;
this.material.uniforms.resolution.value.w = a2;
this.camera.updateProjectionMatrix();
this.regenerateGrid();
}
regenerateGrid() {
this.size = this.settings.grid;
const width = this.size;
const height = this.size;
const size = width * height;
const data = new Float32Array(3 * size);
const color = new THREE.Color(0xffffff);
const r = Math.floor(color.r * 255);
const g = Math.floor(color.g * 255);
const b = Math.floor(color.b * 255);
for (let i = 0; i < size; i++) {
let r = Math.random() * 255 - 125;
let r1 = Math.random() * 255 - 125;
const stride = i * 3;
data[stride] = r;
data[stride + 1] = r1;
data[stride + 2] = r;
}
this.texture = new THREE.DataTexture(
data,
width,
height,
THREE.RGBFormat,
THREE.FloatType
);
this.texture.magFilter = this.texture.minFilter = THREE.NearestFilter;
if (this.material) {
this.material.uniforms.uDataTexture.value = this.texture;
this.material.uniforms.uDataTexture.value.needsUpdate = true;
}
}
addObjects() {
this.regenerateGrid();
let texture = new THREE.Texture(this.img);
texture.needsUpdate = true;
this.material = new THREE.ShaderMaterial({
extensions: {
derivatives: "#extension GL_OES_standard_derivatives : enable",
},
side: THREE.DoubleSide,
uniforms: {
time: {
value: 0,
},
resolution: {
value: new THREE.Vector4(),
},
uTexture: {
value: texture,
},
uDataTexture: {
value: this.texture,
},
},
vertexShader: vertex,
fragmentShader: fragment,
});
this.geometry = new THREE.PlaneGeometry(0.53, 0.44, 1, 1);
this.plane = new THREE.Mesh(this.geometry, this.material);
this.plane.material.side = THREE.DoubleSide;
this.plane.position.set(0, -0.09, 0);
this.scene.add(this.plane);
}
updateDataTexture() {
let data = this.texture.image.data;
for (let i = 0; i < data.length; i += 3) {
data[i] *= this.settings.relaxation;
data[i + 1] *= this.settings.relaxation;
}
let gridMouseX = this.size * this.mouse.x;
let gridMouseY = this.size * (1 - this.mouse.y);
let maxDist = this.size * this.settings.mouse;
let aspect = this.height / this.width;
for (let i = 0; i < this.size; i++) {
for (let j = 0; j < this.size; j++) {
let distance = (gridMouseX - i) ** 2 / aspect + (gridMouseY - j) ** 2;
let maxDistSq = maxDist ** 1.25;
if (distance < maxDistSq) {
let index = 3 * (i + this.size * j);
let power = (maxDist * 1.5) / Math.sqrt(distance);
power = clamp(power, 0, 10);
data[index] += this.settings.strength * 100 * this.mouse.vX * power;
data[index + 1] -=
this.settings.strength * 100 * this.mouse.vY * power;
}
}
}
this.mouse.vX *= 0.9;
this.mouse.vY *= 0.9;
this.texture.needsUpdate = true;
}
render() {
if (!this.isPlaying || this.container.offsetWidth <= 1240) {
if (this.container.contains(this.renderer.domElement)) {
this.container.removeChild(this.renderer.domElement);
}
return;
}
this.time += 0.05;
this.updateDataTexture();
this.material.uniforms.time.value = this.time;
requestAnimationFrame(this.render.bind(this));
this.renderer.render(this.scene, this.camera);
}
}
<div
className="w-full h-full absolute top-0 -z-[1] left-0 bg-cover bg-fixed"
style={{
backgroundColor: "#000",
backgroundImage: "url(/background.png)",
}}
id="canvasContainer"
ref={containerRef}
data-grid="30"
data-mouse="0.25"
data-strength="0.18"
>
<img
src="/hackbyte11.png"
alt="HackByte Logo"
id="hackbyteLogo"
className="invisible absolute"
/>
</div>