39
20

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 1 year has passed since last update.

Houdini ApprenticeAdvent Calendar 2020

Day 16

Houdini18.5 新ノードを使った作例!~従来の方法と一緒に~

Last updated at Posted at 2020-12-15

#はじめに
この記事は HoudiniApprenticeAdventCalendar2020 16日目の記事です。
Houdini Indie 18.5.351 、SideFX Labs 18.5.397を使用しています。

Houdiniは革新的なバージョンアップを繰り返す魅力的なツールであると同時に、
学習リソースとのバージョンの差があっという間に開いてしまう初学者殺しな一面もあります。
この記事では最近のアップデートによって、従来の方法が比較的らくにセットアップできるようになった事例をいくつか紹介したいと思います。

できるだけわかりやすく画像と文章で説明しようと思っているのですが、hipファイルを見ていただくのが一番わかりやすいと思いますので、併せてみていただくのをオススメします。

hipファイルはこちら

#もくじ
はじめに

バリエーションコピー(Scatter and Align, Attribute from Pieces)
ランダムアトリビュートの作成(Attribute Adjust 系SOP)
積もった雪の作例(Mask by Feature)
カーブ上に配置(Chain SOP)
いくつかのTransform操作(Match Size)

初学者向けの注意点
おわりに

#バリエーションコピー
####● 従来の方法1 CopyStampの使用
1-1_copystamp.png
Copy Stampでバリエーションをコピーするとノードが少なく、一見シンプルな構造に見えます。
しかし、Copy Stamp ノード内の変数の定義や Stamp 関数はSOPの操作の中ではかなり特殊で、データの流れは難解です。
input2 の情報をCopy Stamp を通して左側で参照しているわけですが、Dependency Link を表示するとSwitchとCopy Stamp が互いを見ていてループが発生しています。
つまりどういうことだってばよという感じなのですが、Copy Stamp は処理がかなり重くなる場合もあり、個人的には代替法があるのであれば、利用を避けていきたいと思っています。

SideFX のヘルプにも「バリエーションコピーの際にはCopy Stamp は推奨しない、代わりに For-Each を使え」と書かれてます。(2020/12/16現在)
https://www.sidefx.com/ja/docs/houdini/copy/stamping.html

####● 従来の方法2 For-Each の使用
1-2_ForEachCopy.png
ここではFor-Each Point の iteration 変数から乱数をつくりSwitchを切り替えています。
Copy Stamp で隠れていたループ部分が明示的になって扱いやすくなりました。
しかしそれでも、For-Each ではまだ複雑に見えてしまいます。

####● Houdini18 からの機能 Variant Attribute を使用
1-3_VariantCopy.png
Houdini18から Copy to Points に「Piece Attribute」という項目が増え、デフォルトで「variant」というアトリビュートが指定されるようになりました。
右側と左側で同じ variant アトリビュートをつくり、値が一致しているものをコピーするという機能です。
「variant」という名前は別のものにしても動きます。

これは非常にシンプルで理解しやすく、さらに高速で計算されるようになりました!

####● Houdini18.5 の新ノード Scatter and Align, Attribute from Pieces を使用
1-4.png

variant アトリビュートとCopy to Points によるコピーには変わりはありませんが、ほかの部分で便利なノードが追加され、より楽にセットアップできるようになりました。

Scatter and Align では Point をばら撒くと同時に Orient アトリビュートを作ってくれて、回転の制御が楽になりました。
Normal 軸に対しての回転や、傾き回転のランダム具合を調整できます。
また、煩わしかったコピー後にジオメトリが90度寝てしまう問題もデフォルトで解決してくれていて、余計なセットアップが減りました。(Alignment という項目で変更可能です。)
Scatter and Align のヘルプはこちら。↓
https://www.sidefx.com/docs/houdini/nodes/sop/scatteralign.html

Attribute from Pieces では input2 のアトリビュートを指定して(ここではvariant)、そのアトリビュートの存在する値をinput1のポイント群に割り振ってくれるノードです。
variantの種類がいくつあるのかを指定する必要はなく、Expressionの手間がなくなりました。
また、割り振り方の種類が Mode パラメータから Cycle, Patches, Noise, Random などから選択できます。
この Mode の違いなどはヘルプに画像付きで載っています。
Attribute from Pieces ヘルプはこちら。↓
https://www.sidefx.com/docs/houdini/nodes/sop/attribfrompieces.html

