第3回クリエイティブ・コーディング:Three.jsとシェーダーの魔法

第3回の主役は、Web 3Dの世界で圧倒的なシェアを誇る Three.js です。
このライブラリは、ブラウザの中に広大な 3D 空間を作り出すことに特化した「舞台監督」のような存在。今回はこの Three.js の力を借りて、シェーダーという魔法を披露するための「舞台(ステージ)」を整えます。

スポンサーリンク

「Shadertoy」という魔法の鏡

シェーダーの世界は数学と物理の塊、一からすべてを理解しようとすると、入り口で立ち往生してしまいます。
そこで登場するのが、世界中の天才たちが魔法の数式を公開している聖地 Shadertoy

Shadertoy とは?

ブラウザ上で直接 GLSL(シェーダーコード)を書き、その結果をリアルタイムで確認できるサイト。 天才たちが作った魔法のコードが、公開されています。

巨人の肩」に乗るための準備

⚠️ コピーしたコードをそのまま、自分のWebサイトに貼り付けても、エラーになります。

🎨 1. 環境:Three.js という「舞台」を用意する
どれだけ優れた役者(シェーダー)がいても、演じる場所がなければ何も始まらない。ブラウザという画面の中に、描画専用のキャンバス=「舞台」を広げてくれるのがThree.jsの役割です。

📜 2. 翻訳:Shadertoy語を「標準GLSL語」に変換する
Shadertoyのコードは、実はそのサイト専用にアレンジされた「方言」のようなもの。自分のサイトで動かすには、ブラウザが直接理解できる「標準GLSL語」へ書き換える必要があります。

Three.js という舞台を支える「4人のスタッフ」

まずはブラウザの中に「舞台」を整える必要があります。Three.js では、主に 4 つの要素がチームとなって動いています。

🎬 シーン (Scene)

すべての役者が集まる「舞台そのもの」です。

🎥 カメラ (Camera)

観客がどこから舞台を見るかを決める「目」の役割です。

🧍 メッシュ (Mesh)

形(ジオメトリ)と肌(マテリアル)が合体した「役者」です。

🖥️ レンダラー (Renderer)

舞台を計算して、画面に映像として映し出す「監督」です。

今回のポイント:
3Dといっても、今回は奥行きを使いません。「平らな板(PlaneGeometry)」という役者を一人用意し、その肌である「マテリアル」の中に Shadertoy の魔法を流し込んでいきます。

GLSLの基礎:JavaScriptとは違う「魔法の国のルール」

シェーダーを書くための専用言語 GLSL (OpenGL Shading Language) の仕組み。

JavaScriptの常識が通用しないこの世界には、独自のルールと「癖」が存在します。

二人の専属魔法使い:頂点とフラグメント

シェーダーの舞台裏では、役割の違う二人の担当者がチームを組んで働いている。

📐 頂点シェーダー (Vertex Shader)

担当:場所と形(Where)

3Dモデルの「点」が画面のどこにあるかを決める数学担当。「画面いっぱいに、この板(Plane)を広げておいて!」と指示する舞台設営の役割。

🎨 フラグメントシェーダー (Fragment Shader)

担当:色(Color)

ピクセルの一つひとつに「お前はこの色になれ!」と命じる色彩担当。Shadertoyで私たちが書くコードの正体はこれ。 私たちが目指す「色の魔法使い」の本体。

💡Shadertoyでは、最初から「画面いっぱいに板を広げる」という頂点シェーダーの仕事が終わった状態からスタートできる。面倒な準備を飛ばして、いきなり「色の計算」だけに集中できるキャンバスなのです。

初心者が必ずハマる「3つの癖」

GLSLには、JavaScriptに慣れた人ほど驚くような独特の「癖」があります。

  • 💧 「.0」を忘れると即エラー(小数の呪い)
    JSなら 11.0 も同じだが、GLSLは型に超厳しい。小数を扱う時は必ず 1.0 と書くこと。整数と小数を混ぜて計算するだけで、魔法はエラーで止まってしまう。
  • 🧘 隣のピクセルに相談できない(孤独なピクセル)
    「左のピクセルが赤だから自分も……」という相談は一切できない。全ピクセルが同時に、孤独に、自分の色だけを計算している。この「超並列処理」こそが、GPUのパワーの秘密。
  • 🕰️ 昨日のことは覚えていない(一期一会)
    前のフレームの値を保存して使い回すことはできない。常に「今の時間(iTime)」と「今の場所(座標)」というヒントだけを頼りに、毎フレームゼロから色を計算し直している。

この癖さえ分かってしまえば、あとは数学という名の「レシピ」を記述するだけ。1秒間に60回、数百万回の計算を涼しい顔でこなします。

Three.js でシェーダーの「舞台」を作る

まずは、もっとも標準的な Three.js のコードです。ここでは「何が準備に必要なのか」と「どこに Shadertoy のコードを流し込むのか」だけに注目します。

import * as THREE from 'three';

// -----------------------------------------------------------
// 1. 舞台装置(Renderer)の準備
// -----------------------------------------------------------
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio); // 高精細ディスプレイ対応
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// -----------------------------------------------------------
// 2. 舞台(Scene)とカメラ(Camera)
// -----------------------------------------------------------
const scene = new THREE.Scene();

