Face in Circle

上面的三個圓環有什麼特殊嗎?有一定抽象能力的人在離屏幕適當距離的時候可以看到以下三張臉(跟看碼一樣,離得越遠越清晰,近視眼超過400度的請摘掉眼鏡):



原始創意來自於一個視頻,用小釘釘成一個環,然後就可以不停的繞黑線,我只不過用Houdini實現了下,慚愧。

最核心的原理是這樣的:在數學上這些線叫“弦”。一條弦可以由過這個弦的一個點,和這條弦的方向矢量來表示,因爲有了這倆我們就可以求出交點來了。所以不管要形成什麼圖案,我們無非是要解答倆問題:在哪裏定這個點,穿過這個點的弦的方向如何。

容易想到的是1.點灑在黑的地方 2.弦儘量朝着可以穿過最多黑色的方向

問題1很好解決,scatter直接可以做到,問題2其實也容易,把弦離散化成N個點,把點對應的圖片位置的像素採樣加起來比較就可以了。

測試後發現如果點也往黑處撒弦也往黑處穿,會導致圖像過於黑白分明,摘掉眼鏡看時混合的不好,於是把點改成了均勻撒,效果改善很明顯。

以下是唯一的代碼:

float r = ch('r');
vector p1 = point(1, "P", 0);
vector p2 = @P;
vector a = p2 - p1, b = -p1;
vector a_n = normalize(a);
vector c = dot(normalize(a),b)*a_n - b;
vector delta = sqrt(r*r - dot(c, c))*a_n;
vector intersect0 = c + delta, intersect1 = c - delta;
if (length(intersect0 - intersect1)<ch('min_len'))
    return;

int pts[] = {};
vector l = intersect1 - intersect0;
for(int i=0; i<=chi('segment'); i++) {
    vector p = lerp(intersect0, intersect1, float(i)/chi('segment'));
    append(pts, addpoint(geoself(), p));
}
int prim = addprim(geoself(), "polyline", pts);

上面的代碼的作用就是定下倆點後求出和圓的交點,並分成segment段。因爲是vex所以執行效率相當高。

確保wrangle執行方式是point後,input1連任意個可能要穿過的方向(我用了一個低段數的圓,相當於uniform sample),input2連一個點,這段代碼就會生成所有通過input1和input2的弦。下一步就是比較然後選擇這些弦裏壓黑最多的那根保留了。經過這個之後就會對一個點(input2)選出一根線。對所有的點for一次後就可以生成圖像了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章