PROWAREtech
ThreeJS: Transition from One Color to Another
How to gradually transition from one color to another using THREE.js with examples changing the scene background during the scroll event and animation event.
This snippet of code uses a linear transition.
// NOTE: Helper function
var INT2RGB = function (int) {
return [(int & 0xff0000) >>> 16, (int & 0xff00) >>> 8, int & 0xff];
};
// NOTE: Helper function
var RGB2INT = function (rgb) {
return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
};
// NOTE: the function that transitions from one color to another based on a percentage of transition or completion
var transitionColor = function (percent, startColor, endColor) {
if (percent < 0) {
return startColor;
}
else if (percent > 100) {
return endColor;
}
var pos = percent / 100;
var rgb1 = INT2RGB(startColor);
var rgb2 = INT2RGB(endColor);
var r = Math.trunc((1 - pos) * rgb1[0] + pos * rgb2[0] + 0.5);
var g = Math.trunc((1 - pos) * rgb1[1] + pos * rgb2[1] + 0.5);
var b = Math.trunc((1 - pos) * rgb1[2] + pos * rgb2[2] + 0.5);
return RGB2INT([r, g, b]);
};
Here is a working example that transitions during the animate function:
<!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>Color Transition</title>
<style>
body {
margin: 0;
padding: 0;
}
canvas {
display: block;
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<canvas></canvas>
<script src="/js/three.min.js"></script>
<script type="text/javascript">
(function () {
var canvas = document.getElementsByTagName("canvas")[0];
// NOTE: Helper function
var INT2RGB = function (int) {
return [(int & 0xff0000) >>> 16, (int & 0xff00) >>> 8, int & 0xff];
};
// NOTE: Helper function
var RGB2INT = function (rgb) {
return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
};
// NOTE: the function that transitions from one color to another based on a percentage of transition or completion
var transitionColor = function (percent, startColor, endColor) {
if (percent < 0) {
return startColor;
}
else if (percent > 100) {
return endColor;
}
var pos = percent / 100;
var rgb1 = INT2RGB(startColor);
var rgb2 = INT2RGB(endColor);
var r = Math.trunc((1 - pos) * rgb1[0] + pos * rgb2[0] + 0.5);
var g = Math.trunc((1 - pos) * rgb1[1] + pos * rgb2[1] + 0.5);
var b = Math.trunc((1 - pos) * rgb1[2] + pos * rgb2[2] + 0.5);
return RGB2INT([r, g, b]);
};
// NOTE: create the scene to place objects in
var scene = new THREE.Scene();
scene.matrixWorldAutoUpdate = true;
// NOTE: the width and height of the canvas
var size = {
width: canvas.offsetWidth,
height: canvas.offsetHeight
};
var cameraNear = 1, cameraFar = 500;
// NOTE: create the camera with 53 degree field of view; this is how the scene is viewed by the user
var camera = new THREE.PerspectiveCamera(75, size.width / size.height, cameraNear, cameraFar);
var renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(size.width, size.height);
renderer.render(scene, camera);
var percent = -50;
// NOTE: MUST HAVE AN ANIMATE FUNCTION
var animate = function () {
scene.background = new THREE.Color(transitionColor(percent, 0x6699CC, 0xFF6633));
percent += 0.5;
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
animate();
})();
</script>
</body>
</html>
Here is an example of transitioning between two colors during the scroll event:
<!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>Color Transition</title>
<style>
body {
margin: 0;
padding: 0;
height: 300vh;
}
canvas {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<canvas></canvas>
<script src="/js/three.min.js"></script>
<script type="text/javascript">
(function () {
var canvas = document.getElementsByTagName("canvas")[0];
// NOTE: Helper function
var INT2RGB = function (int) {
return [(int & 0xff0000) >>> 16, (int & 0xff00) >>> 8, int & 0xff];
};
// NOTE: Helper function
var RGB2INT = function (rgb) {
return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
};
// NOTE: the function that transitions from one color to another based on a percentage of transition or completion
var transitionColor = function (percent, startColor, endColor) {
if (percent < 0) {
return startColor;
}
else if(percent > 100) {
return endColor;
}
var pos = percent / 100;
var rgb1 = INT2RGB(startColor);
var rgb2 = INT2RGB(endColor);
var r = Math.trunc((1 - pos) * rgb1[0] + pos * rgb2[0] + 0.5);
var g = Math.trunc((1 - pos) * rgb1[1] + pos * rgb2[1] + 0.5);
var b = Math.trunc((1 - pos) * rgb1[2] + pos * rgb2[2] + 0.5);
return RGB2INT([r, g, b]);
};
// NOTE: create the scene to place objects in
var scene = new THREE.Scene();
scene.matrixWorldAutoUpdate = true;
// NOTE: the width and height of the canvas
var size = {
width: canvas.offsetWidth,
height: canvas.offsetHeight
};
var cameraNear = 1, cameraFar = 500;
// NOTE: create the camera with 53 degree field of view; this is how the scene is viewed by the user
var camera = new THREE.PerspectiveCamera(75, size.width / size.height, cameraNear, cameraFar);
camera.position.z = 3;
var renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(size.width, size.height);
renderer.render(scene, camera);
var planeImage = "data:image/png;base64,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";
var planeGeometry = new THREE.PlaneGeometry(1, 1);
var planeMaterial = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(planeImage), transparent: true, side: THREE.DoubleSide });
scene.add(new THREE.Mesh(planeGeometry, planeMaterial));
scene.background = new THREE.Color(0xFF0000);
// NOTE: the parent element is the document body!!!
window.onscroll = function() {
var scrollPosition = document.body.offsetHeight / canvas.offsetHeight / 2 * window.scrollY;
var percent = scrollPosition / document.body.offsetHeight * 100;
scene.background = new THREE.Color(transitionColor(percent, 0xFF0000, 0xFFFF00));
};
// NOTE: MUST HAVE AN ANIMATE FUNCTION
var animate = function () {
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
animate();
})();
</script>
</body>
</html>
Comment