Creating a 3D Slideshow with Three.js

Photo by Annie Spratt on Unsplash

<script src=”https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js" integrity=”sha512-dLxUelApnYxpLt6K2iomGngnHO83iUvZytA3YjDUCjT0HDOHKXnVYdf3hU4JjM8uEhxf9nD1/ey98U3t2vZ0qQ==” crossorigin=”anonymous” referrerpolicy=”no-referrer”></script>

<script src=”https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js" integrity=”sha512-lIKG1kC5TMb1Zx32vdz1n31YJMZRknVY20U9MJ28hD3y2c0OKN0Ce5NhJji78v8zX5UOSsm+MTBOcJt7yMBnSg==” crossorigin=”anonymous” referrerpolicy=”no-referrer”></script>

<script>

// Creating Necessary Instances and Initializations

/**

* Sizes

*/

const sizes = {

width: window.innerWidth,

height: window.innerHeight,

};

const root = document.getElementById(“app”);

var renderer = new THREE.WebGLRenderer({ alpha: true });

renderer.setSize(sizes.width, sizes.height);

root.appendChild(renderer.domElement);

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(

75,

sizes.width / sizes.height,

0.1,

1000

);

camera.position.z = 10;

// const interactionManager = new InteractionManager(

// renderer,

// camera,

// renderer.domElement

// );

const loader = new THREE.TextureLoader();

let activeImage = 0;

</script>

function createPlaneWTexture(h, w, texture, x, y, z){

const geometry = new THREE.PlaneGeometry( h, w );

const material = new THREE.MeshBasicMaterial( {map: texture} );

const mesh = new THREE.Mesh( geometry, material );

mesh.position.x = x;

mesh.position.y = y;

mesh.position.z = z;

return mesh;

}

const images = {

p1: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1628191081071-a2b761bf21d9"), 0, 0, 0),

p2: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1606787620819-8bdf0c44c293"), -1, -5, 0),

p3: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1518811829466-1372392d4544"), 2, 2, 0),

p4: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1578763918454-d0deb5469071"), -5, 5, 0),

}

Object.keys(images).forEach(key => {

scene.add(images[key])

})

function animate(callback) {

function loop(time) {

callback(time);

requestAnimationFrame(loop);

}

requestAnimationFrame(loop);

}

animate((time) => {

renderer.render(scene, camera);

});

function TweenScaleTo(objMesh, w, h) {

const scale = {

w: objMesh.geometry.parameters.width,

h: objMesh.geometry.parameters.height,

};

new TWEEN.Tween(scale)

.to({ w: w, h: h })

.easing(TWEEN.Easing.Quadratic.InOut)

.onUpdate(() => {

objMesh.geometry = new THREE.PlaneGeometry(scale.w, scale.h);

})

.start();

}

function cameraTo(x, y, z) {

const coords = {

x: camera.position.x,

y: camera.position.y,

z: camera.position.z,

};

new TWEEN.Tween(coords)

.to({ x: x, y: y, z: z + 2 })

.easing(TWEEN.Easing.Quadratic.Out)

.onUpdate(() => camera.position.set(coords.x, coords.y, coords.z))

.start();

}

function resetImages(images, except) {

Object.keys(images).forEach((key) => {

if (key !== except) {

TweenScaleTo(images[key], 1.6, 0.9);

}

});

}

let seconds = 0;

function makeZoomAccordingToActive(active) {

switch (active) {

case 0:

resetImages(images, “p1”);

TweenScaleTo(images.p1, 16, 9);

cameraTo(images.p1.position.x, images.p1.position.y, images.p1.position.z + 8);

break;

case 1:

resetImages(images, “p2”);

TweenScaleTo(images.p2, 16, 9);

cameraTo(images.p2.position.x, images.p2.position.y, images.p2.position.z + 8);

break;

case 2:

resetImages(images, “p3”);

TweenScaleTo(images.p3, 16, 9);

cameraTo(images.p3.position.x, images.p3.position.y, images.p3.position.z + 8);

break;

case 3:

resetImages(images, “p4”);

TweenScaleTo(images.p4, 16, 9);

cameraTo(images.p4.position.x, images.p4.position.y, images.p4.position.z + 8);

break;

default:

resetImages(images, “p”)

cameraTo(0, 0, 10);

}

}

function checkSeconds() {

seconds += 1;

if (seconds > 5) {

seconds = 0;

if (activeImage + 1 > 4) {

activeImage = 0;

} else {

activeImage += 1;

}

makeZoomAccordingToActive(activeImage)

}

}

setInterval(checkSeconds, 1000);

<!DOCTYPE html>

<html lang=”en”>

<head>

<meta charset=”UTF-8">

<meta http-equiv=”X-UA-Compatible” content=”IE=edge”>

