すだちキャンパス

すだちキャンパス

やってみたこと、学んだことなどのメモ。

TouchDesignerとGLSLでキューブマッピング

こんにちは。
TD上で、GLSLだけでキューブマッピングをしてみました。

キューブマッピングとは

背景に箱型にした画像を置き、それが写り込んでいるように球などを描画すること・・・だと思っています。
今回はフラグメントシェーダーだけで、頂点シェーダーを使わないので、レイマーチングという方法を用いました。

画像の読み込み

まずは画像をキューブマッピングに使える形で読み込みます。
TDでは、360度カメラなどで撮影した画像を読み込んで projection TOP を用いるとキューブ型に変換してくれます。
f:id:sweetgohan:20191105031351p:plain

そのまま projection TOP を GLSL TOP につなぎ、

#define cubeImage sTDCubeInputs[0]

で読み込みます。

レイマーチング

レイマーチングとは、カメラから光線が出ていると考え、その光線がぶつかった物体から描画していくという手法です。この方法を使うと、平面に描いているのに立体的に見えます。
具体的には、for文を書くことで少しづつ光線を伸ばしていくイメージです。そのため、for文を回す回数が少ないとギザギザします。
最後に、光線がぶつかった場所に球を描画(今回は反射ベクトルを計算)して完了です。

#define cubeImage sTDCubeInputs[0]
uniform float     iTime;

vec2 fragCoord = vUV.xy * iResolution;
float zoom = 2.0;
const float sphereSize = 1.0;

float sphereFunc(vec3 p){
    return length(p) - sphereSize;
}

out vec4 fragColor;

void main()
{
    float time = iTime;
    vec2 p = (fragCoord.xy * 2.0 - iResolution) / min(iResolution.x, iResolution.y);
    
    // camera
    vec3 cameraPos = vec3(0.0,  0.0, zoom);
    vec3 cameraDir = vec3(0.0,  0.0, -1.0);
    vec3 cameraUp  = vec3(0.0,  1.0,  0.0);
    vec3 cameraSide = cross(cameraDir, cameraUp);
    float depth = 1.0;

    // レイマーチング 
    vec3 ray = normalize(cameraSide * p.x + cameraUp * p.y + cameraDir * depth);
    float distance = 0.0;
    float rayLength = 0.0;
    vec3  rayPos = cPos;
    for(int i = 0; i < 64; i++){
        distance = sphereFunc(rayPos);
        rayLength += distance;
        rayPos = cameraPos + ray * rayLength;
    }

	vec3 ref;
	vec3 normal = normalize(rayPos);

	if(abs(distance) < 0.001){
		vec3 spherePos = vec3(0.0); 
    	        ref = reflect(spherePos - cameraPos, normal);
	}else{
    	        ref = normal;
	}

        color  = texture(cubeImage, ref).rgb;
        fragColor = TDOutputSwizzle(vec4(color, 1.));
}

カメラの回転

せっかくなので、カメラを回転させます。位置と向きに回転行列をかければ回転します。

//回転行列
mat3 rotate(float angle){
    float c = cos(angle);
    float s = sin(angle);
    return mat3(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0,  c); 
}