####● Houdini 19.0 のバリエーションコピー
Houdini 19.0 のバリエーションコピーについては ↓ の記事で書いています。

####● パラメータ違いのバリエーションコピーしたい際のCopyStamp
少し話が戻る&脱線します。
「Copy Stampをなるべく使わないようにしたいのはわかったけど、パラメータ違いによるバリエーションはどうするの?」
と、もう一人の自分が語り掛けてきました。
どういうことかというと、こういった事例です。↓
1-5.png
ここでは Mountain SOP のオフセットにpoint番号をStampを通して取得してノイズ具合をバラけさせています。
ノード数からしてシンプルなセットアップですが、実はこういった事例の時にCopy Stamp はかなり重くなります。

####● パラメータ違いのバリエーションコピーしたい際の代替法
1-6.png
これが正解と胸張って言える訳ではないのですが、Trail SOP と Time Shift を使ったお気に入りの方法を紹介したいと思います。

・バリエーションを持たせたいパラメータに「$F」など時間軸による値の違いを与えます。
・Trail SOP のTrail Length に持たせたいバリエーション数を指定します。ここでは Scatter の point 数を参照しています。
 Trail SOP は軌跡を作るためのノードで、過去のフレームの結果を今のフレームにコピーしてきてくれます。
・そのままではタイムスライダを動かすと結果が変わってしまうため、Time Shift で結果を固定します。

この事例ではCopyStampの5倍の速度でバリエーション作成&コピーができました。
↓速度の比較画像です。
CopyStamp
1-7.png
代替法
1-8.png

しかし、この事例に限れば、100個のポイントに100種類もバリエーションが必要ないように思えます。
10種類のバリエーションとランダムな回転が入っていれば気にならない気がします。
1-9.png
バリエーション数を減らすには Trail SOP の Trail Length の値を変更するだけです。
1-9_cap2.png
速度がさらに速くなりました!

さらに複雑で高速なバリエーション作成したいとすると、PDGを使用してキャッシュを作る方法が有力かと思われますが、ここでは割愛したいと思います。

#ランダムアトリビュートの作成
先ほどの章で回転は Scatter and Align 内でランダムに回転させていました。
加えて、スケールをランダムに調整するには pscale アトリビュートにランダム値を与える必要があると思います。
ランダムな pscale を作る方法は以前にもたくさんありました。
####● 従来のいくつかの方法
2-1.png
・Attribute Create の Value に rand 関数を用いて作成する。
・Attribute Randomize で最小値と最大値を指定する。
・Attribute Noise で最小値と最大値を指定する。Rondomize と違いノイズ。
・Attribute Wrangle で作成する。自由度が最も高く好きなように値が作れるが、記述が面倒。
・Attribute VOP で作成する。wrangle とほぼ同様。

####● Houdini18.5 の新ノード Attribute Adjust 系SOP
2-2.png
新ノードAttribute Adjust ノードは型ごとに3種類(Float, Integer, Vector)用意されています。
サイコロのアイコンからも察せるように、よくあるランダム値生成の全部入りという印象で、
Attribute Create のように固定の値、Attribute Randomize のようにランダムな値、Attribute Noise のようにノイズの値が作れます。
Expression や VEX の記述なしにお手軽に作成・操作ができます。
Random, Noise で出来た値を Fit したり Rampで調整したり、Clampしたり、元の値と Blend もできます。
嬉しいFrame ⇔ Time 変換や Degree ⇔ Radian 変換にも対応しています。
2-3.png  2-4.png
人によっては、デフォルトで「pscale」が既に入力されているのは気が利きすぎに感じるかもしれません。
(ちなみにInteger は「variant」、Vectorは「v」がデフォルトで入力されています。)
Attribute Adjust Float のヘルプはこちら↓
https://www.sidefx.com/docs/houdini/nodes/sop/attribadjustfloat.html

#積もった雪の作例
Houdini を学び始めるとよく出会う作例があり、その一つが積もった雪の作例です。
####● 従来の方法1 Groupで上面を選択
3-1.png

