のぐそんブログ

暗いおじさんがシコシコ書くブログです。

TouchDesignerのFeedback TOPを使う

Feedback TOPの使い方がイマイチわからなかったのでメモがわりにまとめます。

Feedback TOPは、フレームの映像を薄く残していくために使います。

基本的な使い方は以下のようにオペレーターをループさせて合成していきます。

TouchDesigner___Users_nogson_Desktop_NewProject_1_toe.png

Feedback TOPは現在のフレームよりも前のフレームを表示してくれる為、ループすることで下のように残像を残すことができます。

10月-11-2017 23-18-58.gif

続きを読む

アルファブレンディングやってみる

アルファブレンディングとはその名の通り、不透明表示のことです。 ポイントはmaterialのtransparenttrueにすることです。

GLSLでテクスチャを貼っているので、フラグメントシェーダー側で透明度を設定します。 ※GLSLでテクスチャを貼っている意味はあまりないです。

続きを読む

glslでテクスチャをはる

glsl側でテクスチャを貼ってみたいと思います。 画像はTHREE.ImageUtils.loadTextureで読み込んでuniform変数として渡します。

渡した画像は、glslのビルドイン関数であるtexture2Dを利用します。 テクスチャの型はsampler2Dを利用します。

precision mediump float;
uniform sampler2D uTex;
varying vec2 vUv;

void main(){
   gl_FragColor = texture2D(uTex,vUv);
}
続きを読む

法線でライトを表現する

WebGLでライトを実装する為に最低限理解しておく必要基礎知識でライトと法線の関係について記載しましたが、実際に法線をつかってライトを表現してみようと思います。

ライトベクトル

ライトの向きのことをライトベクトルと言います。

ライトと記載していますが、ライトの実態は「平行光源」です。 平行光源は3D空間の全てに一様の向きで当たりますので、ライトの向きだけを利用します。

その為、ライトベクトルの値は法線と違い空間上で1つです。どの頂点からみてもライトベクトルの値は同じになります。

Kobito.xSNfYZ.png

ライトベクトルの正規化

ライトベクトルは向きしか利用しない為、正規化して利用します。 正規化にはGLSLのビルドイン関数であるnormalizeを利用します。

vec3 lightDirection = normalize(vec3(0.0, 0.0, 1.0));
ライトの影響度を計算

WebGLでライトを実装する為に最低限理解しておく必要基礎知識でも書きましたが、ライトの影響度はライトベクトルと、法線の内積で求められます。

GLSLでは内積ようの関数であるdotが用意されています。

使い方はdot(A,B)のように内積を求める値を引数として設定します。

//ライトの向き
vec3 lightDirection = normalize(vec3(0.0, 0.0, 1.0));
//normalは法線の値
float diffuse = max(dot(normal,lightDirection),0.0);

実行結果

実際に、ライトベクトルと法線を使って、ライトを実装してみます。

JS
const myVert = require('./../shader/sample.vert');
const myFrag = require('./../shader/sample.frag');


window.onload = () => {
  let windowWidth = window.innerWidth;
  let windowHeight = window.innerHeight;

  // rendererの作成
  let renderer = new THREE.WebGLRenderer();
  // canvasをbodyに追加
  document.body.appendChild(renderer.domElement);

  // canvasをリサイズ
  renderer.setSize(windowWidth, windowHeight);

  // scene作成
  let scene = new THREE.Scene();
  // camera作成
  let camera = new THREE.PerspectiveCamera(75, windowWidth / windowHeight, 0.1, 1000);
  camera.position.z = 1;

  // Geometry作成
  let geometry =new THREE.SphereBufferGeometry( 0.1, 10, 10 );

  // Material作成
  let material = new THREE.RawShaderMaterial({
    vertexShader: myVert,
    fragmentShader: myFrag,
  });
  
  // Mesh作成
  let mesh = new THREE.Mesh(geometry, material);

  // Meshをシーンに追加
  scene.add(mesh);

  // draw
  render();

  var r = 0;

  //描画
  function render() {
    renderer.render(scene, camera);

    r += 0.01;

    mesh.rotation.set(0,r,r); 

    // animation
    requestAnimationFrame(render);
  }

};
vert(頂点シェーダー)
attribute vec3 normal;
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
varying vec4 vColor;