// 今回は「板」を画面いっぱいに映すだけなので、
// 座標 (-1, 1) の範囲を映す特殊なカメラを使います
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);

// -----------------------------------------------------------
// 3. 役者(Mesh)= 形(Geometry)+ 魔法の肌(Material)
// -----------------------------------------------------------
// 画面全体を覆う 2x2 の板
const geometry = new THREE.PlaneGeometry(2, 2);

const material = new THREE.ShaderMaterial({
  // 頂点シェーダー:板を画面の隅々まで広げる設定
  vertexShader: `
    void main() {
      gl_Position = vec4(position, 1.0);
    }
  `,

  // 🔥【ここが Shadertoy のコードを貼り付ける場所!】🔥
  fragmentShader: `
    void main() {
      // 翻訳したコードをここに! 
      // 例:オレンジ色で塗りつぶす
      gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
    }
  `
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// -----------------------------------------------------------
// 4. 【重要】リサイズ対策:画面の大きさが変わったら追いかける
// -----------------------------------------------------------
window.addEventListener('resize', () => {
  // ブラウザのサイズを取得
  const width = window.innerWidth;
  const height = window.innerHeight;

  // レンダラー(描画装置)のサイズを更新
  renderer.setSize(width, height);

  // カメラの比率などは今回 Orthographic なので固定でOKですが、
  // 通常の3D(PerspectiveCamera)ならここでもっと複雑な更新をします
});

// -----------------------------------------------------------
// 5. 上映開始(アニメーションループ)
// -----------------------------------------------------------
function animate() {
  // 1秒間に60回、自分自身を呼び出し続ける
  requestAnimationFrame(animate);

  // 描画!
  renderer.render(scene, camera);
}

animate();

仕組みを知るなら Three.js、効率化なら React Three Fiber

Reactという「UIを宣言的に構築する」ライブラリの利点を活かし、Three.jsという『最強の 3D エンジン』を「コンポーネント単位で制御する」ためのツール。それが React Three Fiber です。

なぜ「素の Three.js」から入るのか?

それは、「舞台の仕組み」を根本から理解するためです。

  • 🟢 メリット: カメラやレンダラーがどう動いているか、3Dの基本構造が身につく 。
  • 🔴 デメリット: 画面のリサイズ対応や、アニメーションのループ処理など、本質(クリエイティブ)以外の「準備」にコードの半分以上が割かれてしまう。

RTF で得られる「自由」

一方で React Three Fiber (RTF) は、これら面倒な準備をすべて自動化してくれる。

  • 圧倒的な短さ: 先ほどの Vanilla Three.js のコードが、数行のタグだけで完結する 。
  • 🎨 クリエイティブに集中: リサイズ対応などの「裏方仕事」を RTF に任せ、私たちは「どんなシェーダーを書くか」だけに時間を使える。
  • 🧩 コンポーネント化: 作ったシェーダーを「部品」として扱えるので、組み合わせるのも簡単。

React Three Fiber:最小限のシェーダー舞台

先ほどの「Vanilla Three.js」のコードを覗き、「React Three Fiber」でいかにスマートに記述できるかを比較してみてください。

import { Canvas } from '@react-three/fiber'

function ShaderPlane() {
  return (
    <mesh>
      {/* 1. 役者の「形」を決める(2x2の板) */}
      <planeGeometry args={[2, 2]} />

      {/* 2. 役者の「肌(シェーダー)」を決める */}
      <shaderMaterial
        // 頂点シェーダー:板を画面いっぱいに広げる
        vertexShader={`
          void main() {
            gl_Position = vec4(position, 1.0);
          }
        `}
        // 🔥【ここが Shadertoy のコードを貼り付ける場所!】🔥
        fragmentShader={`
          void main() {
            // ここに翻訳したコードを流し込む
            gl_FragColor = vec4(0.0, 0.8, 1.0, 1.0); // 水色の魔法
          }
        `}
      />
    </mesh>
  )
}

export default function App() {
  return (
    // Canvasタグが「Scene」「Camera」「Renderer」「Animation Loop」を
    // すべて自動で準備し、リサイズ対応までやってくれます!
    <Canvas style={{ width: '100vw', height: '100vh' }}>
      <ShaderPlane />
    </Canvas>
  )
}

開発環境をどこに構えるか?

p5.jsの時は OpenProcessing という便利な場所があったが、本格的なシェーダー開発では「自分の道具」を揃える必要があります。

✅ 初心者におすすめの2ステップ

  1. まずは手軽に:CodeSandbox
    ブラウザだけで動く「Web版OpenProcessing」。React Three Fiber の練習には最適です。
  2. 本気でやるなら:VS Code + Vite
    自分のPCに環境を作る。最初は少し勇気がいるが、一度整えてしまえば、自由自在になります。

第4回では、いよいよ React Three Fiber を使って、Shadertoy の芸術的なコードを自分のプロジェクトへと繋ぎ込む『クリエイティブ・コーディング』に挑戦します!