Group ノードで面のノーマル方向とベクトル{0,1,0}との比較から上を向いている面をグループ化します。
そのグループに対して Scatter を行い、VDB化→スムース→ポリゴン化という手順です。
3-2.png
しかし、この方法だけでは問題があります。
ラバートイを豚さんに置き換えると口の中にも雪が積もってしまいました。
遮蔽物の考慮をしてくれず、口の中の面が上を向いていることが原因です。

####● 従来の方法2 Ray SOP を使用
そこでGroupの代わりに RaySOP を使用することでこの現象を回避することができます。
3-3.png
豚の上部にグリッドを配置し、そこにScatterで点をばら撒きます。
Ray SOP で真下にpoint達を向かわせ、豚さんにぶつかったところに吸着させます。
余計なpointを削除したら、あとは先ほどと同じ手順です。

####● Houdini 18.5 の新ノード Mask by Feature を使用した方法
3-4.png
Mask by Feature を使ってどれくらい上面を向いているかのアトリビュート(mask)を作成、
そのアトリビュートを元に Scatter (Density Attribute 項目で maskを指定)する方法です。
この方法の特筆すべき点はShadowを考慮、つまり遮蔽物を考慮してくれる点です。
ここでは使用してませんが、さらに Ambient Occlusion も計算に含めることができます。
疑似的なライティングからマスクを作るノードといった感じです。

####● Mask by Feature をもう少しご紹介
3-5.png
Mask by Feature には input が3つあります。
input3 にジオメトリを指すと、遮蔽物を追加することができます。
3-6.png
input2 に point を指し、Direction from パラメータを「Point Cloud」に変更すると
指定したpointが点光源のようなマスクが作れます。
Calculate Directional Mask をオンにすると距離に応じて減衰する効果も追加できます。
まるでライティングしているかのようですが、mask アトリビュート を Cd にリネームして表示しているだけです。
3-7.png
input2 にはいくつでもpointを追加することができます。
3-8.png
また、Shadowをボカすこともできます。
Mask by Feature ヘルプはこちら↓
https://www.sidefx.com/docs/houdini/nodes/sop/maskbyfeature.html

####● Mask by Feature を使った植生の作例
3-9.gif
Sphere を太陽と見立てて、光の当たっている場所で距離に応じて草が大きくなる例を作りました。
Mask by Feature のおかげでノードも少なく、シンプルにセットアップできたように思います。

Scatter and Align でラバートイにばら撒いた point 群に、Mask by Feature で作った mask を pscale として付与しています。
その point 群に L-System で作った単純な草をコピーし、Attribute VOP でノイズ変形(UVを使って根本は固定)をさせています。
最後に Color SOP で pscale の値に応じた色をつけています。
詳しくは hip ファイルをご覧いただければと思います。

#カーブ上に配置
####● 従来の方法1 Copy to Point & Poly Frame の使用
4-1.png
Resample をかけた Curve に Poly Frame をつないで、回転方向を決めるアトリビュート N と up を付与します。
この場合では、Tangent Name を N に、Bitangent Name を up とすると綺麗にコピーした box が並びます。

4-2.png
しかし、Curve の形状によっては期待通りの向きにならない場合があります。

4-3.png
N と up を表示してみると、up が期待通りの方角を向いていないことが確認できます。

####● Houdini18からのノード Orientation Along Curve の使用
4-4.png
4-4-1.png
Houdini 18 から新しいPoly Frame ともいえる Orientation Along Curve が追加されました。
デフォルトの設定で期待通りの N と up を作ってくれます。
Houdini 18 から新しくなった Sweep の機能の一部を独立させたかのようなノードで、Roll, Twist, Yaw, Pitch など回転操作の機能が豊富です、

4-4-2.png
角の box が斜めを向いているのが気になる方は Tangent Type を「Next Edge」または「Previous Edge」にすると真っ直ぐになります。
(これはPoly Frame も同じで、Poly Frame の場合は Style を「First Edge」にします。)

4-5.png
もちろん曲がっているカーブでも問題なく並べられます。

個人的な経験ですが、逆にOrientation Along Curve でうまくいかない時にPoly Frame でうまくいった場合がありました。(すいません、どんな場面か忘れました)
どちらがいいというよりは、選択肢が増えたと捉えたほうがいいように思います。

