RGBとCMYK
パソコンのモニタや液晶テレビの場合、色は赤・緑・青のRGB(加法混色)というシステムを使います。また、印刷物の場合にはシアン・マゼンタ・黄・黒のCMYK(減法混色)になります。
RGB 加法混色
加法混色は、色を混ぜれば混ぜるほど白に近づきます。

CMYK 減法混色
減法混色は、色を混ぜれば混ぜるほど黒に近づきます。

RGBの混色
概念的な話だけではなかなか分かりにくいと思うので、実際にRGBの色彩を混色できるプログラムを動かしてみましょう。

次のコードをProcessingに貼り付けて動かしてみてください。
上部のR、G、Bのバーをドラッグすることによって、中央の色が混色されます。
注: 一部の機種ではblendModeが正常に機能しない場合があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | int r, g, b; //赤、緑、青用の変数 int rWidth, gWidth, bWidth; //バーの幅 //バーの領域にマウスが入っているかを判定 boolean rFlag, gFlag, bFlag; int barH = 15; //バーの高さ int margin = 50; //文字表示用のスペース PFont font; //文字用変数 void setup() { blendMode(LIGHTEST); //加法混色にするため、ブレンドモードを変更 size(400, 400); noStroke(); rWidth = gWidth = bWidth = width - margin; //初期化 rFlag = gFlag = bFlag = false; font = createFont("Arial", 11); textFont(font, 11); } void draw() { background(0); //map関数を使ってバーの幅を色(0~255)に変換 r = int(map(rWidth, 0, width - margin, 0, 255)); g = int(map(gWidth, 0, width - margin, 0, 255)); b = int(map(bWidth, 0, width - margin, 0, 255)); //赤のバーを描画 fill(255, 0, 0); rect(0, 0, rWidth, barH); //緑のバーを描画 fill(0, 255, 0); rect(0, barH, gWidth, barH); //青のバーを描画 fill(0, 0, 255); rect(0, barH*2, bWidth, barH); //赤の円を描画 fill(r, 0, 0); ellipse(150, 180, 200, 200); //緑の円を描画 fill(0, g, 0); ellipse(250, 180, 200, 200); //青の円を描画 fill(0, 0, b); ellipse(200, 267, 200, 200); //右下の四角を描画 fill(r, g, b); rect(370, 370, 30, 30); //テキスト描画 fill(255); text("R = " + r, width - margin + 3, barH - 3); text("G = " + g, width - margin + 3, barH*2 - 3); text("B = " + b, width - margin + 3, barH*3 - 3); } void mousePressed() { //選択範囲。もしマウスが赤のバーの領域に入ったら、 if ((mouseX > 0) && (mouseX < width - margin) && (mouseY > 0) && (mouseY < barH)) { rWidth = mouseX; //バーの幅をmouseXにする rFlag = true; //赤用フラッグをtrue //緑のバーの領域 } else if ((mouseX > barH) && (mouseX < width - margin) && (mouseY > 0) && (mouseY < barH*2)) { gWidth = mouseX; gFlag = true; //青のバーの領域 } else if ((mouseX > barH*2) && (mouseX < width - margin) && (mouseY > 0) && (mouseY < barH*3)) { bWidth = mouseX; bFlag = true; } } void mouseDragged() { if ( mouseX <= width - margin) { //ドラッグしている間はバーの幅を変更する if (rFlag) rWidth = mouseX; else if (gFlag) gWidth = mouseX; else if (bFlag) bWidth = mouseX; } } void mouseReleased() { //マウスを話したらフラッグをfalseにする rFlag = gFlag = bFlag = false; } |
色立体
色を表示するための色立体の種類は非常に多いので、ここではもっとも基本的な色立体であるRGB、HSB(HSV)、HSLについて解説します。
RGB
コンピュータで使われる色彩の表記法として代表的なのはRGB(Red、 Green、Blue)です。
また、プログラミングでは、透明度を表すA(alpha)が加わってRGBAも使われます。
RGBの色の関係は3次元的な立体で表すことができます。RGBを立体で表してみましょう。

Processing上でドラッグしながら動かせるサンプルを作りました。Processingにコードを貼りつけて実行してみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | float boxSize = 15; //立方体のサイズ float distance = 20; //立方体同士の距離 float halfDis; //立方体同士の一辺の全体の距離の半分 int boxNum = 10; //立方体の数 float step = 255/boxNum; //色を変化させる単位 int angleX = 30; //x軸を中心とした回転角度の初期値 int angleY = 60; //y軸を中心とした回転角度 void setup() { size(400, 400, P3D); //立方体が並んだ際の距離の半分 halfDis = distance*(boxNum- 1)/2; noStroke(); } void draw() { background(0); translate(width/2, height/2); //基準点を画面中央に移動 rotateX(radians(-angleX)); //x軸を中心に回転 rotateY(radians(angleY)); //y軸を中心に回転 for (int z = 0; z < boxNum; z ++) { //立方体を、z軸方向に並べる for (int y = 0; y < boxNum; y ++) { //立方体を、y軸方向に並べる for (int x = 0; x < boxNum; x ++) { //立方体を、x軸方向に並べる pushMatrix(); //一つずつ移動させる translate(x*distance - halfDis, y*distance - halfDis, z*distance - halfDis); fill(255 - step*x, 255 - step*y, 255 - step*z); //色を指定する box(boxSize, boxSize, boxSize); //立方体を描く popMatrix(); } } } } void mouseDragged() { //マウスをドラッグすることによって立体と回転 angleX += (mouseY - pmouseY); //x軸を中心とした回転 angleY += (mouseX - pmouseX); //y軸を中心とした回転 if (angleX < -120) angleX = -120; //上下は-60度から60度の間しか回転しない if (angleX > 0) angleX = 0; } |
このように、RGBは立方体で表すことができます。サンプルでは一辺10 x 10 x 10の1000個のキューブを表示していますが、実際には、一辺256 x 256 x 256色の16,777,216色(約1677万色)の色彩を表示することができます。
HSB(HSV)
もうHSB(Hue-色相、Saturation-彩度、Brightness-明度)は、HSV (Hue-色相、Saturation-彩度、Value-明度)とも呼ばれます。一般的にこのモードのように、色彩を「色相・彩度・明度」で捉える方法は、より人間の知覚に近いといわれます。

