p5.js+シェーダー(GLSL) - Boxの法線で面を塗り分ける
p5.jsで3D図形のBoxにシェーダーを適用させてみます。
Boxの法線
Box(立方体)は面を6面持つ3D図形です。 それぞれの面に対して垂直方向を表すのが法線になります。
6面の面はxyzの3方向に向いており、それぞれ+x方向、-x方向、+y方向、-y方向、+z方向、-z方向の法線となっています。
Boxの各面を塗り分ける
法線はattribute vec3 aNormal;
で取り扱われています。
これを頂点シェーダーからフラグメントシェーダーへvarying vec3 vNormal;
として渡します。
このvNormal
がBoxでは
- +x方向なら (1.0, 0.0, 0.0)
- -x方向なら (-1.0, 0.0, 0.0)
- +y方向なら (0.0, 1.0, 0.0)
- -y方向なら (0.0, -1.0, 0.0)
- +z方向なら (0.0, 0.0, 1.0)
- -z方向なら (0.0, 0.0, -1.0)
となっています。
vNormal
を使って、法線の方向(面の向き)に応じて、各面を以下の色で塗り分けます。
let vs = ` precision highp float; precision highp int; attribute vec3 aPosition; attribute vec3 aNormal; varying vec3 vNormal; uniform mat4 uProjectionMatrix; uniform mat4 uModelViewMatrix; void main() { vec4 positionVec4 = vec4(aPosition, 1.0); vNormal = aNormal; gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4; } `; let fs = ` precision highp float; precision highp int; varying vec3 vNormal; ${ new Array(6) .fill() .map((_, i) => `uniform vec3 u_color${i};` ) .join('') } void main() { vec3 color = (vNormal.x > 0.0) ? u_color0 : (vNormal.x < 0.0) ? u_color1 : (vNormal.y > 0.0) ? u_color2 : (vNormal.y < 0.0) ? u_color3 : (vNormal.z > 0.0) ? u_color4 : (vNormal.z < 0.0) ? u_color5 : vec3(0.50) ; gl_FragColor = vec4(color, 1.0); } `; const w = 720; let theShader; function setup() { createCanvas(w, w, WEBGL); textureMode(NORMAL); colorMode(HSB); noStroke(); theShader = createShader(vs, fs); shader(theShader); set_uniform(theShader); } function draw(){ background(0); fill(0, 0, 0, 0); shader(theShader); rotateX(frameCount * 0.010); rotateY(frameCount * 0.011); rotateZ(frameCount * 0.012); box(w * 0.5); } function set_uniform(in_shader) { let u_c = new Array(6); u_c[0] = color(0, 100, 100); //red u_c[1] = color(60, 100,100); //yellow u_c[2] = color(120, 100, 100); //green u_c[3] = color(180, 100,100); //sky u_c[4] = color(240, 100, 100); //blue u_c[5] = color(300, 100,100); //pink new Array(6) .fill() .map(function(_, ii){ u_c[ii] = color_set(u_c[ii]); in_shader.setUniform(`u_color${ii}`, u_c[ii]); }); } function color_set(in_color) { let vec_color = [red(in_color)/255.0, green(in_color)/255.0, blue(in_color)/255.0]; return vec_color; }
Boxを回転させているので、実行した際は動画でみることができるはずです。 ここでは画像で実行時の一部を抜き出しました。
色の塗り分けは以下のようにしました。
- +x方向なら 赤色
- -x方向なら 黄色
- +y方向なら 緑色
- -y方向なら 水色
- +z方向なら 青色
- -z方向なら 桃色
実行画面を確認すると、各面が指定した色で塗られているのがわかります。 一色ずつ塗り分けがわかるように実行して確認してみると、より深く理解できると思います。
まとめ
3D図形のBoxで法線の方向(面の向き)を使って、各面を異なる色で塗り分けることができました。
各面に異なる模様をつけたり、応用が色々考えられると思います。