####● Houdini18からのノード Copy to Curve の使用
4-6.png
事前のアトリビュート付与を必要とせず、カーブとコピー元ジオメトリがあればすぐさま並べてくれます。
HDAになっていて、中に入ると Copy to Points と Orientation Along Curve が入っていることが確認できます。
なので結果の違いは前述とほとんどないのですが、お手軽に並べたい時や、ノードの組み合わせをすっきりさせたい時に使用するのがいいかもしれません。

####● Houdini18.5 の新ノード Chain SOP の使用
4-7.png
Chain SOP で Enable Rigidity をオンにすると、カーブに沿ってジオメトリを並べてくれます。
Chain SOP はポイント位置にコピーするのではなく、カーブいっぱいにジオメトリを並べます。
ですので、ジオメトリの大きさを変えるとコピーされる数が変わります。

Alignment タブの Piece Spacing の値が 0 の時、「カーブが直線の時にピッタリ並べる」間隔で並べられます。
この状態では、カーブが曲がっていると、曲率が高いほど潜りあってしまいます。
4-8.png
Piece Spacing の値を調整すると、間隔をあけてコピーしてくれます。

4-10.png
問題の起こりやすいほうのカーブで見てみます。
直線だけだと情報が少なくうまくいかなかったので、Resampleを挟んでいます。
しかしそれでも角のところが、ガタついてしまいました。

4-11.png
Mode を 「Deform Along Curve」 から 「Deform Between Pivots」 にしたら修正することができました。
Chain SOP のヘルプはこちらです↓
https://www.sidefx.com/docs/houdini/nodes/sop/chain.html

####● Chain SOP をもう少し紹介
4-9.png
別々のジオメトリを Merge でつなぎ、Chain SOP につなぐと順番に並べてくれます。

Find Pieces パラメータが「By Connectivity」になっていると、ジオメトリの形状から違うジオメトリであることを自動で判別してくれます。
「By Piece Attribute」にすると、指定したアトリビュートの違いから判別してくれます。

4-12.png
また、Pattern の Repeat Pattern パラメータで並べるルールを「Cycle」、「Explicit Pattern」、「Random」などから変更できます。
「Explicit Pattern」にすると配置するパターンを手入力で設定することができます。

#####● 鎖の作例
4-13.png
Chain SOP 使ってその名の通り、鎖を作ってみました。
Piece Spacing をマイナス値入れることで、互いが食い込みあうように。
Piece Rotation を「90」とすることで 90 度ずつ回転しながら配置してくれます。

#####● 線路の作例
4-14.png
ここまでの作例はすべて Rigidity をオンにしていました。
オフにするとどうでしょう? 正方形を Sweep したような形状になりました。
実はRigidityをオフにすると配置後にカーブに沿った形に変形してくれます。

4-15.png
4-16.png
この特性を生かして、線路をつくってみました。
Find Pieces は「By Connectivity」にすると枕木とレールがバラバラにされてしまうので「By Piece Attribute」にしています。

4-17.png
さらに様々なパーツを Chain SOP で並べてみました。
詳細は hip ファイルをご覧ください。

#いくつかのTransform操作(Match Size の使用例)
Match Sizeは(たぶん)17.5からのノードで最新ノードではないのですが、あらゆる場面で活躍する
私の「推しノード」なのでご紹介したいと思います。
###■0平面上に移動
#####● 従来の方法1 Transform & ローカル変数($YMIN) の使用
5-1.png
Transform ノードの Translate Y の値に「-$YMIN」と入力することで、一番の底が原点の高さになるように移動してくれます。
「$YMIN」とは Y 座標の中で一番低い値が入っているTransformノードのローカル変数です。
原点にあるジオメトリを、地面に埋まらないように移動したい時によくやる手法だと思います。
しかし、ローカル変数の値は他のノードのパラメータから参照(Relative Reference)することができません。

#####● 従来の方法2 Transform & bbox関数 の使用
5-2.png
Transform ノードの Translate Y の値に 「-bbox(0,D_YMIN)」を入力することで同様の移動ができます。
bbox関数ではジオメトリの bounding box から数値を取得する関数です。
「$YMIN」との大きな違いは、bbox関数で作り出した値を他のノードのパラメータから参照(Relative Reference)することができる点です。

#####● Match Size の使用
5-3.png
Transform ノードの代わりに Match Size をつなぎ Justify X,Z を「None」、Yを「Min」にすることで同様な移動ができます。
Expression を打ち込まなくていいのが利点かもしれません。