const vec3 lightDirection = normalize(vec3(0.0, 0.0, 1.0));

void main() {
  float diffuse = max(dot(normal,lightDirection),0.0);

  vColor = vec4(vec3(0.5),1.0) * vec4(vec3(diffuse), 1.0);
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
frag(フラグメントシェーダー)
precision mediump float;
varying vec4 vColor;

void main(){
  gl_FragColor = vColor;
}

See the Pen RLVZMQ by nogson (@satofaction) on CodePen.

法線の回転

上記の例の場合、ライトの実装はできていますが、オブジェクトを回転させると影もついていってしまいます。 ライトの位置が変わらない場合は、オブジェクトが回転しても影のつき方は、一定方向になるはずです。

なぜ、影も回転してしまうかというと、オブジェクトの回転に合わせて法線の向きも移動させる必要があるからです。 法線の回転を行う為にThree.jsではnormalMatrixという行列が用意されています。

  vec3 n = normalMatrix * normal;
  float diffuse = max(dot(n,lightDirection),0.0);

normalMatrix(法線を正しい向きにする変換行列)は何をやっているかと言うと、モデル座標変換行列の逆転置行列を使うようです。

法線を回転した実行結果

See the Pen wrdrvb by nogson (@satofaction) on CodePen.

法線をオブジェクトの回転にあわせて回転させることで、影の方向が一定になりました。

まとめ

とにかくシェーダーは難しいです。慣れるしかなさそうです。。。

TouchDesugberで階層の違うオペレータをつなぐ

Geometry COMP内のTransform SOPなどに違う階層から、値を送るのはどうしたらいいのかなと思っていたら、こちらの記事に書いてありました。

画面左上の「Pane Layout」で画面を分割することができます。 画面を分割することで、階層ごとにオペレータをつなぐことができました。

こんな感じになります。 知らないことが多いですが便利な使い方が沢山ありそうです。

THREE.jsでフラグメントシェーダを使ってみるの基礎基礎メモ1

フラグメントシェーダを使って色を変更してみたいと思います。

基礎の復習

ベースとなるコードです。

js
window.onload = () => {
  let windowWidth = window.innerWidth;
  let windowHeight = window.innerHeight;

  // rendererの作成
  let renderer = new THREE.WebGLRenderer();
  
  // canvasをbodyに追加
  document.body.appendChild(renderer.domElement);

  // canvasをリサイズ
  renderer.setSize(windowWidth, windowHeight);

  // scene作成
  let scene = new THREE.Scene();
  
  // camera作成
  let camera = new THREE.PerspectiveCamera(75, windowWidth / windowHeight, 0.1, 1000);
  camera.position.z = 100;

  // Geometry作成
  let geometry = new THREE.PlaneBufferGeometry(100, 100);
  
  // Material作成
  let material = new THREE.ShaderMaterial({
    vertexShader: myVert,
    fragmentShader: myFrag,
    uniforms:{
      uColor: {type: "c", value: new THREE.Color(0xFF0000)}
    }
  });
  
  // Mesh作成
  let mesh = new THREE.Mesh(geometry,material);

  // Meshをシーンに追加
  scene.add(mesh);

  // draw
  renderer.render(scene, camera);
};
vert(頂点シェーダー)
void main() {
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
frag(フラグメントシェーダー)
precision mediump float;

 uniform vec3 uColor;

void main(){    
  gl_FragColor =vec4(uColor, 1.0);
}
結果

Kobito.yP7wXn.png

マウス座標で色を変えてみる

マウス座標を取得して色を変更してみたいと思います。 requestAnimationFrameでuniformsを更新していきます。

js
window.onload = () => {
  let windowWidth = window.innerWidth;
  let windowHeight = window.innerHeight;
  let mouse = new THREE.Vector2(0.0, 0.0);

  // rendererの作成
  let renderer = new THREE.WebGLRenderer();
  
  // canvasをbodyに追加
  document.body.appendChild(renderer.domElement);

  // canvasをリサイズ
  renderer.setSize(windowWidth, windowHeight);

  // scene作成
  let scene = new THREE.Scene();
  // camera作成
  let camera = new THREE.PerspectiveCamera(75, windowWidth / windowHeight, 0.1, 1000);
  camera.position.z = 100;

  // Geometry作成
  let geometry = new THREE.PlaneBufferGeometry(100, 100);
  
  // Material作成
  let material = new THREE.ShaderMaterial({
    vertexShader: myVert,
    fragmentShader: myFrag,
    uniforms: {
        uMouse: {
        type: "v2",
        value: mouse
      },
    }
  });
  
  // Mesh作成
  let mesh = new THREE.Mesh(geometry, material);

  // Meshをシーンに追加
  scene.add(mesh);

  //マウス座標を取得
  renderer.domElement.addEventListener('mousemove', function (e) {
    mouse = new THREE.Vector2(
      e.clientX / windowWidth,
      e.clientY / windowHeight);
  }, false);

  // draw
  render();

  //描画
  function render() {
    renderer.render(scene, camera);
    
    material.uniforms.uMouse.value = mouse;

    // animation
    requestAnimationFrame(render);
  }

};
frag(フラグメントシェーダー)
precision mediump float;

 uniform vec2 uMouse;

void main(){
  // テクスチャ座標をカラーに出力
  gl_FragColor =vec4(uMouse.x,uMouse.y,0.0, 1.0);
}
結果

マウスを動かすと色が変わります。

See the Pen vJqRqb by nogson (@satofaction) on CodePen.

経過時間で色を変えてみる

window.onload = () => {
  let windowWidth = window.innerWidth;
  let windowHeight = window.innerHeight;
  let clock = new THREE.Clock();
  let time = 0.0;

  // rendererの作成
  let renderer = new THREE.WebGLRenderer();
  
  // canvasをbodyに追加
  document.body.appendChild(renderer.domElement);

  // canvasをリサイズ
  renderer.setSize(windowWidth, windowHeight);

  // scene作成
  let scene = new THREE.Scene();
  // camera作成
  let camera = new THREE.PerspectiveCamera(75, windowWidth / windowHeight, 0.1, 1000);
  camera.position.z = 100;

  // Geometry作成
  let geometry = new THREE.PlaneBufferGeometry(100, 100);
  
  // Material作成
  let material = new THREE.ShaderMaterial({
    vertexShader: myVert,
    fragmentShader: myFrag,
    uniforms: {
        uTime: {
        type: "f",
        value: time
      },
    }
  });
  
  // Mesh作成
  let mesh = new THREE.Mesh(geometry, material);

  // Meshをシーンに追加
  scene.add(mesh);

  //マウス座標を取得
  renderer.domElement.addEventListener('mousemove', function (e) {
    mouse = new THREE.Vector2(
      e.clientX / windowWidth,
      e.clientY / windowHeight);
  }, false);

  // draw
  render();

  //描画
  function render() {
    renderer.render(scene, camera);
    
    //経過時間を取得
    time  = clock.getElapsedTime();
    material.uniforms.uTime.value = time;

    // animation
    requestAnimationFrame(render);
  }

};
frag(フラグメントシェーダー)
precision mediump float;
 uniform float uTime;

void main(){
  float t = abs(cos(uTime));
  gl_FragColor =vec4(t,t,t, 1.0);
}
結果

See the Pen YxovGW by nogson (@satofaction) on CodePen.

まとめ

すごい基礎的な部分なのですが、なかなか上手くいきません。 とにかく色々やってみるしかありません。