<meta name=”viewport” content=”width=device-width, initial-scale=1.0">

<title>Three JS Gallery</title>

</head>

<body style=”background-color: black;”>

<div id=”app”></div>

<script

src=”https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"

integrity=”sha512-dLxUelApnYxpLt6K2iomGngnHO83iUvZytA3YjDUCjT0HDOHKXnVYdf3hU4JjM8uEhxf9nD1/ey98U3t2vZ0qQ==”crossorigin=”anonymous”

referrerpolicy=”no-referrer”></script>

<script

src=”https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js"

integrity=”sha512-lIKG1kC5TMb1Zx32vdz1n31YJMZRknVY20U9MJ28hD3y2c0OKN0Ce5NhJji78v8zX5UOSsm+MTBOcJt7yMBnSg==”crossorigin=”anonymous”

referrerpolicy=”no-referrer”></script>

<script>

// Creating Necessary Instances and Initializations

/**

* Sizes

*/

const sizes = {

width: window.innerWidth,

height: window.innerHeight,

};

const root = document.getElementById(“app”);

var renderer = new THREE.WebGLRenderer({ alpha: true });

renderer.setSize(sizes.width, sizes.height);

root.appendChild(renderer.domElement);

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(

75,

sizes.width / sizes.height,

0.1,

1000

);

camera.position.z = 10;

const loader = new THREE.TextureLoader();

let activeImage = 0;

function createPlaneWTexture(h, w, texture, x, y, z){

const geometry = new THREE.PlaneGeometry( h, w );

const material = new THREE.MeshBasicMaterial( {map: texture} );

const mesh = new THREE.Mesh( geometry, material );

mesh.position.x = x;

mesh.position.y = y;

mesh.position.z = z;

return mesh;

}

const images = {

p1: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1628191081071-a2b761bf21d9"), 0, 0, 0),

p2: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1606787620819-8bdf0c44c293"), -1, -5, 0),

p3: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1518811829466-1372392d4544"), 2, 2, 0),

p4: createPlaneWTexture(1.6, 0.9, loader.load(“https://images.unsplash.com/photo-1578763918454-d0deb5469071"), -5, 5, 0),

}

Object.keys(images).forEach(key => {

scene.add(images[key])

})

function TweenScaleTo(objMesh, w, h) {

const scale = {

w: objMesh.geometry.parameters.width,

h: objMesh.geometry.parameters.height,

};

new TWEEN.Tween(scale)

.to({ w: w, h: h })

.easing(TWEEN.Easing.Quadratic.InOut)

.onUpdate(() => {

objMesh.geometry = new THREE.PlaneGeometry(scale.w, scale.h);

})

.start();

}

function cameraTo(x, y, z) {

const coords = {

x: camera.position.x,

y: camera.position.y,

z: camera.position.z,

};

new TWEEN.Tween(coords)

.to({ x: x, y: y, z: z + 2 })

.easing(TWEEN.Easing.Quadratic.Out)

.onUpdate(() => camera.position.set(coords.x, coords.y, coords.z))

.start();

}

function resetImages(images, except) {

Object.keys(images).forEach((key) => {

if (key !== except) {

TweenScaleTo(images[key], 1.6, 0.9);

}

});

}

function animate(callback) {

function loop(time) {

callback(time);

requestAnimationFrame(loop);

}

requestAnimationFrame(loop);

}

animate((time) => {

renderer.render(scene, camera);

TWEEN.update(time);

});

// Helper to auto zoom and Focus Images

let seconds = 0;

function makeZoomAccordingToActive(active) {

switch (active) {

case 0:

resetImages(images, “p1”);

TweenScaleTo(images.p1, 16, 9);

cameraTo(images.p1.position.x, images.p1.position.y, images.p1.position.z + 8);

break;

case 1:

resetImages(images, “p2”);

TweenScaleTo(images.p2, 16, 9);

cameraTo(images.p2.position.x, images.p2.position.y, images.p2.position.z + 8);

break;

case 2:

resetImages(images, “p3”);

TweenScaleTo(images.p3, 16, 9);

cameraTo(images.p3.position.x, images.p3.position.y, images.p3.position.z + 8);

break;

case 3:

resetImages(images, “p4”);

TweenScaleTo(images.p4, 16, 9);

cameraTo(images.p4.position.x, images.p4.position.y, images.p4.position.z + 8);

break;

default:

resetImages(images, “p”)

cameraTo(0, 0, 10);

}

}

function checkSeconds() {

seconds += 1;

if (seconds > 5) {

seconds = 0;

if (activeImage + 1 > 4) {

activeImage = 0;

} else {

activeImage += 1;

}

makeZoomAccordingToActive(activeImage)

}

}

setInterval(checkSeconds, 1000);

</script>

</body>

</html>

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store