RGB与HSL
20 Jun 2019
Author:wuguanxi
CSS中的色彩表示
CSS中常见的颜色表示方法有#HEX
、RGB
、HSL
这几种。
其中#HEX
和RGB
的关系比较简单,就是16进制与10进制之间的转换。都是表示R(红)G(绿)B(蓝)这三原色之间的混合比例,数值是取 [0 ~ 255]。
HSL
则是一种用色相(hue)饱和度(Saturation)亮度(Lightness)表示颜色的方法,这种方法更复合人类对颜色表达的习惯。
RGB与HSL的关系
RGB与HSL的关系,维基百科这篇文章说得很清楚了https://en.wikipedia.org/wiki/HSL_and_HSV
RGB
和HSL
可以看成是两种对颜色表达的不同模型,有其对应的几何意义。
RGB
的几何模型是一个立方体,HSL
则是一个圆柱体,它们之间存在着非线性转换的关系。
用three.js模拟RGB cube
我们可以用three.js搭建一个3D的RGB魔方
分别用[RGB]代表[x,y,z]三个方向,创建一个16*16*16的魔方,每一块对应其RGB颜色
const Cube = function(zb){
const {px,py,pz,sc,color,name,visible} = zb;
// 创建一个长宽高均为 sc 个单位长度的立方体(几何体)
const cubeGeometry = new THREE.BoxGeometry(sc, sc, sc);
// 创建材质
const cubeMaterial = new THREE.MeshLambertMaterial({
color
});
// 创建一个立方体网格(mesh):将材质包裹在几何体上
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// 设置网格位置
cube.position.x = px;
cube.position.y = py;
cube.position.z = pz;
// 将立方体网格加入到场景中
return cube;
}
const cubesData = [];
const size = 16;
const sc = 2;
for(let r = 0; r < size; r ++){
for(let g = 0; g < size; g ++){
for(let b = 0; b < size; b ++){
cubesData.push({
px:r * sc,
py:g * sc,
pz:b * sc,
sc,
color:createColor(r,g,b,size),
})
}
}
}
const cubeMeshs = cubesData.map((item) => {
return Cube(item);
});
cubeMeshs.forEach((item) => {
scene.add(item);
});
function createColor(r,g,b,size){
const length = size - 1;
return parseInt(r / length * 0xff) * 0x10000 + parseInt(g / length * 0xff) * 0x100 + parseInt(b / length * 0xff);
}
移动摄影机的位置观察魔方的四周(可以在网页里按PALY按钮)
让摄影机移动到(200,200,200)
的位置并lookAt(0,0,0)
(按Hue按钮),就可以模拟魔方在x+y+z=0
这个面上的投影,看到类似HSL
的色环,这里可以看到360度的色相。
按STOP按钮返回。
只显示魔方的中轴线,隐藏其他(按Lig按钮),可以看到一条从黑到灰到白的线,这个就相当与是HSL
里的亮度的梯度。
饱和度用魔方比较难显示,但可以用点阵模拟。3D的RGB点阵
这是一个亮度50%的色彩面,可以看到他是由6个直角三角形拼接而成。越靠近中心饱和度越低,外围饱和度最高。
调整L进度度条,可以改变亮度,可以看不同亮度下的色彩面。
10%
30%
50%
70%
90%
RGB 和 HSL 互换公式
// RGB 转换成 HSL
// R[0~255] G[0~255] B[0~255] H[0~360] S[0~1] L[0~1]
// https://en.wikipedia.org/wiki/HSL_and_HSV
export function rgb2hsl(R,G,B){
const r = R / 0xff;
const g = G / 0xff;
const b = B / 0xff;
const max = Math.max(r,g,b);
const min = Math.min(r,g,b);
const c = max - min;
let _hue;
if (c === 0){
_hue = null;
} else if (max === r) {
_hue = ((g - b) / c) % 6;
} else if (max === g) {
_hue = (b - r) / c + 2;
} else {
_hue = (r - g) / c + 4;
}
const hue = _hue === null ? 0 : (_hue * 60) % 360;
const lightness = (max + min) / 2;
const saturation = (lightness === 1 || lightness === 0) ? 0 : c / (1 - Math.abs(2 * lightness - 1));
return {
H:(hue >= 0 ? hue : 360 + hue) ,S:saturation,L:lightness
}
}
// HSL 转换成 RGB
// R[0~255] G[0~255] B[0~255] H[0~360] S[0~1] L[0~1]
// https://en.wikipedia.org/wiki/HSL_and_HSV
export function hsl2rgb(H,S,L){
const saturation = S;
const lightness = L;
const c = (1 - Math.abs(2 * lightness - 1)) * saturation;
const _hue = (H % 360) / 60;
const x = c * (1 - Math.abs(_hue % 2 - 1));
let r,g,b;
if (_hue >= 0 && _hue < 1) {
[r,g,b] = [c,x,0];
} else if (_hue >= 1 && _hue <= 2) {
[r,g,b] = [x,c,0];
} else if (_hue >= 2 && _hue <= 3) {
[r,g,b] = [0,c,x];
} else if (_hue > 3 && _hue <= 4) {
[r,g,b] = [0,x,c];
} else if (_hue > 4 && _hue <= 5) {
[r,g,b] = [x,0,c];
} else if (_hue > 5 && _hue <= 6) {
[r,g,b] = [c,0,x];
}
const m = lightness - c / 2;
const [R,G,B] = [Math.abs(r + m),Math.abs(g + m),Math.abs(b + m)];
return {
R:R * 0xff,G:G * 0xff,B:B * 0xff
}
}