のぐそんブログ

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

最近覚えたTouchDesignerのちょっとしたメモ1

最近覚えたTouchDesignerのちょっとしたメモです。 自分用のメモなのであまり参考にはならないと思います。

360度の値を作る

LFO CHOPはTypeをRampを設定する。 Math CHOPはRangeのto Rangeを0~360**を設定する。

0、1の値を作成する

switchなどで表示を連続して切り替える場合に、0と1の値を取得したい場合があります。

LFO CHOPはTypeをSquaerを設定する。 Math CHOPはRangeのFrom Rangeを-1~1to Rangeを0~1 **を設定する。

背景をつける

一番簡単な方法としては、背景にはconstant TOPを利用します。 constant TOPはアルファ付き単色画像として利用できます。

ポイントとしては、constant TOPの解像度をメインのビジュアルと同じにすることです。

背景とメインのビジュアルを重ねるためには、Over TOPを利用します。

グラデーションの背景にしたい場合は、constant TOPの代わりにRamp TOPを利用する。

カメラの向きを固定する

Look Atを利用することでカメラが移動しても、常に一定の方向を向かせることができます。

Camera COMPのLook atにNull COMPを設定します。

◎Null COMPのTranslateが「0,0,0」の場合

◎Null COMPのTranslateが「3,3,3」の場合

Filter TOPを利用してボタンの値を滑らかに変化させる

Button COMPとFilter TOPをあわせて使うと、ボタンを押した際の値(0 ~ 1)を滑らかに変化させることができます。

パスに沿ってをカメラを移動させる

パスに沿ってカメラを移動させてみます。 Camera COMPのPath SOPに、ガイド用のSOPを作成します。 以下の例では、Circle SOPを利用しています。

カメラの動きはイメージです。 circleに沿って回ります。

サンプルはこちら

3Dオブジェクトの頂点情報を取得

3Dオブジェクトの頂点座標をデータとして取得する際は、「SOP to CHOP」を利用しました。 だだし、取得できるのはX,Y,Zの座標データのみでした。

ちなみにここでは、Sphere SOP」を利用してます。

上記の画像のP(0~2)tx ty tzに当たります。 もしN(0~2)を取得したい場合は、下記のように記載します。

※ちなみにNは法線情報だと思います。Pwは何だろう。。。

Pwの値も取得したい場合は下記になります。

ちなみに下記のよううな書き方でも問題ないです。

3Dオブジェクトの頂点情報をデータとして利用する

TouchDesignerで3Dオブジェクトから頂点座標を抜き出す

3Dオブジェクトから頂点座標を抜き出して、データとして利用する方法のメモです。

①SOPから、好きな3Dオブジェクトを配置。
②オペレーターの右下にある「 + 」ボタンを押す。

③右クリックでコンテキストメニューから「Display Options」を選択

トラックパッドの場合は2点タッチ

④メニューからAllを選択

⑤SOP toオペレーターをつかって頂点座標を数値化する

頂点座標に3Dオブジェクトを配置する

3Dオブジェクトを利用するためには、「Camera COMP」、Light COMP」、「Geometry COMP」が必要です。

インスタンスを利用する

①Geometoryでインスタンスを利用できるようにする

Geometryを選択して、「instancce」タブを選択して「Instancing」をONにします。 ONにすることで、「Instance CHOP/DAT」を選択できるようになります。

②頂点データをインスンタンスに設定する

インスタンスの座標を割り当てる

②で設定した頂点データをどの座標として使うかを設定する。

④頂点に設定されているgeometoryの大きさを調整

Box SOPをSIZE「0.01,0.01,0.01」で設定する。

その他

頂点データの詳しい内容は、DATAのSOP toオペレーターで確認することができる。

f:id:nogson2:20180410233926p:plain

まとめ

最終的にはこんな感じになります。 基礎的な部分ですがよく使う方法らしいので、覚えておくようにしたいと思います。

GPGPUがまったくわからないのでGPUComputationRenderer.jsをまず調べてみるメモ

GPGPU用のヘルパーライブラリであるGPUComputationRenderer.jsの使い方を調べてみました。

GPGPUが難しいので上手く説明できておらず、よくわからない文章になってしまっています。 あまり参考にならないかもしれません。

こちらの「Three.jsのGPGPUのサンプルが難しすぎるから解体して勉強してみる」のがとてもわかりやすので参考になります。

やること事

なんとなくのイメージこんな感じです。 GPGPUなのでテクスチャをデータ格納用に利用します。 テクスチャは、参照用と、データ格納用を作成して毎レーム入れ替えていきます。 ※複数のフレームバッファを使う場合です。1つだけの場合は「オフスクリーンレンダリング2」はいりません。

STEP 1

GPUComputationRendererのインスタンスを作成する。

引数のwidth, height, rendererはオフスクリーンレンダリング用のWebGLRenderTargetや、DataTextureを作成する際に利用される。