###■原点へ移動・元の位置への復帰
原点にあると、あらゆる処理を施す時に考えやすくなります。
遠くにあるものを原点へ移動し、何かしらの処理をして、元の位置に戻すという事をやりたい時がよくあるでしょう。
#####● 従来の方法1 Transform & ローカル変数( $CEX,$CEY,$CEZ ) の使用
5-4.png
原点に移動したい時は Transform の Translate からそれぞれローカル変数($CE)を引くと可能です。
$CE~変数は、ジオメトリの各軸の中心の位置を格納しています。
しかし前述のとおり、ローカル変数の値は参照できないため元の位置に戻すのが困難です。
トポロジーが変わらない処理であれば、rest アトリビュートを取っておいて戻すのも手かもしれませんが、やれることは限定的になってしまいそうです。

#####● 従来の方法2 Transform & centroid関数 & Reference Copy の使用
5-5.png
centroid 関数はジオメトリの各軸の中心点を求める関数です。
$CE~変数の時と同様に、今の位置から引き算すれば原点に移動することが可能です。

5-6.png
centroid 関数は別のノードから値を参照することができるため、元の位置へ復帰することが容易です。
ここで便利なのが Reference Copy で、すべてのパラメータを参照するノードを作る機能があります。
Transform ノードを右クリックして、「Actions」→「Create Reference Copy」で作成できます。
(もしくは Ctrl + Shift + Alt + ドラッグ&ドロップ でも作成できます。)
それによって新たに作られた Transform ノードの 「Invert Transformation 」だけを Delete Channel(Ctrl + Shift + 左クリック) してオンに変更します。
すると、原点へ移動した値の、逆の値を移動することによって、元の位置へ復帰できます。

#####● Match Size の使用
5-7.png
Match Size のデフォルトの値が原点への移動の設定になっています。(Justify XYZ が全て「Center」)
Stash Transform をオンにすると Match Size 内で行った 動作が xform アトリビュートに保存されます。

5-8.png
元の位置へ復帰させるにはもう一つ Match Size をつなぎ Restore Transform をオンにするだけです。
これは xform アトリビュートに invert かけた値を適用する動作です。
適用後は xform アトリビュートを削除してくれます。

#####● Transform & Match Size
実は Match Size でなくても、いくつかのノードで xform アトリビュートの保存ができます。
Transform ノードが代表的です。先ほどの例で復帰だけ Match Size を使用してみましょう。
5-10.png
画像のように、ローカル変数「$CE~」を使用した際でも xform アトリビュートを通して復帰することができました。
もちろん centroid関数でも同じことが可能です。

###■ xform アトリビュートの利用
#####● Lab Straightenで回転の復帰
移動、スケールは比較的操作しやすいですが、回転は鬼門です。
box のような上面、前面がハッキリしているジオメトリであれば、Lab Straighten ノードで各軸を向いた扱いやすい状態にすることができます。
5-11.png
5-12.png
Lab Straighten では上面と前面をグループで指定して使用します。
ここでは直接 primitive を選んでますが、Group ノードなどを使用してプロシージャルに選んでもいいかもしれません。
Lab Straighten でも xform アトリビュートを保存できるので、Match Size で元の回転へと復帰できます。
5-14.png

#####● xform アトリビュートが複数ある場合
Match Size と Lab Straighten をもちいて、移動、回転を原点に持っていきたいと思います。
5-15.png
Match Size の Stash Transform のデフォルトの設定は「Replace Existing」で Straightenで保存した xform を上書きしてしまいます。
「Post-Multiply」または「Pre-Multiply」に変更すると、Straighten の xform の効果を残してくれます。

もしくは、xform の保存時に名前を「rot_xform」「pos_xform」など名前を変えて、それぞれ別の Match Size ノードで Restore するのも手だと思います。

#####● Transform by Attribute の使用
Match Size の 「Restore Transform」 は xform を invert した値を適用し、削除しますが、
xform をもう一度適用したい、ほかで作った xform を適用したい、xform を削除せず残したい場合などに便利な、
素直に xform アトリビュートを適用するノード「Transform by Attribute」があります。
5-16.png
この画像の例では、boxを原点に持ってくる時に作った xform アトリビュートを、
Attribute Copy を使って豚さんに渡し、Transform by Attribute で適用しています。

