GLSLレイマーチング研究_距離関数について勉強してみた11(Triangular Prismの関数をいじる)

[modeling with distance functions](http://iquilezles.org/www/articles/distfunctions/distfunctions.htm)の距離関数の一覧に沿って記事を書いています.

二次元のグラフの描画は、[Desmos Graphing Calculator](https://www.desmos.com/) を使っています.

# やっていることは、[Hexagonal](http://qiita.com/muripo_life/items/48605fc427e41e3884bb)と同じです.

![Triangular_Prism.PNG](https://qiita-image-store.s3.amazonaws.com/0/102634/d43d902e-9bb7-e8e0-d334-72d14244b665.png)

## 距離関数

```c++
// Triangular Prism
vec3 q = abs(p);
vec2 h = vec2(1.0, 1.0);
return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);
```

## 導出方法

前回の

```math

|x| + |y| = 1 (-1<x<1)

```

から y の絶対値をぬいた.

```math
|x| + y = 1(−1<x<1)
```

を使う.

![Triangular_Prism01.PNG](https://qiita-image-store.s3.amazonaws.com/0/102634/47734461-2359-a6fc-1d5c-b1ff303c47aa.png)

係数を合わせて,

```math
\sin(\frac{\pi}{3})|x|+\sin(\frac{\pi}{6})y = 1 (-1<x<1)
```

![Triangular_Prism02.PNG](https://qiita-image-store.s3.amazonaws.com/0/102634/dd9bea69-cf1b-0d46-48ba-ae091110075d.png)

[数式のリンク](https://www.desmos.com/calculator/lg5i6zcyfn)

で、距離関数はこれ、

```c++
// Triangular Prism1
float radio = 1.0; // 一辺の長さ
float hight = 1.0; // 厚さ（高さ）
return max(abs(p.z)-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y)-radio);
```

もとに、記事の通りだとこれ

```c++
// Triangular Prism2
vec3 q = abs(p);
float radio = 1.0; // 一辺の長さ
float hight = 1.0; // 厚さ（高さ）
return max(q.z-hight,max(q.x*0.866025+p.y*0.5, -p.y)-radio);
```

## 三角柱の距離関数をいじる

### アニメーション1

```c++
// motion01
return max(abs(p.z)-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y*sin(time))-radio);
```

![motion01.gif](https://qiita-image-store.s3.amazonaws.com/0/102634/aa31fad4-bf11-f473-75a3-2ac8b0e8b5eb.gif)


### アニメーション2
* x軸回転を入れる
* z成分を `abs(sin(time))` 倍する

```c++
// 回転
mat3 m_x = mat3(1,0,0,0,cos(time),-sin(time),0,sin(time),cos(time));
p = m_x * p;
return max(abs(p.z*abs(sin(time)))-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y)-radio);

```

![motion02.gif](https://qiita-image-store.s3.amazonaws.com/0/102634/a1e7f614-99d6-bacc-283f-d14053748649.gif)


## アニメーション3

けいれんぽい感じ

`p.x` に　`max(abs(p.x)*0.866025, abs(p.x)*abs(sin(exp(10.0*abs(sin(time)))))` を入れる.

```c++
// motion03
return max(abs(p.z)-hight,max(max(abs(p.x)*0.866025, abs(p.x)*abs(sin(exp(10.0*abs(sin(time))))))+p.y*0.5, -p.y)-radio);
```

![motion03.gif](https://qiita-image-store.s3.amazonaws.com/0/102634/0246570b-0dab-b719-9d56-c3d5c60c43b3.gif)

## アニメーション4

砂嵐ぽいもの

そとの `max` を `mod` に変えました。

```c++
// motion04
mat3 m_x = mat3(1,0,0,0,cos(time),-sin(time),0,sin(time),cos(time));
p = m_x * p;
return mod(abs(p.z)-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y)-radio);
```

![motion04.gif](https://qiita-image-store.s3.amazonaws.com/0/102634/a165e977-672f-0d99-77ca-e25b20f1c9ef.gif)

[コード](https://github.com/muripoLife/RayMarchingDistanceFunction/blob/master/11/fsp.frag)

```c++
// ============================================================================
// Triangular Prism function
// ============================================================================

precision mediump float;
uniform vec2  resolution;    // resolution (512.0, 512.0)
uniform vec2  mouse;         // mouse      (-1.0 ~ 1.0)
uniform float time;          // time       (1second == 1.0)
uniform sampler2D prevScene; // previous scene texture

// Triangular Prismの距離関数
float sdTriPrism(vec3 p)
{
    float radio = 1.0; // 一辺の長さ
    float hight = 1.0; // 厚さ（高さ）

    // 回転
    // mat3 m_x = mat3(1,0,0,0,cos(time),-sin(time),0,sin(time),cos(time));
    // p = m_x * p;
    // mat3 m_y = mat3(cos(time),0,-sin(time),0,1,0,sin(time),0,cos(time));
    // p = m_y * p;
    // mat3 m_z = mat3(cos(time),-sin(time),0,sin(time),cos(time),0,0,0,1);
    // p = m_z * p;
    // mat3 m_x = mat3(1,0,0,0,cos(1.57),-sin(1.57),0,sin(1.57),cos(1.57));
    // p = m_x * p;

    // Triangular Prism1
    return max(abs(p.z)-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y)-radio);

    // Triangular Prism2
//  vec3 q = abs(p);
//  return max(q.z-hight,max(q.x*0.866025+p.y*0.5, -p.y)-radio);

    // motion01
//  return max(abs(p.z)-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y*sin(time))-radio);

    // motion02
//     mat3 m_x = mat3(1,0,0,0,cos(time),-sin(time),0,sin(time),cos(time));
//     p = m_x * p;    
//  return max(abs(p.z*abs(sin(time)))-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y)-radio);

    // motion03
    //  return max(abs(p.z)-hight,max(max(abs(p.x)*0.866025, abs(p.x)*abs(sin(exp(10.0*abs(sin(time))))))+p.y*0.5, -p.y)-radio);

    // motion04
    // mat3 m_x = mat3(1,0,0,0,cos(time),-sin(time),0,sin(time),cos(time));
    // p = m_x * p;
    // return mod(abs(p.z)-hight,max(abs(p.x)*0.866025+p.y*0.5, -p.y)-radio);

}

// 距離関数を呼び出すハブ関数
float distanceHub(vec3 p){
    return sdTriPrism(p);
}

// 法線を生成する
vec3 genNormal(vec3 p){
    float d = 0.001;
    return normalize(vec3(
        distanceHub(p + vec3(  d, 0.0, 0.0)) - distanceHub(p + vec3( -d, 0.0, 0.0)),
        distanceHub(p + vec3(0.0,   d, 0.0)) - distanceHub(p + vec3(0.0,  -d, 0.0)),
        distanceHub(p + vec3(0.0, 0.0,   d)) - distanceHub(p + vec3(0.0, 0.0,  -d))
    ));
}

void main(){
    // スクリーンスペースを考慮して座標を正規化する
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
    // カメラを定義する
    vec3 cPos = vec3(0.0,  0.0,  5.0); // カメラの位置
    vec3 cDir = vec3(0.0,  0.0, -1.0); // カメラの向き(視線)
    vec3 cUp  = vec3(0.0,  1.0,  0.0); // カメラの上方向
    vec3 cSide = cross(cDir, cUp);     // 外積を使って横方向を算出
    float targetDepth = 1.0;           // フォーカスする深度
    // カメラの情報からレイを定義する
    vec3 ray = normalize(cSide * p.x + cUp * p.y + cDir * targetDepth);
    // マーチングループを組む
    float dist = 0.0;  // レイとオブジェクト間の最短距離
    float rLen = 0.0;  // レイに継ぎ足す長さ
    vec3  rPos = cPos; // レイの先端位置(初期位置)
    for(int i = 0; i < 32; ++i){
        dist = distanceHub(rPos);
        rLen += dist;
        rPos = cPos + ray * rLen;
    }
    // レイとオブジェクトの距離を確認
    if(abs(dist) < 0.001){
        // 法線を算出
        vec3 normal = genNormal(rPos);
        // ライトベクトルの定義
        vec3 light = normalize(vec3(1.0, 1.0, 1.0));
        // ライトベクトルとの内積を取る
        float diff = max(dot(normal, light), 0.1);
        // gl_FragColor = vec4(vec3(diff, diff, diff), 1.0);
        gl_FragColor = vec4(vec3(diff*177.0/255.0, diff*120.0/255.0, diff*68.0/255.0), 1.0);
    }else{
        // 衝突しなかった場合はそのまま黒
        gl_FragColor = vec4(vec3(0.0, 0.0, 0.0), 1.0);
    }
}
```