8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GLSLレイマーチング研究_距離関数について勉強してみた15(Heartの関数を作ってみた)

Last updated at Posted at 2017-03-22

今回は、少し別枠で、自分で距離関数を作ってみました。

ちょっといろいろ諸事情でハートの距離関数が必要になったので、せっかくなので、作ってみました。

参考記事:ハートの方程式

x^2 + (y-x^\frac{2}{3})^2 = 4

コードへの落とし方

\begin{align}
&x^2 + (y-x^\frac{2}{3})^2 = 4 \\
&x^2 + (y-x^\frac{2}{3})^2 - 4 = 0 \\
&(\sqrt{x^2 + (y-x^\frac{2}{3})^2} - 2)(\sqrt{x^2 + (y-x^\frac{2}{3})^2} + 2) = 0 \\
&(\sqrt{x^2 + (y-x^\frac{2}{3})^2} + 2) > 0 より \\
&(\sqrt{x^2 + (y-x^\frac{2}{3})^2} - 2) = 0
\end{align}

コードに落とす(C++で書き直す)と

return sqrt(p.x*p.x+(p.y-pow(0.5*p.x*p.x, 0.3333))*(p.y-pow(0.5*p.x*p.x, 0.3333)))-2.0;

描画すると,

キャプチャ.PNG

のxにzを足すと

x^2+z^2 + (y-x^\frac{2}{3})^2 = 4

コードへの落とし方

\begin{align}
&x^2 + z^2 + (y-x^\frac{2}{3})^2 = 4 \\
&x^2 + z^2 + (y-x^\frac{2}{3})^2 - 4 = 0 \\
&(\sqrt{x^2 + z^2 + (y-x^\frac{2}{3})^2} - 2)(\sqrt{x^2 + z^2 + (y-x^\frac{2}{3})^2} + 2) = 0 \\
&(\sqrt{x^2 + z^2 + (y-x^\frac{2}{3})^2} + 2) > 0 より \\
&(\sqrt{x^2 + z^2 + (y-x^\frac{2}{3})^2} - 2) = 0
\end{align}

コードに落とす(C++で書き直す)と

return sqrt(p.x*p.x+p.z*p.z+(p.y-pow(0.5*p.x*p.x, 0.3333))*(p.y-pow(0.5*p.x*p.x, 0.3333)))-2.0;

キャプチャ02.PNG

いい具合に係数を合わせて,

0.83x^2+z^2 + (y-0.5x^\frac{2}{3})^2 = 4

キャプチャ03.PNG

距離関数を書くと

return sqrt(0.7*p.x*p.x+p.z*p.z+(p.y-pow(0.5*p.x*p.x, 0.3333))*(p.y-pow(0.5*p.x*p.x, 0.3333)))-2.0;

lengthありで書くと

vec3 q = vec3(0.83*p.x, (p.y-pow(0.5*p.x*p.x, 0.3)), p.z);
return length(q)-2.0;

最後に回転させて

motion02.gif

完成

ソース

// ============================================================================
// Heart
// ============================================================================

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

// Heartの距離関数
float sdHeart(vec3 p)
{
    // 回転
    // 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;

    /* Heart距離関数 */
    // return sqrt(0.7*p.x*p.x+p.z*p.z+(p.y-pow(0.5*p.x*p.x, 0.3333))*(p.y-pow(0.5*p.x*p.x, 0.3333)))-2.0;

    /* Heart距離関数(lengthあり) */
    vec3 q = vec3(0.83*p.x, (p.y-pow(0.5*p.x*p.x, 0.3)), p.z);
    return length(q)-2.0;
}

// 距離関数を呼び出すハブ関数
float distanceHub(vec3 p){
    return sdHeart(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*240.0/255.0, diff*128.0/255.0, diff*128.0/255.0), 1.0);
    }else{
        // 衝突しなかった場合はそのまま黒
        gl_FragColor = vec4(vec3(0.0, 0.0, 0.0), 1.0);
    }
}
8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?