var gpuRender = new GPUComputationRenderer(width, height, renderer);

GPUComputationRendererのインスタンスを作成すると、はじめに下記のようなオブジェクトが作成される。

var material = new THREE.ShaderMaterial( {
  uniforms:{
    texture: { value: null }
  },
  vertexShader: vs,//中身は↓に記載
  fragmentShader: fs//中身は↓に記載
} );

var geometory =  new THREE.PlaneBufferGeometry( 2, 2 );

var mesh = new THREE.Mesh(geometory, material );
◎vs
void main()  {
    gl_Position = vec4( position, 1.0 );
}

◎fs

uniform sampler2D texture;

void main() {
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    gl_FragColor = texture2D( texture, uv );
}

STEP 2

テクスチャを作成する。

var textuer = gpuCompute.createTexture();

GPUComputationRenderer内で以下の処理が実行されテクスチャデータが作成される。

var arr = new Float32Array( width * height * 4 );
var texture = new THREE.DataTexture( arr, width, height, THREE.RGBAFormat, THREE.FloatType );
texture.needsUpdate = true;

STEP 3

matrialやtextuerなどのデータを格納しておくオブジェクトを作成する。

第二引数はフラグメントシェーダを指定します。 第三引数にはテクスチャを指定します。

var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, textuer );

GPUComputationRenderer内で以下の処理が実行され、設定した内容が保持される。

var material = new THREE.ShaderMaterial( {
  uniforms:{},
  vertexShader: vs,//中身は↓に記載
  fragmentShader: fragmentShaderVel
} );


var variable = {
  name: "textureVelocity",
  initialValueTexture: textuer,
  material: material,
  dependencies: null,
  renderTargets: [],
  wrapS: null,
  wrapT: null,
  minFilter: THREE.NearestFilter,
  magFilter: THREE.NearestFilter
};

//作成したデータをインスタンス内に保持する
this.variables.push( variable );
◎vs
void main()  {
    gl_Position = vec4( position, 1.0 );
}

STEP 4

velVar、posVarに設定されたフラグメントシェーダーそれぞれからSTEP 2で作成したテクスチャが参照できるようする為の前準備。 シェーダー間でテクスチャを参照できるようになる。

下記の場合は、velVarのフラグメントシェーダから、velVar、posVarのテクスチャを参照することができる。

gpuCompute.setVariableDependencies( velVar, [ velVar, posVar] );

velVarのフラグメントシェーダから、velVarのテクスチャの参照だけで良い場合は、下記のような定義になる。

gpuCompute.setVariableDependencies( velVar, [ velVar] );

STEP 5

オフスクリーンレンダリング用のWebGLRenderTargetを作成する。

「STEP 3」で空だったrenderTargetsの配列にWebGLRenderTargetのインスタンスを追加します。

gpuCompute.init()

GPUComputationRenderer内では、同じWebGLRenderTargetが2つ作成される。

variable.renderTargets[ 0 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter );
variable.renderTargets[ 1 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter );

また設定しているフラグメントシェーダーの頭に、テクスチャの読みこみ用の定義が追加される。

自分で用意したフラグメントシェーダーにuniform sampler2Dの定義がないのに、何故テクスチャが参照できるのだろうと疑問におもっていたがここでライブラリが自動で挿入してくれていた。

uniform sampler2D textureVelocity;
uniform sampler2D texturePosition;

//↓↓fragmentShaderVelに定義した処理がはいる↓↓

material(shaderMaterial)にも、uniformの定義が追加される。 この段階ではまだ、テクスチャの値はnull。

uniforms.textureVelocity = { value: null };

STEP 6

最後に毎フレーム毎に下記を実行して、参照用と格納用のテクスチャを切り替えていく。

gpuCompute.compute();

GPUComputationRenderer内では、STEP 5ではまだnullだったテクスチャデータに、 WebGLRenderTargetが挿入される。

サンプル

実際にサンプルを作りました。 このサンプルはオフスクリーンレンダリングは1つだけです。 内部的にはGPUComputationRendererがテクスチャを複製してくれるので2つです。

GPGPU SAMPLE

まとめ

GPUComputationRendererはGPGPUの面倒なところを代わりにやってくれるので、私のような初学者には大変助かるライブラリです。 だたし、中でなにをやっているかを正しく理解しないと、GPGPUとはなんなのかがわからなくなりそうです。

TouchDesignerで使いそうなデータ制御の基礎基礎メモ1

あくまで自分用ですが、使いそうだけど、すぐ忘れてしまいそうな基本的なデータの制御です。

一定の時間でカウントアップする

特定の処理をループしたい場合など、一定時間でカウントアップした値を作成したい場合はLFO CHOPを利用します。

正の整数だけ利用したい場合は、TypeをRampを選択します。

参考:LFO Saw Wave ?

カウントアップはCount CHOPを利用します。 カウントアップの閾値Trigger Thresholdを利用します。ここでは0.98を設定しています。