Invert Transfomation パラメータをオンにすれば、Match Size の Restore ように逆の効果を適用できます。
Delete Transform Attribute パラメータをオフにすれば、xform アトリビュートを削除せずに保持することができます。

###■ 隣接して配置
#####● Match Size & Lab Split Primitives by Normal の使用
Match Size を利用して豚さんの隣にラバートイを配置する方法を紹介します。
5-17.png
豚さんに box をつないで、bounding box を得ます。
5-18.png
Lab Split Primitives by Normal をつなぎ、コピーしたい方角の面を残します。
5-19.png
Match Size の input2 は Match させる先を指定することができます。
Match Size の input1、input2 をそれぞれ繋いで、合わせたい軸で「Min」場合によっては「Max」を指定します。
パーツを組み合わせるようにモデリングしたい時などに便利な操作です。

###■ Match Size の Scale 操作
ここまで移動と回転を取り上げてきましたが、スケールにおいても便利な機能が Match Size にあります。
5-20.png
Scale to Fit をオンにすると、それぞれの軸の長さが1になるようなスケール操作がされます。

5-21.png
加えて Uniform Scale をオンにすると、比率を守ってスケールします。
Scale Axis が「Best Fit」になっていれば、一番長い軸の長さが 1 になるようにスケールしてくれます。
どの軸を 1 にするかは Scale Axis から選ぶことができます。

5-22.png
input2 にジオメトリを差すと、その bounding box にあわせてスケールすることができます。
Match Size という名前に一番ふさわしい使い方かもしれません。
軸ごとに、あえてマッチさせない事もできます。

#####● @Pを01に収める
5-23.png
Justify を全部「Min」、Scale to Fit をオンにすると、@Pが各軸で01に収まるようにリマップされることになります。
これは考えようによっては便利な機能です。
@Pを01にリマップした値は、入力のサイズに関わらず効果の範囲を全体や、特定の割合に適用したい時に便利です。
いままでも、uvを張る方法や、Bounding Box の値と@Pを割り算することで@Pを01にリマップしたと同様の数値を得ることができました。
@P自体を01にリマップする方法はそれらの代替法として活用できます。

5-24.png
この画像でのセットアップでは、Z軸を01にリマップしてからTwistを360度かけて元に戻しています。
こうすると、Twist の Capture Length はデフォルトの 1 のままで全体をピッタリ範囲にすることができます。

5-25.png
設定をそのままに、入力を寝かしたトミーに差し替えてみました。
どんな大きさのジオメトリであっても、一度「01にリマップ」を挟んでいるため、必ず全体を範囲にして360度ツイストしてくれるセットアップができました。

#初学者向けの注意点
この記事では最新のノードを使用した方法を解説しましたが、端的に従来の方法が悪く、新しい方法が良いというわけではありません。
ノーマル方向でのグループ、Ray SOP、PolyFrameやOrient Along Curve によるアトリビュートの付与、ローカル変数、bbox関数・centroid関数などは様々な場面で大活躍します。
重要なのは様々なシチュエーションで最良な選択ができるよう、アイデアの武器をたくさんもっておく事だと個人的に思います。

#おわりに
最後まで読んでいただきありがとうございました!
昨年の記事にも書きましたが、Slackの「Houdini部」にもいくつか hip ファイルをアップしているので、興味ある方は参加してみてください。
質問コーナーではどんな初歩的な質問でも、私ふくめて部員の皆さんが誠実に答えてくれると思います。
https://houdinibu.slack.com/join/shared_invite/zt-dumulued-xW9yRhU23Oa34hVAk9Vc1w#/

また、今年はめんたいこさん主催のHoudiniゆるゆる会に何度か参加させていただきました。
ゆるゆる会のhipファイルも公開されていますので、勉強に役立てることができると思います。
ゆるゆる会connpassページ:https://houdini-teaparty.connpass.com/
hipファイルtrello:https://trello.com/b/7ftxZclJ/houdini%E3%82%86%E3%82%8B%E3%82%86%E3%82%8B%E4%BC%9A

来週にもう一つ記事を書く予定ですので、そちらもどうぞよろしくお願いします。

39
20
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
39
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?