block by devgru 4c6c73b278a0dba364f8

RGB, HSL and LAB color spaces

Full Screen

script.js

var cubeItems = 17 + 1;
var cubeSpace = 7;
var cubeRatio = 4;
var cubeSize = cubeSpace / cubeRatio;
var margin = -cubeSpace * (cubeItems - 1) / 2;
var colorStep = 255 / (cubeItems - 1);
var r = colorStep * 256 * 256;
var g = colorStep * 256;
var b = colorStep;

var maxSpeed = 3;
var maxSpeedSq = Math.pow(maxSpeed, 2);
var meshes = null;

var container, stats;

var camera, controls, scene, renderer;

var axisX = new THREE.Vector3(1, 0, 0);
var axisY = new THREE.Vector3(0, 1, 0);
var axisZ = new THREE.Vector3(0, 0, 1);
var angleX = -Math.PI / 4;
var angleY = -Math.PI / 4;
var angleZ = Math.atan(Math.sqrt(2) / 2);

init();

function move(p, t) {
    var distance = p.distanceToSquared(t);
    var isTooFar = distance > maxSpeedSq;

    if (isTooFar) {
        var step = new THREE.Vector3()
            .subVectors(t, p)
            .setLength(maxSpeed);
        p.add(step);
        return false;
    } else {
        p.copy(t);
        return true;
    }
}

function animate() {
    render();
    meshes.forEach(function (mesh) {
        var data = mesh.userData;
        if (data.targetReached) {
            return;
        }
        var p = mesh.position;
        var t = data.target;

        data.targetReached = move(p, t);
        mesh.updateMatrix();

    });
    stats.update();
    controls.update();
    requestAnimationFrame(animate);
}

function numberToHex(i) {
    var pad = "000000";
    var s = i.toString(16);
    return '#' + pad.substring(0, pad.length - s.length) + s
}

function calcLabTarget(rgb) {
    var lab = d3.lab(rgb);
    return new THREE.Vector3(
        (lab.b),
        -100 + 2 * lab.l,
        (lab.a)
    );
}

function setLabTarget(mesh) {
    mesh.userData.targetReached = false;
    mesh.userData.target = calcLabTarget(mesh.userData.color);
}

function calcHslTarget(rgb) {
    var hsl = d3.hsl(rgb);
    if (isNaN(hsl.s)) hsl.s = 0;
    if (isNaN(hsl.h)) hsl.h = 0;
    hsl.h -= 45;
    var rad = Math.PI * hsl.h / 180;
    return new THREE.Vector3(
        hsl.s * 100,
        -100 + 200 * hsl.l,
        0
    )
        .applyAxisAngle(axisY, rad);
}
function setHslTarget(mesh) {
    mesh.userData.targetReached = false;
    mesh.userData.target = calcHslTarget(mesh.userData.color);
}

function rgbTransform(x) {
    return margin + cubeSpace * x / colorStep;
}
function calcRgbTarget(rgb) {
    return new THREE.Vector3(
        rgbTransform(rgb.r),
        rgbTransform(rgb.g),
        rgbTransform(rgb.b)
    )
        .applyAxisAngle(axisX, angleX)
        .applyAxisAngle(axisZ, angleZ)
        .applyAxisAngle(axisY, angleY)

}
function setRgbTarget(mesh) {
    mesh.userData.targetReached = false;
    mesh.userData.target = calcRgbTarget(mesh.userData.color);
}

function setPosition(vector, values) {
    Object.keys(values).forEach(function (k) {
        vector[k] = values[k];
    });
}

function init() {
    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.z = 500;

    controls = new THREE.OrbitControls(camera);

    scene = new THREE.Scene();

    // world
    var cube = new THREE.SphereGeometry(cubeSize);
    var material = new THREE.MeshBasicMaterial({shading: THREE.FlatShading});

    for (var x = 0; x < cubeItems; x++) {
        for (var y = 0; y < cubeItems; y++) {
            for (var z = 0; z < cubeItems; z++) {
                var rgbInt = x * r + y * g + b * z;
                var color = d3.rgb(numberToHex(rgbInt));

                var m = material.clone();
                m.color = new THREE.Color(rgbInt);
                var mesh = new THREE.Mesh(cube, m);

                mesh.userData = {color: color};
                setRgbTarget(mesh);

                scene.add(mesh);

                mesh.matrixAutoUpdate = false;
                setPosition(mesh.position, mesh.userData.target);
                mesh.updateMatrix();
            }
        }
    }

    meshes = scene.children.filter(function (o) {
        return o instanceof THREE.Mesh;
    });

    // renderer

    renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setClearColor(0x808080);
    renderer.setSize(window.innerWidth, window.innerHeight);

    container = document.getElementById('container');
    container.appendChild(renderer.domElement);

    stats = new Stats();
    var statsStyle = stats.domElement.style;
    statsStyle.position = 'absolute';
    statsStyle.top = '0px';
    statsStyle.zIndex = 100;
    container.appendChild(stats.domElement);

    window.addEventListener('resize', onWindowResize, false);

    animate();
}

function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function render() {
    renderer.render(scene, camera);
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <title>three.js - RGB and LAB color spaces</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link rel="stylesheet" href="style.css">
</head>

<body>
<div id="container"></div>
<div id="info">
    <a href="//threejs.org" target="_blank">three.js</a> -
    <button onclick="meshes.forEach(setRgbTarget)">RGB</button>,
    <button onclick="meshes.forEach(setHslTarget)">HSL</button> and
    <button onclick="meshes.forEach(setLabTarget)">LAB</button>
    color spaces
</div>

<script src="//threejs.org/build/three.min.js"></script>
<script src="//threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="//threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="script.js"></script>

</body>
</html>

style.css

body {
    color: #000;
    font-family: Monospace;
    font-size: 13px;
    text-align: center;
    font-weight: bold;

    background-color: #fff;
    margin: 0;
    overflow: hidden;
}

#info {
    color: #000;
    position: absolute;
    top: 0;
    width: 100%;
    padding: 5px;
}

a {
    color: red;
}