Home
GLSL
GLSLの修飾子varyingの使い方【Three.js】

GLSLの修飾子varyingの使い方【Three.js】

GLSLの修飾子varyingの使い方【Three.js】

どうも!かけちまるです!

Three.jsでシェーディングするために使うGLSL。
その中でも重要な修飾子の一つであるvaryingに注目して解説します。

varyingを理解することで、画像をゆらゆらアニメーションさせたり、色を動的に変えたりできます。

GLSLってなんなん?という方はこちらの記事が参考になりそうです。

この記事では、

  • ・varyingとは?
  • ・varyingの使い方

がわかります。

varyingとは?

varyingは、GLSLの修飾子のひとつです。
修飾子は他に、attributeuniformがあり、よく使われます。

それぞれの役割は次のような感じ

  • attribute・・・頂点情報などを入れる
  • uniform・・・グローバル変数を入れる
  • varying・・・VertexShaderからFragmentShaderに変数を渡すときに使う

上記にあるようにvaryingはVertexShaderからFragmentShaderに変数を渡す役割があります。

varyingはVertexShaderからFragmentShaderに変数を渡す役割

varyingの使い方

では、実際にどのように使うのか見ていきましょう。
この記事では次のような成果物を作ります。

テンプレート

次のテンプレートをベースに実装していきます。

テンプレートをコピペして次のような感じになっていればOKです。

テンプレート
ディレクトリ構成
開く&閉じるコピー
index.html js/ -main.js
index.html
開く&閉じるコピー
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script async src="https://unpkg.com/es-module-shims@1.5.8/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.142.0/build/three.module.js" } } </script> <script src="./js/main.js" type="module"></script> <style> *{ margin: 0; padding: 0; box-sizing: border-box; } </style> </head> <body> <script id="v-shader" type="x-shader/x-vertex"> void main(){ gl_Position = projectionMatrix * modelMatrix * viewMatrix * vec4(position,1.0); } </script> <script id="f-shader" type="x-shader/x-fragment"> void main(){ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } </script> </body> </html>
main.js
開く&閉じるコピー
import * as THREE from 'three'; /** * シーン・カメラ・レンダラーを用意する */ const fov = 50; const fovRad = (fov / 2) * (Math.PI / 180); // 視野角をラジアンに変換 let distance = (window.innerHeight / 2) / Math.tan(fovRad); // カメラ距離を求める const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 0.1, 2000 ); camera.position.z = distance; const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); document.body.appendChild(renderer.domElement); /** * ジオメトリ+マテリアル=メッシュを用意する */ const planeGeometry = new THREE.PlaneGeometry(200, 200); const shaderMaterial = new THREE.ShaderMaterial({ //バーテックスシェーダを設定 vertexShader: document.querySelector('#v-shader').textContent, //フラグメントシェーダを設定 fragmentShader: document.querySelector('#f-shader').textContent, }); let mesh = new THREE.Mesh(planeGeometry, shaderMaterial); scene.add(mesh); // アニメーション function animate() { renderer.render(scene, camera); requestAnimationFrame(animate); } animate(); // ブラウザのリサイズに対応させる window.addEventListener('resize', onWindowResize); function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; distance = (window.innerHeight / 2) / Math.tan(fovRad); camera.position.z = distance; camera.updateProjectionMatrix(); }

テンプレート通りにやったけどうまくいかない場合はVisual Studio CodeのLive Serverというプラグインを使ってローカルサーバー環境で試してみてください。

※他のエディタを使っている方はローカルサーバーを構築できる方法がないか調べてみてください🙇‍♂️

実装してみる

1

ShaderMaterialの引数にuniformsを設定

まず、VertexShaderに渡す値をShaderMaterialに設定します。
設定する値は引数uniformsに設定します。

main.js
開く&閉じるコピー
・・・ /** * ジオメトリ+マテリアル=メッシュを用意する */ const planeGeometry = new THREE.PlaneGeometry(200, 200); const shaderMaterial = new THREE.ShaderMaterial({ uniforms: { uColor: { value: new THREE.Vector3(1.0, 0.0, 1.0) } }, //バーテックスシェーダを設定 vertexShader: document.querySelector('#v-shader').textContent, //フラグメントシェーダを設定 fragmentShader: document.querySelector('#f-shader').textContent, }); let mesh = new THREE.Mesh(planeGeometry, shaderMaterial); scene.add(mesh); ・・・
2

uniformsの設定値をVertexShaderで受け取る

VertexShaderでuniform修飾子を使い、値を受け取ります。

index.html
開く&閉じるコピー
・・・ <script id="v-shader" type="x-shader/x-vertex"> uniform vec3 uColor; void main(){ vColor = uColor; gl_Position = projectionMatrix * modelMatrix * viewMatrix * vec4(position,1.0); } </script> <script id="f-shader" type="x-shader/x-fragment"> void main(){ gl_FragColor = vec4(vColor, 1.0); } </script> ・・・
3

varying修飾子でFragmentShaderに渡す

VertexShaderでvarying修飾子で変数を用意し、main()関数内で②で受け取った値を入れます。
これでVertexShaderからFragmentShaderに値を渡す準備ができました。

そして、FragmentShaderでもvarying修飾子に受け取りたい変数名を定義します。
これで、FragmentShaderで値を受け取ることができます。

index.html
開く&閉じるコピー
・・・ <script id="v-shader" type="x-shader/x-vertex"> uniform vec3 uColor; varying vec3 vColor; void main(){ vColor = uColor; gl_Position = projectionMatrix * modelMatrix * viewMatrix * vec4(position,1.0); } </script> <script id="f-shader" type="x-shader/x-fragment"> varying vec3 vColor; void main(){ gl_FragColor = vec4(vColor, 1.0); } </script> ・・・

ここまでで色が変わっていればOKです。

完成形
4

実装確認

原始的ですが、main.jsのuColorの値を変えると正方形の色が変わることがわかると思います。

これで、VertexShaderからFragmentShaderに値が渡されていることがわかりますね。

ちなみにGLSLでは色を0.0〜1.0で表現します。

まとめ

この記事で作ったサンプルでは、varying修飾子の重要性はそれほど感じなかったかもしれません。

例えば、VertexShaderで座標毎に色を計算し、値を渡すことでグラデーションを表現できたりします。

VertexShaderでは座標ごとにひと手間加えたい事が多いのでvarying修飾子は重要かなと思います。

おわり

かけちまる
かけちまる
Webエンジニアをしています。
HTML/CSS/JavaScript/jQuery/PHPができます。
WEB制作を中心に日々学びになったこと、興味が沸いたことについて初心者の方でもわかりやすいようにアウトプットしていくブログです。

関連記事

【Macユーザー向け】ngrokでローカル環境のサイトを外部へ公開

【Macユーザー向け】ngrokでローカル環境のサイトを外部へ公開

次世代画像フォーマットWebPでサイトの表示速度を改善しよう!

次世代画像フォーマットWebPでサイトの表示速度を改善しよう!

【GSAP】registerEffectでアニメーションをテンプレート化する方法

【GSAP】registerEffectでアニメーションをテンプレート化する方法

【簡単】WebサイトにGoogleマップを埋め込む一番簡単な方法

【簡単】WebサイトにGoogleマップを埋め込む一番簡単な方法

【CSSのみ】指定行数を超えたテキストを非表示にする方法

【CSSのみ】指定行数を超えたテキストを非表示にする方法

Visual Studio Codeの検索と置換

Visual Studio Codeの検索と置換