TSLとは?WebGPU時代の新しいシェーダーの書き方
みなさんこんにちは。フロントエンドエンジニアのしゅん(@shun_webdesign)です。
最近、僕はXでThree.jsのシェーダー作品をちょこちょこ投稿しているんですが、その多くを「TSL」というもので書いています。
TSL=Three.js Shading Language。ここ最近のThree.jsで使えるようになった、新しいシェーダーの書き方です。
正直、最初は「GLSLで困ってないし、わざわざ新しいの覚える必要ある?」と思っていました。でも実際に触ってみると、これがWebGPU時代のスタンダードになるのも納得、という体験だったんですよね。
この記事では、そもそもTSLって何? なぜ今これなの? というところを、GLSLと見比べながらできるだけやさしく解説していきます。
Table of Contents
TSLの話をする前に、背景にある「WebGPU」に軽く触れておきます。
ざっくり言うと、WebGPUはWebGLの後継にあたる、ブラウザでGPUを扱うための新しい仕組みです。2026年に入って主要ブラウザすべてで標準搭載になり、「実験的なもの」から「普通に使えるもの」になりました。
ここで地味に困るのが、シェーダー言語が変わるという点です。WebGLでは「GLSL」を書いていましたが、WebGPUでは「WGSL」という別の言語を書く必要があります。
つまり、WebGLとWebGPUの両方に対応しようとすると、同じ処理をGLSLとWGSLで二重に書くことになりかねない。これはなかなかしんどいですよね。
この「二重に書く問題」を解決してくれるのがTSLです。
TSLとは:JavaScriptでシェーダーを書く
TSL(Three.js Shading Language)の一番のポイントはこれです。
JavaScriptでシェーダーのロジックを書くと、Three.jsがそれをWGSL(WebGPU用)やGLSL(WebGL用)に自動で変換してくれる
GLSLやWGSLのような「文字列の言語」を直接書くのではなく、JavaScriptの関数やノードを組み合わせてシェーダーを表現する——というのがTSLの考え方です。書いたものは出力先に応じてコンパイルされるので、1回書けばWebGPUにもWebGLにも対応できるんですね。
僕がTSLに「なるほど」と思ったのは、まさにここでした。WebGPUへの移行を、シェーダーの書き直しなしで乗り越えられる道があるんだ、と。
GLSLのつらみと、TSLが嬉しい理由
これまでThree.jsでシェーダーを書くときは、ShaderMaterial にGLSLを文字列で渡していました。これ、慣れると書けるんですが、地味なつらみがあります。
- ただの文字列なので、補完も型チェックも効かない(タイポに気づきにくい)
- JS側の値とのやり取りがuniform経由で面倒
- 処理を部品化して使い回しにくい
TSLはこのあたりが素直に解決されます。
- JavaScriptなのでエディタの補完が効く
- 関数として書けるので部品化・使い回しがしやすい
- 何よりWebGPU / WebGL の両対応
「シェーダーをコードとして扱える」感覚に近くて、僕みたいに普段JS/TSを書いている人間にはかなり馴染みやすかったです。
GLSLとTSLを見比べてみる
言葉だけだとピンと来ないと思うので、雰囲気だけ見てみましょう。
たとえば、UV座標を使って横方向に波打つ色を作る、みたいな処理。GLSLだとフラグメントシェーダーにこう書きます(イメージです)。
varying vec2 vUv;
void main() {
float wave = sin(vUv.x * 10.0) * 0.5 + 0.5;
gl_FragColor = vec4(wave, vUv.y, 1.0, 1.0);
}
これをTSLで書くと、こんな感じになります。
import { Fn, uv, vec3, vec4, sin } from "three/tsl";
import { MeshBasicNodeMaterial } from "three/webgpu";
const material = new MeshBasicNodeMaterial();
material.colorNode = Fn(() => {
const st = uv();
const wave = sin(st.x.mul(10)).mul(0.5).add(0.5);
return vec4(wave, st.y, 1, 1);
})();
注目してほしいのは、全部JavaScriptで書けているところ。uv() や sin() がそのまま関数として呼べて、.mul() .add() のようにメソッドチェーンで計算をつないでいけます。
そして、このコードはWebGPUなら裏でWGSLに、WebGLなら裏でGLSLにコンパイルされます。書き手は出力先を意識しなくていい。ここがTSLの気持ちよさです。
※ TSLはまだ新しく、関数名やインポート先(
three/tslなど)はバージョンで変わることがあります。実際に書くときは、three.js公式のサンプル集や、TSL公式リファレンス(Three.js Shading Language / three.js wiki)を基準にするのがおすすめです。
TSLを始めるには
最低限おさえるのはこの3つです。
WebGPURendererを使う(three/webgpuから読み込む)MeshBasicNodeMaterialなどの「ノードマテリアル」を使うmaterial.colorNodeやmaterial.positionNodeにTSLで書いた処理を渡す
通常の WebGLRenderer + ShaderMaterial の構成とはマテリアル周りが少し変わりますが、Scene・Camera・Meshといった基本構造はThree.jsのままです。Three.jsの基礎を知っていれば、移行のハードルはそこまで高くありません。
(Three.jsそのものが初めての方は、先に [Three.js入門ガイド] を読んでから戻ってくると理解が早いはずです)
いつTSLを使うべき?
僕の今のスタンスはこんな感じです。
- これから新しく作るなら、TSLで書く(WebGPU時代に向けて素直)
- 既存のGLSL資産は、無理に全部書き換えない(動いているものはそのまま)
WebGPUが標準になった今、新規の表現はTSLで書いておくと将来の移行コストがかからず、WebGLにもフォールバックできます。一方で、すでにGLSLで書いた作品を急いで置き換える必要はありません。少しずつ慣れていけば十分です。
- TSL = JavaScriptでシェーダーを書き、WGSL/GLSLに自動変換してくれる仕組み
- WebGPU時代の「シェーダー二重書き問題」を解決してくれる
- GLSLより補完・部品化がしやすく、JS/TS書きと相性がいい
- 新規はTSL、既存GLSLは急がず——くらいの温度感でOK
TSLはまだ日本語の情報が少ない領域なので、これから触る人の入口になればうれしいです。僕もXでTSLの作品を出していくので、よかったら覗いてみてください。
次は、TSLの土台になる [GLSL入門] や、[Three.jsでWebGPUを使う(WebGPURenderer移行ガイド)] も読んでみてください。よく使うノードは [TSLノード早見表] にまとめていく予定です。
それでは、よいThree.jsライフを🌊