あなたが見ている色は、“現実”だろうか?
🫧 シャボン玉の虹色は、本当に“色”なのか?
――あの美しさの裏にある、光と構造の魔法
ある日、風の中をふわふわと舞うシャボン玉を見たとき、
あなたは思ったことがありませんか?
「なんで、シャボン玉は虹色に見えるんだろう?」
シャボン玉に、絵の具や顔料が塗られているわけではありません。
それなのに、見る角度や光の当たり方によって、赤・青・緑と色が変わって見える。
まるでプリズムのようなあの輝き。
実はそれ、“光の干渉”という現象によって生まれているんです。
🧪 シャボン玉は、ただの「石けん水」ではない
シャボン玉は、ほんの数十ナノメートル〜数百ナノメートルの超薄い膜でできています。
この膜がちょうど、光の波長(色の正体)と同じくらいのサイズなんです。
つまり、シャボン玉の膜は**“薄膜といわれる光を干渉させる舞台**になっているのです。
🌈 光は“ぶつかって、ずれて、打ち消し合う”
白い太陽光がシャボン玉に当たると、
光の一部は膜の外側で反射し、
もう一部は膜の内側に入り、裏側で反射して外に出てきます。
このとき、2つの光はほんのわずかにずれたタイミングで外に出てくるため、
それぞれの波長(=色)によって、強まったり、打ち消されたりするのです。
🔁 これを「光の干渉」と呼びます。
赤は強まって反射され、青は打ち消される……
その結果、見る角度によって色が変わって見えるのです。
🎨 シャボン玉の“色”は、実は存在していない
ここで大事なことがあります。
シャボン玉に見えるあの色――実際にはその色で塗られているわけではないのです。
赤く見えるときも、青く見えるときも、
その膜は常に「透明」で、「色なんて持っていない」。
それでも色が現れるのは、光の波が膜という“構造”と出会った結果なのです。
💡 光が構造と出会うとき、色が生まれる

