Hey everyone,
I’m facing a challenging issue and could really use some assistance. I’m trying to load an EXR file into my shader, following what I believe to be the standard implementation procedure. However, whenever I run my project, the browser hangs, and there’s no output in the console whatsoever.
Any insights or suggestions would be greatly appreciated. Thanks in advance for your help!
import * as THREE from "three";
import GSAP from "gsap";
import Animations from "./Animations";
import SmoothScroll from "./SmoothScroll";
import vertexShader from "./shaders/vertex.glsl";
import fragmentShader from "./shaders/fragment.glsl";
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
/* import { EXRLoader } from "https://threejs.org/examples/jsm/loaders/EXRLoader.js" */
class ScrollStage {
constructor() {
this.element = document.querySelector(".content");
this.elements = {
line: this.element.querySelector(".layout__line"),
exrTexture: { value: new THREE.DataTexture() }
};
this.time = 0;
this.viewport = {
width: window.innerWidth,
height: window.innerHeight,
};
this.mouse = {
x: 0,
y: 0,
};
this.scroll = {
height: 0,
limit: 0,
hard: 0,
soft: 0,
ease: 0.05,
normalized: 0,
running: false,
};
this.settings = {
// vertex
uFrequency: {
start: 0,
end: 3,
},
uAmplitude: {
start: 4,
end: 4,
},
uDensity: {
start: 1,
end: 1,
},
uStrength: {
start: 0,
end: 1.1,
},
// fragment
uDeepPurple: {
// max 1
start: 1,
end: 0,
},
uOpacity: {
// max 1
start: 0.1,
end: 0.66,
},
};
this.scene = new THREE.Scene();
this.renderer = new THREE.WebGLRenderer({
canvas: document.querySelector("#webgl"),
antialias: true,
alpha: true,
});
this.canvas = 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.clock = new THREE.Clock();
this.smoothScroll = new SmoothScroll({
element: this.element,
viewport: this.viewport,
scroll: this.scroll,
});
GSAP.defaults({
ease: "power2",
duration: 6.6,
overwrite: true,
});
this.updateScrollAnimations = this.updateScrollAnimations.bind(this);
this.update = this.update.bind(this);
this.init();
}
init() {
// Load EXR texture
const exrLoader = new EXRLoader();
exrLoader.load('/env.exr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
this.elements.exrTexture.value = texture;
console.log("EXR texture loaded successfully!");
}, undefined, (error) => {
console.error("Error loading EXR texture:", error);
});
this.addCamera();
this.addMesh();
this.addEventListeners();
this.onResize();
this.update();
}
addCamera() {
this.camera.position.set(0, 0, 2.5);
this.scene.add(this.camera);
}
addMesh() {
this.geometry = new THREE.PlaneGeometry(1, 1, 1, 1);
this.material = new THREE.ShaderMaterial({
blending: THREE.AdditiveBlending,
transparent: true,
vertexShader,
fragmentShader,
uniforms: {
uFrequency: { value: this.settings.uFrequency.start },
uAmplitude: { value: this.settings.uAmplitude.start },
uDensity: { value: this.settings.uDensity.start },
uStrength: { value: this.settings.uStrength.start },
uDeepPurple: { value: this.settings.uDeepPurple.start },
uOpacity: { value: this.settings.uOpacity.start },
uResX: { value: this.viewport.width },
uResY: { value: this.viewport.height },
uTime: { value: this.time },
uScroll: { value: this.scroll.normalized },
uAspect: { type: "v2", value: new THREE.Vector2() },
exrTexture: this.elements.exrTexture
},
});
this.plane = new THREE.Mesh(this.geometry, this.material);
this.scene.add(this.plane);
}
/**
* SCROLL BASED ANIMATIONS
*/
updateScrollAnimations() {
this.scroll.running = false;
this.scroll.normalized = (this.scroll.hard / this.scroll.limit).toFixed(1);
this.material.uniforms.uScroll.value = this.scroll.normalized;
console.info(`Scroll position: ${this.scroll.normalized}`);
/* GSAP.to(this.plane.rotation, {
x: this.scroll.normalized * Math.PI,
}); */
GSAP.to(this.elements.line, {
scaleX: this.scroll.normalized,
transformOrigin: "left",
duration: 1.5,
ease: "ease",
});
for (const key in this.settings) {
if (this.settings[key].start !== this.settings[key].end) {
GSAP.to(this.plane.material.uniforms[key], {
value:
this.settings[key].start +
this.scroll.normalized *
(this.settings[key].end - this.settings[key].start),
});
}
}
}
/**
* EVENTS
*/
addEventListeners() {
window.addEventListener("load", this.onLoad.bind(this));
window.addEventListener("scroll", this.onScroll.bind(this));
window.addEventListener("resize", this.onResize.bind(this));
}
onLoad() {
document.body.classList.remove("loading");
this.animations = new Animations(this.element, this.camera);
}
onMouseMove(event) {
// play with it!
// enable / disable / change x, y, multiplier …
this.mouse.x = (event.clientX / this.viewport.width).toFixed(2) * 4;
this.mouse.y = (event.clientY / this.viewport.height).toFixed(2) * 2;
GSAP.to(this.plane.material.uniforms.uFrequency, { value: this.mouse.x });
GSAP.to(this.plane.material.uniforms.uAmplitude, { value: this.mouse.x });
GSAP.to(this.plane.material.uniforms.uDensity, { value: this.mouse.y });
GSAP.to(this.plane.material.uniforms.uStrength, { value: this.mouse.y });
// GSAP.to(this.plane.material.uniforms.uDeepPurple, { value: this.mouse.x })
// GSAP.to(this.plane.material.uniforms.uOpacity, { value: this.mouse.y })
console.info(`X: ${this.mouse.x} | Y: ${this.mouse.y}`);
}
printSettings(settings) {
//console.log("uFrequency:", settings.uFrequency.start);
/* console.log("uAmplitude:", settings.uAmplitude);
console.log("uDensity:", settings.uDensity);
console.log("uStrength:", settings.uStrength);
console.log("uDeepPurple:", settings.uDeepPurple);
console.log("uOpacity:", settings.uOpacity); */
}
onScroll() {
if (!this.scroll.running) {
window.requestAnimationFrame(this.updateScrollAnimations);
this.scroll.running = true;
}
}
onResize() {
this.viewport.width = window.innerWidth;
this.viewport.height = window.innerHeight;
this.smoothScroll.onResize();
const imageAspect = 1; // Set the desired image aspect ratio
const viewportRatio = this.viewport.width / this.viewport.height;
let a1, a2;
if (viewportRatio > imageAspect) {
a1 = imageAspect / viewportRatio;
a2 = 1;
} else {
a1 = 1;
a2 = viewportRatio / imageAspect;
}
this.camera.aspect = this.viewport.width / this.viewport.height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.viewport.width, this.viewport.height);
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
this.material.uniforms.uResX.value = this.viewport.width;
this.material.uniforms.uResY.value = this.viewport.height;
this.material.uniforms.uAspect.value.x = a1;
this.material.uniforms.uAspect.value.y = a2;
//console.log(`${this.viewport.width}/${this.viewport.height}`);
}
/**
* LOOP
*/
update() {
const elapsedTime = this.clock.getElapsedTime();
/* this.plane.rotation.y = elapsedTime * 0.05; */
this.smoothScroll.update();
this.render();
window.requestAnimationFrame(this.update);
}
/**
* RENDER
*/
render() {
this.printSettings(this.settings);
this.time += 0.05;
this.material.uniforms.uTime.value = this.time;
this.renderer.render(this.scene, this.camera);
}
}
new ScrollStage();