同じように、Processing用のサンプルを作成してみました。Processingに貼りつけて回転してみてください

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | float boxSize = 2; //立方体のサイズの初期値 float distance = 28; //縦方向の立方体同士の距離 float halfDis; //立方体同士の一辺の全体の距離の半分 float radius = 4; //x, y軸方向の立方体の距離の初期値 int boxNum = 8; //立方体の数 int angleX = -50; //x軸を中心とした回転角度の初期値 int angleZ = 0; //z軸を中心とした回転角度の初期値 void setup() { size(400, 400, P3D); colorMode(HSB, 360, 100, 100); //立方体を縦方向に並べた際の距離の半分 halfDis = distance*(boxNum - 1)/2; noStroke(); } void draw() { background(0); translate(width/2, height/2); //基準点を画面中央に移動 rotateX(radians(-angleX)); //x軸を中心に回転 rotateZ(radians(-angleZ)); //z軸を中心に回転 for (int z = 0; z < boxNum; z ++) { //縦にも増やす for (int angle = 0; angle < 360; angle += 15) { //15度ずつ移動 //boxNumの数だけx軸方向に立方体を増やす for (int i = 0; i < boxNum; i ++) { pushMatrix(); //円状に配置するためのxy座標の計算 float x = i*(radius + i*1.5)*cos(radians(angle)); float y = -i*(radius + i*1.5)*sin(radians(angle)); float saturation = float(i)/float(boxNum - 1)*100.0; //彩度を計算 float brigtness = float(z)/float(boxNum - 1)*100.0; //明度を計算 translate(x, y, z*distance - halfDis); //一つずつ移動させる rotateZ(radians(-angle)); //円状に配置 fill(angle, saturation, brigtness); //色を指定する //立方体を描く box(boxSize + boxSize*i, boxSize + boxSize*i, boxSize + boxSize*i); popMatrix(); } } } } void mouseDragged() { //マウスをドラッグすることによって立体と回転 angleX += (mouseY - pmouseY); //x軸を中心とした回転 angleZ += (mouseX - pmouseX); //z軸を中心とした回転 if (angleX < -60) angleX = -60; if (angleX > 60) angleX = 60; } |
HSL(HLS)
さらにもうひとつ、HSL(Hue-色相、Saturation-彩度、Luminance-輝度)という色立体があります。HSLはWindowsで使われる色空間で、HLSとも呼ばれます。
HSLとHSBは概念的にはかなり近いモデルですが、実際には違うシステムです。より深く知りたい方は次のページを参考にしてください。
HSLとHSBの違い

色の空間性
また、色には「膨張・進出」して見える性質のものと、「収縮・後退」して見える性質のものがあります。一般的に、次の傾向があります。
暖色系、明るい色は、膨張・進出する
寒色系、暗い色は、収縮・後退する

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | float angle = 10; float R = 150; PFont font; size(400, 400); background(255); smooth(); noStroke(); colorMode(HSB, 360, 100, 100); float cX = width/2; float cY = height/2; for(int i = 0; i < 360; i += angle) { fill(i, 100, 100); float rad = radians(i); ellipse(cX + R*cos(rad), cY + R*sin(rad), 20, 20); } //フォントリストの中から選ぶ。 //MacとWindowsの両方に入っているフォントが無難 font = createFont("Arial", 24); textFont(font); //テキスト表示 textSize(25); fill(0, 100, 100); text("暖色系", 230, 250); fill(240, 150, 150); text("寒色系", 100, 150); |
この特性をうまく使うと、色彩だけで構成した画面でも手前・奥の関係を作ることができます。例えば、次のサンプルは、左から右の正方形にいくに従って彩度と明度を上げています。結果、右の正方形の方が手前にあるように見えます。
しかし、上段と下段を比べると、上段の黄色の正方形の方が全体的に若干手前にあるように見えます。これは、黄色が膨張色・進出色であるため、収縮色・後退色である青よりも手前に見えるためです。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | size(300, 300); background(0); colorMode(HSB, 360, 100, 100); //カラーモードをHSBに変更 noStroke(); //黄色の四角 for (int x = 0; x < 5; x ++) { //左から順番に彩度と明度を20ずつ上げる fill(60, x*20 + 10, x*20 + 10); rect(x*50 + 35, height/3 - 15, 30, 30); } //青の四角 for (int x = 0; x < 5; x ++) { //左から順番に彩度と明度を20ずつ上げる fill(240, x*20 + 10, x*20 + 10); rect(x*50 + 35, height/3*2 - 15, 30, 30); } |