閾値を設定するとカウントアップされるようになりますが、どこかの値で0に戻したい場合は、LimitLoop Min/Maxにします。 そして、Limit Maximumに最大値を設定します。

オーディオデータの制御

オーディをデータはそのままだと、使いづらい場合があります。 Audio spectrum CHOPを利用することで、オーディオデータを正の整数にすることができます。 また、analyze CHOPを利用すると、特定の値を取得することができます。 analyze CHOPのFunctionをMaximumにすることで最大値のみ取得することができます。

ランダムな値を作る

ランダムな値をつくるにはNoise CHOPを利用します。

10月-14-2017 19-03-57.gif

Noise CHOPはcommonタブの、Time SliceをONにしないと動きが発生しません。

THREE.jsでグネグネしたメタボールを作成する

こちらを目指して、グネグネしたメタボール(呼び方がメタボールであってるのかわかりません)を作ってみたいと思い挑戦してみました。 結果としては、実現することが出来ませんでした。。。

実際に作成できたのはこちらです。

難しい。

JS

global.THREE = require('three');
const glslify = require('glslify');
const vertexShader = glslify('./src/js/shaders/circle/vertexShader.vert');
const fragmentShader = glslify('./src/js/shaders/circle/fragmentShader.frag');

const clock = new THREE.Clock();

let time = 0.0;
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
let dpr = window.devicePixelRatio;

const app = {
  renderer: new THREE.WebGLRenderer(),
  scene: new THREE.Scene(),
  camera: new THREE.PerspectiveCamera(60, windowWidth / windowHeight, 0.1, 1000)
};
const body = document.getElementsByTagName('body')[0];

app.renderer.setClearColor(new THREE.Color(0xffffff), 1.0);
app.renderer.setPixelRatio(window.devicePixelRatio || 1);

// canvasをbodyに追加
body.appendChild(app.renderer.domElement);

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

//LIGHTS
let light = new THREE.AmbientLight(0xffffff, 1.0);
app.scene.add(light);

app.camera.position.z = 1.5;

// Geometory作成
let geometry = new THREE.IcosahedronGeometry(0.5, 4);

// Material作成
let material = new THREE.ShaderMaterial({
  uniforms: {
    'time': {
      type: 'f',
      value: time
    },
    'resolution': {
      type: 'v2',
      value: new THREE.Vector2(windowWidth * dpr, windowHeight * dpr)
    }
  },
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  //wireframe:true
});

let mesh = new THREE.Mesh(geometry, material);

app.scene.add(mesh);

render();

function render() {
  time = clock.getElapsedTime();
  mesh.material.uniforms.time.value = time;
  app.renderer.render(app.scene,app.camera);
  requestAnimationFrame(render);
}

頂点シェーダー

ノイズはglsl-noiseを利用させていただいています。

#pragma glslify: cnoise = require(glsl-noise/classic/3d)

varying float noise;
uniform float time;
uniform vec2 resolution;

//グネグネの振り幅
const float amplitude = 0.5;
//グネグネのスピード
const float speed = 0.25;

void main() {
    noise = cnoise( vec3(normal * amplitude + time * speed));

    vec3 p = position + normal * noise * 0.2;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( p, 1.0 );
}

フラグメントシェーダー

#ifdef GL_ES
precision highp float;
#endif

uniform float time;

void main(){
     gl_FragColor = vec4(vUv, sin(time), 1.0);
}

まとめ

やってみて感じたポイントとしては、以下2点でした。

  • geometryにIcosahedronGeometry(正20面体)を利用すること
  • 頂点の歪みは法線(normal)を利用すること

頂点シェーダーだけがんばればグネグネさせることができました。

球体同士がつながるところはどのようにしたらいいのかがわかりませんでした。

フラグメントシェーダーで複数の円をグルグル回転させる

メタボールをやってみたいので、 まずは、フラグメントシェーダーで、複数の円をグルグル回転させてみたいと思います。

#ifdef GL_ES
precision highp float;
#endif
 
uniform float time;
uniform vec2 resolution;
 
#define XSpeed 1.50
#define YSpeed 1.50
#define size 0.1
#define count 10.0
const float PI = 3.1415926535897932384626433832795;


void main( void ) 
{
    //座標を正規化
    vec2 pos =(gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);;
    
    float c = 0.0;
    float rad = (PI*2.0) /count;

    for( float i = 1.0; i < count+1.0; ++i )
    {   
        //X軸の移動
        float px = cos( time * XSpeed + (i * rad)) ;

        //Y軸の移動 
        float py = sin( time * YSpeed + (i* rad));

        //circleの座標
        vec2 circlePos = vec2( px , py );

        //円のサイズを変更
        float d = size / length(pos - circlePos);

        //円のボケ幅を調整
        c += pow( d, 5.0 );
    }
 
    gl_FragColor = vec4(vec3(c), 1.0 );
 
}

動作はこちらで確認できます。