Hi, I’ve been trying to research around but still could not figure out what in my code is preventing the images to act like ‘background-size:cover’
Codepen link: https://codepen.io/vchoo/pen/OJGMXaZ
<!--- IMAGESLOADED --->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.4/imagesloaded.pkgd.js"></script>
<script>
function cover( texture, aspect ) {
var imageAspect = texture.image.width / texture.image.height;
var scaleX = 1;
var scaleY = 1;
console.log("Cover function:", texture.image.width);
if (aspect > imageAspect) {
// Canvas aspect ratio is wider than image aspect ratio
scaleX = aspect / imageAspect;
} else {
// Canvas aspect ratio is taller than or equal to image aspect ratio
scaleY = imageAspect / aspect;
}
texture.offset.set(0.5 * (1 - scaleX), 0.5 * (1 - scaleY));
texture.repeat.set(scaleX, scaleY);
}
const displacementSlider = function(opts) {
let vertex = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`;
let fragment = `
varying vec2 vUv;
uniform sampler2D currentImage;
uniform sampler2D nextImage;
uniform float dispFactor;
void main() {
vec2 uv = vUv;
vec4 _currentImage;
vec4 _nextImage;
float intensity = 0.3;
vec4 orig1 = texture2D(currentImage, uv);
vec4 orig2 = texture2D(nextImage, uv);
_currentImage = texture2D(currentImage, vec2(uv.x, uv.y + dispFactor * (orig2 * intensity)));
_nextImage = texture2D(nextImage, vec2(uv.x, uv.y + (1.0 - dispFactor) * (orig1 * intensity)));
vec4 finalTexture = mix(_currentImage, _nextImage, dispFactor);
gl_FragColor = finalTexture;
}
`;
let images = opts.images, image, sliderImages = [];
let parent = opts.parent;
let sizes = {
w: window.innerWidth,
h: window.innerHeight
};
let canvasWidth = sizes.w;
let canvasHeight = sizes.h;
let renderWidth = images[0].clientWidth;
let renderHeight = images[0].clientHeight;
let renderer = new THREE.WebGLRenderer({
antialias: false,
});
let camera = new THREE.OrthographicCamera(
renderWidth / -2,
renderWidth / 2,
renderHeight / 2,
renderHeight / -2,
1,
1000
);
let scene = new THREE.Scene();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setClearColor( 0x23272A, 1.0 );
renderer.setSize( renderWidth, renderHeight );
parent.appendChild( renderer.domElement );
let loader = new THREE.TextureLoader();
loader.crossOrigin = "anonymous";
let imageTextures = [];
images.forEach( ( img ) => {
let imageTexture = loader.load( img.getAttribute( 'src' ) + '?v=' + Date.now(), (texture) => {
console.log("Image loaded:", imageTexture);
cover( texture, canvasWidth / canvasHeight );
scene.background = texture;
} );
imageTexture.magFilter = imageTexture.minFilter = THREE.LinearFilter;
imageTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
sliderImages.push( imageTexture );
imageTextures.push(imageTexture);
});
camera.position.z = 1;
let mat = new THREE.ShaderMaterial({
uniforms: {
dispFactor: { type: "f", value: 0.0 },
currentImage: { type: "t", value: sliderImages[0] },
nextImage: { type: "t", value: sliderImages[1] },
},
vertexShader: vertex,
fragmentShader: fragment,
transparent: true,
opacity: 1.0
});
let aspectRatioCanvas = renderWidth / renderHeight;
let aspectRatioImage = images[0].width / images[0].height;
let scaleWidth = 1;
let scaleHeight = 1;
if (aspectRatioImage > aspectRatioCanvas) {
scaleWidth = aspectRatioImage / aspectRatioCanvas;
} else {
scaleHeight = aspectRatioCanvas / aspectRatioImage;
}
let geometry = new THREE.PlaneBufferGeometry(
renderWidth * scaleWidth,
renderHeight * scaleHeight,
1
);
let object = new THREE.Mesh(geometry, mat);
object.position.set(0, 0, 0);
scene.add(object);
let addEvents = function(){
let pagButtons = Array.from(document.getElementById('pagination').querySelectorAll('a'));
let isAnimating = false;
pagButtons.forEach( (el) => {
el.addEventListener('mouseenter', function() {
if( !isAnimating ) {
isAnimating = true;
document.getElementById('pagination').querySelectorAll('.active')[0].className = '';
this.className = 'active';
let slideId = parseInt( this.dataset.slide, 10 );
mat.uniforms.nextImage.value = sliderImages[slideId];
mat.uniforms.nextImage.needsUpdate = true;
TweenLite.to( mat.uniforms.dispFactor, 1, {
value: 1,
ease: 'Expo.easeInOut',
onComplete: function () {
mat.uniforms.currentImage.value = sliderImages[slideId];
mat.uniforms.currentImage.needsUpdate = true;
mat.uniforms.dispFactor.value = 0.0;
isAnimating = false;
}
});
let slideStatusEl = document.getElementById('slide-status');
let nextSlideStatus = document.querySelectorAll(`[data-slide-status="${slideId}"]`)[0].innerHTML;
TweenLite.fromTo( slideStatusEl, 0.5,
{
autoAlpha: 1,
y: 0
},
{
autoAlpha: 0,
y: 20,
ease: 'Expo.easeIn',
onComplete: function () {
slideStatusEl.innerHTML = nextSlideStatus;
TweenLite.to( slideStatusEl, 0.5, {
autoAlpha: 1,
y: 0,
delay: 0.1,
})
}
});
}
});
});
};
addEvents();
window.addEventListener( 'resize' , function(e) {
var aspect = window.innerWidth / window.innerHeight;
camera.aspect = aspect;
camera.updateProjectionMatrix();
imageTextures.forEach(function(texture) {
cover(texture, aspect);
});
renderer.setSize( window.innerWidth, window.innerHeight );
});
let animate = function() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
};
imagesLoaded( document.querySelectorAll('img'), () => {
// document.body.classList.remove('loading');
const el = document.getElementById('slider');
const imgs = Array.from(el.querySelectorAll('img'));
new displacementSlider({
parent: el,
images: imgs
});
});
</script>
I’m using vanilla JS, no framework involved
Appreciate your help in advance!
Edit: I visited possible solutions but pretty much all are working with perspective camera.
Is there a way to integrate with orthographic camera?
I also suspect the THREE.PlaneBufferGeometry
has something to do with the issue, but I’m new to three.js