クジャクの羽根、CDの裏面、そしてシャボン玉。
どれも共通しているのは、
構造が“光の波”を操り、色を生み出している
ということです。
この現象は「構造色」と呼ばれ、
自然界ではカブトムシ、モルフォ蝶、クジャクなど、あらゆる場所で使われています。
🧠 最後に:あなたが見ている色は、“現実”だろうか?
シャボン玉の色は、単なる光の干渉です。
そこに**「色そのもの」**は存在していません。
それでも、あなたの目には、虹のような輝きが見える。
それは現実か?
それとも、光と構造が見せた幻なのか?
科学は、そんな問いへの入り口を、いつもシャボン玉の中にそっと隠しているのです。
🫧「シャボン玉の虹色は、なぜ生まれるのか?」
スペクトルと干渉、そしてRGBという仮想の“色”の話。
子どもの頃、誰しも一度は空に舞うシャボン玉を追いかけたことがあるでしょう。
空に浮かぶあの半透明の球体は、まるで魔法のように、虹色に輝いていました。
でも、よく考えてみてください。
あの色、本当に“存在”していたのでしょうか?
🎨 あの七色は「物の色」ではない
シャボン玉には色素がありません。絵の具も使っていません。
それなのに、どうして虹のような色が見えるのか?
答えは、光そのものにあります。
🌈 シャボン玉は“薄い膜”でできている
シャボン玉の膜はとても薄い「水と石けん」の層でできています。
この膜に太陽光(白色光)が当たると、一部の光は前面で反射し、もう一部は膜を通って内側から反射します。
この2つの光は出会ったときに、干渉という現象を起こします。
ある波長の光は強調され(強め合い)
別の波長の光は打ち消され(弱め合い)
その結果、特定の色だけが強調されてあなたの目に届くのです。
🧪 数式で再現できる? → できる!
この現象は数学的に簡易的なモデルで再現できます。
干渉によって強調される波長(λ)は、膜の厚さ dd、屈折率 nn、観察角度 θθ によって次のように計算されます:
lambda = 2nd\cosθ
これを使えば、**「どの波長の光が強調されるか」**がわかります。
でも、私たちは光の波長で色を見ているわけではありません。
パソコンの画面やアプリで色を表示するためには、**RGB(赤・緑・青)**という3色の値に変換する必要があります。
🔁 波長 → RGB への変換
これは現実に即した変換ではありません。
人間の視覚の特性とディスプレイの構造を考慮した、近似関数を用いて変換します。
例えば:
470nm は「青」寄りの色
550nm は「緑」寄りの色
620nm は「赤」寄りの色
このようにして、物理的な波長を、私たちが見慣れた「色」へ翻訳しているのです。
🧑🔬 このアプリは何をしているの?
この「シャボン玉色シミュレーター」では、あなたがスライダーを動かすたびに:
膜の厚さ、屈折率、角度を取得
上の干渉式で、強調される波長を計算
その波長を RGBに変換
色としてディスプレイに表示
という処理をしています。
🧘 色とは、「目で感じる光の解釈」
あなたが見ている色は、現実そのものではありません。
それは光の波長があなたの目と脳にどう影響したかの結果にすぎない。
シャボン玉も、CDの裏面も、クジャクの羽も、
そしてあなたの目に映る“虹色”も——
それはすべて、**光の干渉と、波長と、あなたの脳が作り出した「色の幻想」**なのです。
💻 実際に触ってみよう!
この原理を活かして作られたシャボン玉シュミレータ(では、
物理法則と視覚の関係を、目で見て体験できます。
膜を厚くするとどうなる?
角度を変えると、なぜ色が動く?
なぜ青い光が出たり、赤に変わったりするの?
遊びながら、色の本質に触れてみてください。
🧠 最後に:色はあなたの脳が作った「ストーリー」
「色」というのは、実体のない感覚です。
そしてその感覚は、光の物理現象と、人間の生理現象の複合によって成り立っています。
あなたの見ている色は、あなた自身の中にしか存在しない。
それでも、それは確かに、あなたにとって「リアル」なのです。


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>シャボン玉の色シミュレーター</title>
<style>
body {
background: #222;
color: #fff;
font-family: sans-serif;
text-align: center;
padding: 30px;
}
.slider-container {
margin: 20px auto;
width: 300px;
}
input[type=range] {
width: 100%;
}
#display {
width: 300px;
height: 300px;
margin: 30px auto;
border-radius: 50%;
box-shadow: 0 0 25px rgba(255, 255, 255, 0.3);
border: 2px solid #ccc;
}
label {
display: block;
margin-top: 10px;
}
</style>
</head>
<body>
<h1>🫧 シャボン玉の色シミュレーター</h1>
<p>光の干渉による色の変化を観察できます</p>
<div class="slider-container">
<label>膜の厚さ (nm): <span id="thicknessVal">250</span></label>
<input type="range" id="thickness" min="50" max="800" value="250" />
<label>屈折率 (n): <span id="refractiveIndexVal">1.33</span></label>
<input type="range" id="refractiveIndex" min="120" max="180" value="133" />
<label>観察角度 (°): <span id="angleVal">0</span></label>
<input type="range" id="angle" min="0" max="80" value="0" />
</div>
<div id="display"></div>
<script>
const thicknessSlider = document.getElementById("thickness");
const refractiveIndexSlider = document.getElementById("refractiveIndex");
const angleSlider = document.getElementById("angle");
const display = document.getElementById("display");
const thicknessVal = document.getElementById("thicknessVal");
const refractiveIndexVal = document.getElementById("refractiveIndexVal");
const angleVal = document.getElementById("angleVal");
function wavelengthToRGB(wavelength) {
let R = 0, G = 0, B = 0;
if (wavelength >= 380 && wavelength <= 440) {
R = -(wavelength - 440) / (440 - 380);
G = 0;
B = 1;
} else if (wavelength > 440 && wavelength <= 490) {
R = 0;
G = (wavelength - 440) / (490 - 440);
B = 1;
} else if (wavelength > 490 && wavelength <= 510) {
R = 0;
G = 1;
B = -(wavelength - 510) / (510 - 490);
} else if (wavelength > 510 && wavelength <= 580) {
R = (wavelength - 510) / (580 - 510);
G = 1;
B = 0;
} else if (wavelength > 580 && wavelength <= 645) {
R = 1;
G = -(wavelength - 645) / (645 - 580);
B = 0;
} else if (wavelength > 645 && wavelength <= 780) {
R = 1;
G = 0;
B = 0;
}
// 視覚的な感度を考慮して調整
const factor = (wavelength >= 380 && wavelength < 420) ? 0.3 + 0.7 * (wavelength - 380) / 40 :
(wavelength >= 420 && wavelength < 700) ? 1.0 :
(wavelength >= 700 && wavelength <= 780) ? 0.3 + 0.7 * (780 - wavelength) / 80 : 0.3;
R = Math.round(Math.pow(R * factor, 1.0) * 255);
G = Math.round(Math.pow(G * factor, 1.0) * 255);
B = Math.round(Math.pow(B * factor, 1.0) * 255);
// RGB値が範囲外にならないようにする
R = Math.max(0, Math.min(255, R));
G = Math.max(0, Math.min(255, G));
B = Math.max(0, Math.min(255, B));
return [R, G, B];
}
function updateColor() {
const d = parseFloat(thicknessSlider.value); // 膜厚 nm
const n = parseFloat(refractiveIndexSlider.value) / 100; // 屈折率
const theta = parseFloat(angleSlider.value) * Math.PI / 180; // 観察角度(ラジアン)
thicknessVal.textContent = d;
refractiveIndexVal.textContent = (n).toFixed(2);
angleVal.textContent = angleSlider.value;
// 強めの干渉条件 (2nd cosθ = mλ)
// ここではm=1の主な干渉波長を計算
const lambdaPeak = 2 * n * d * Math.cos(theta);
// 波長が可視光範囲外の場合、適切に処理
if (lambdaPeak < 380 || lambdaPeak > 780) {
// 可視光外の場合は補間や複数波長の混合を模擬
const lambda = Math.max(380, Math.min(780, lambdaPeak));
const [r, g, b] = wavelengthToRGB(lambda);
display.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
} else {
const [r, g, b] = wavelengthToRGB(lambdaPeak);
display.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
}
}
thicknessSlider.addEventListener("input", updateColor);
refractiveIndexSlider.addEventListener("input", updateColor);
angleSlider.addEventListener("input", updateColor);
updateColor();
</script>
</body>
</html>