セピアちゃん模様シェーダ
イカ的模様をポスタリゼーションしたパーリンノイズで描いて、模様使いたくない部分をマスクテクスチャで弾く(謎模様ジェネレータ2では座標でやってたのを、画像でやる)ような事すれば行けんじゃねーの? と言うアイデア と言うわけで調査
https://www.youtube.com/watch?v=-vmG7dSonIY
警戒時(?)はシマシマになるのねえ
反射プローブの参照とか必要かしら?
調べすぎるとおっくうになりそう
UTS2は映像向けで、ゲーム向けじゃないのでうーむ
ーーーー
要点としては、ノイズ由来の模様を、マスクテクスチャで制御する。なので、先ずはそこに焦点を絞る
できた
https://youtu.be/7MUI2p2YIto
要点
code:glsl
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv); // 本来のテクスチャ色
fixed mask = tex2D(_MaskTex, i.uv); // マスク用のテクスチャ色(白さ)
// 模様生成
float noise_a = ClassicNoise(fixed3(i.uv * _Freq, _Time.y));
float noise_b = ClassicNoise(fixed3(i.uv.x * _Freq * 0.01, i.uv.y * _Freq * 0.05 + _Time.a, 100));
noise_a = (noise_a + 1) * 0.5;
noise_b = (noise_b + 1) * 0.5;
noise_b = noise_b * noise_b; // 模様を若干はっきりさせる
float noise = (noise_a * 1 + noise_b * 2) / 2;
fixed4 noiseCol = _NoiseColor; // 模様の色
noiseCol.a = (1 - mask) * noise; // 模様を塗るかどうか
// アルファブレンドで合成
fixed3 rgb = noiseCol.rgb * noiseCol.a + max(col.rgb, 0) * (1 - noiseCol.a);
fixed4 dist = fixed4(rgb, col.a);
要するに、模様側のα値をマスクテクスチャから拾ってるだけである
おおよそはこのライブラリの使い方調べるのに手間取った感じ
値域0~1におけるパーリンノイズのもや感を軽減させる手段
今までは階調を落とす位しか思いつかなかった
が、累乗する事でも波の荒さが際立ってもや感の軽減が出来る事が判明した
課題
模様を塗るかどうかの判定が、たぶん逆。エミッションとかは白い所が光るけど、これは黒い所に模様が出る。混乱するので逆にした方が良い
Litなシェーダになるようにする。必要がある気がする
あと、本職の人にどういう機能が欲しいか聞いてみる。とか?
スペキュラか鏡面反射を入れたい。気がする。
模様の方向性にもちょっと手入れした方が良さそう
大きな模様と、細かい縞模様を掛け合わせた表現が必要に感じる
要するに、表現したい模様に対する想像精度を上げろと言う話(どんな模様を作りたいのか?)
模様がじゃっかんボケてるように感じるのは気のせいだろうか・・・?
驚いた時にパッと色が変わるような、トリガー連動もしたい
ーーー
ばーじょんつー
https://youtu.be/f_xiQUNRCoE
志したのはトリガー連動の体色変化
ノイズを3種類用意し
質感用の細かいノイズ
模様用の荒いノイズ
感情表現用のアニメノイズ
それぞれのノイズは、重み付き平均値で合成
code:glsl
float noise = (
noise_a * 0.5
+ noise_b * 1.5
) / 2;
noise = (
noise * 1
+ noise_c * _Fade
) / (1 + _Fade);
質感用の細かいノイズ
普通に細かくしてもなんかこう、イカの色包感が出ない(グラデがきれいすぎる)のでポスタリゼーションした noise_a = floor(noise_a * 4) / 3;
模様用の荒いノイズ
普通のパーリンノイズだと、これもやはりグラデが滑らか過ぎて模様感が薄い
とはいえポスタリゼーションすると今度は境界が明確過ぎて嫌だ
と言うわけで、曲率を引き上げるような演算をしたい(したかった)
試行錯誤してこんな計算 noise_b = (clamp((noise_b - 0.5) * 2 * 2, -1, 1) + 1) * 0.5;
3つのパートに分かれてる
noise_bは値域0~1で正規化済みなので、これを戻す計算 f = (noise_b -0.5) * 2
曲率を引き上げる計算 g = clamp(f * 2, -1, 1)
再度正規化し直す計算 (g + 1) * 0.5
一度値域を-1~1にし直してるのは、値域0~1のままだと、曲率を引き上げた時、clamp範囲を含む後処理が面倒だから
https://gyazo.com/3ddf3e0a3434ac74362c4a03a5139f0e
加えて、0の範囲(色の無い範囲)より1の範囲(色のついた範囲)を広くするために、意図的に値域0~1の時における曲率の引き上げをした
code:glsl
noise_b = (clamp((noise_b - 0.5) * 4, -1, 1) + 1) * 0.5; // グラデ幅を短くする(0と1の面積を広げる)
noise_b = clamp(noise_b * 1.5, 0, 1); // 1の面積を広げる
感情表現用のアニメノイズ
なんかこう、イカに対して、興奮するとシマシマがぐるんぐるんするイメージを持ってる
模様の荒いノイズでやった、曲率の引き上げをもうちょい極端に適用した
こっちはむしろ、アニメ用の_Timeに対する適用係数を、AnimationController側から操作された時のじゃみじゃみ感(シマが超高速で動いてる)をどう軽減するかに腐心した
code:glsl
float spd = sqrt(_Speed);
float noise_c = ClassicNoise(fixed3(i.uv.x * lineFreq * 0.01, i.uv.y * lineFreq * 0.05 + (_Time.y * spd * 20), 100));
結局、フェードでシマ模様が表出する前にある程度のスピードまで持ち上げておく。という逃げ手を打った
パーリンノイズの周波数もそうだけど、外部から係数を操作した時の値のごちゃつきって、どうしたら良いんだろう?
トリガーのためのFXレイヤー設定
FXレイヤーにジェスチャで反応する別のレイヤーを新たに作成する
https://gyazo.com/b1819db7c6edcac6a90b5cbd62563fef
新たに作ったレイヤーに、体色変更のアニメーションクリップを登録していく
表情変更と体色変更がお互いに影響し合わないようにするための工夫
ーーー
ノイズの値を、頂点の法線方向への移動に利用すると、擬態してる時のデコボコが再現できるのでは?
https://gyazo.com/95f02f076b22e968166d150ed7004868
まだら状箇所の頂点を法線方向に押し出せば、イカが擬態してる時の皮膚の盛り上がりを再現できるのではと思ったけどボツ
モデル本体のポリゴン解像度が低くても大丈夫でしょとタカをくくってた。ダメだった
それはそれとしてこのポリゴン押し出しを時間変化させたりすると、うにょうにょして面白い
押し出し要否を例によってテクスチャで制御仕様とした訳だが、vertexシェーダ側でテクスチャを参照するのにひと手間掛かる事が判明した
float d = tex2Dlod(_Tex2Dlod, float4(v.texcoord.xy,0,0)).r;
バーテックスシェーダ供養
code:hlsl
v2f vert (appdata v)
{
v2f o;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
fixed mask = tex2Dlod(_MaskTex, float4(v.uv.xy,0,0)).r;
fixed time = _Time.y * 3; // 三角波を作りたい
fixed s1 = sin(time);
fixed s2 = sin(time * 2);
fixed s3 = sin(time * 3);
fixed s4 = sin(time * 4);
fixed s5 = sin(time * 5);
fixed s6 = sin(time * 6);
fixed s7 = sin(time * 7);
fixed s8 = sin(time * 8);
fixed s9 = sin(time * 9);
fixed s10 = sin(time * 10);
fixed pow1 = s1+s2+s3+s4+s5+s6+s7+s8+s9+s10;
pow1 = pow1 / 10;
pow1 = (pow1 + 1) / 2;
// pow *= 2;
// float pow = (sin(v.uv.x + v.uv.y * 10000000 + _Time.y*2) + 1) * 0.5;
float4 world_pos = mul(UNITY_MATRIX_M, v.vertex);
float pow = (sin(world_pos.z * 40 + pow1*4) + 1) * 0.5;
pow *= 0.4;
// float lineFreq = 6000;
// float spd = sqrt(_Speed);
// float pow = ClassicNoise(fixed3(o.uv.x * lineFreq * 0.01, o.uv.y * lineFreq * 0.05 + (_Time.y * spd * 20), 100));
v.vertex.xyz += v.normal * 0.02 * pow * mask.r;
o.vertex = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
ーーー
litToonを改造してちゃんと作ろうかしら
・・・あまりにもLilToonのソースコードが読めないので挫折
ArxCSのがまだ何処いじればよいのか見えるので、こっちを改造してみようか ArxCSのarkludeFrag.cgincに、メインカラーに対してサブカラー(Detail)を合成している箇所があるので、ここを参考に自前の生成テクスチャを合成するよう書く
ArxCSへのパラメータ追加は、どうもインスペクタをエディタースクリプトで書いてるようで、AxInspector.csに追記が必要 https://gyazo.com/c3a1d617c5e5c69a4f9fe6ded616870b
https://gyazo.com/125e3dd925653b1bc452496d2076ee88
ーーー
興味本位で、ノイズの生成に渡してるUV値を、離散化してみると、ブロックノイズみたいになってカッコよかった https://gyazo.com/6417a5c441800a1a110939c4d04a9536
これはこれでいつか使ってみたい
このブロック状の挙動を見て、円を並べられるんじゃないかと思って調べたら見つけた
code:hlsl
fixed4 frag (v2f i) : SV_Target
{
fixed radius = 0.4;
fixed r = distance(i.uv, fixed2(0.5,0.5));
return step(radius, r);
}
●の描き方を見つけたので、色素包を使った模様の変化にしようと、方針変更
https://gyazo.com/60578d7de94638f8a4924d5e6b18409e
これが出来るなら、RGB毎の色素包を用意して、これらの合成で色を表現するとそれらしいのではなかろうか。
https://www.youtube.com/watch?v=-52nthjt3k8
やってみたものの、テレビに目を近づけて見た時みたいな表現になってちょっと意図と違う
https://gyazo.com/f853ca49ae741727d6b01866335c5ff0
イカは色素で色を出してるので、減法混色にすれば良いのではないかと考える https://gyazo.com/4419d5e6e0bc0f85bb1cf079ecd16e11
減法混色の実装にはちょっと手間取った
どんな色にしたいか入力をRGBで受け取る
一度CMYKに変換
C, M, Y毎の色素包を作成する
改めてRGBに戻す
code:hlsl
//
// 色包の生成
//
fixed block = 400;
// // 加法混色
// fixed redCol = _SepiaColor.r;
// fixed greenCol = _SepiaColor.g;
// fixed blueCol = _SepiaColor.b;
// half red = makeCircle(i.uv0, fixed2(0.25, 0.5), basePattern * redCol, block) ;//* _SepiaColor.r;
// half green = makeCircle(i.uv0, fixed2(0,0), basePattern * greenCol, block) ;//* _SepiaColor.g;
// half blue = makeCircle(i.uv0, fixed2(0.5,0), basePattern * blueCol, block) ;//* _SepiaColor.b;
// float3 rgb = float3(red, green, blue);
// float a = max(red, max(green, blue));
// 減法混色版
// --- 入力をCMYKに変換
fixed k = 1-max(_SepiaColor.r, max(_SepiaColor.g, _SepiaColor.b));
k = min(k, 0.99);
fixed cyanCol = (1-_SepiaColor.r-k) / (1-k);
fixed mazendaCol = (1-_SepiaColor.g-k) / (1-k);
fixed yellowCol = (1-_SepiaColor.b-k) / (1-k);
// --- 色素包そのものの色の決定用処理
fixed kCell = 1-max(_SepiaCellColor.r, max(_SepiaCellColor.g, _SepiaCellColor.b));
kCell = min(kCell, 0.99);
fixed cyanCell = (1-_SepiaCellColor.r-kCell) / (1-kCell);
fixed mazendaCell = (1-_SepiaCellColor.g-kCell) / (1-kCell);
fixed yellowCell = (1-_SepiaCellColor.b-kCell) / (1-kCell);
// --- 色素包の製造
// --- fixed makeCircle(fixed2 uv, fixed2 offset, fixed r, fixed block){}
fixed2 cyan_offset = fixed2(0.25 + random_x, 0.5 + random_y);
half cyan = makeCircle(i.uv0, cyan_offset, basePattern * cyanCol, block) * cyanCell;
fixed2 mazenda_offset = fixed2(0 + random_x, 0 + random_y);
half mazenda = makeCircle(i.uv0, mazenda_offset, basePattern * mazendaCol, block) * mazendaCell;
fixed2 yellow_offset = fixed2(0.5 + random_x, 0 + random_y);
half yellow = makeCircle(i.uv0, yellow_offset, basePattern * yellowCol, block) * yellowCell;
// --- RGBに戻す
float3 rgb = float3(
(1-cyan)*(1-k),
(1-mazenda)*(1-k),
(1-yellow)*(1-k)
);
float a = max(cyan, max(mazenda, yellow));
色素包を拡大した動画はちょっとお気に入り
https://gyazo.com/fade0d7cf57ede829a63bcfde93b09cf
https://gyazo.com/adc0d27a1273b82cd719b4e616d7f744
https://gyazo.com/77f7654248b7a6f8958241f3dcbbce3d
色素包の色を決定してる処理は上の通りだけど、要するにCMYのそれぞれに、どれくらいの重みで採用するか、っていうアプローチ
入力をRGBで、係数決定はCMYKで行ってるのでなんともこう、何がどうなってるのか把握しづらい
Black-Whiteを調整して、全色同じ係数を適用しようとすると、RGBが0.13辺りでもう真っ白になる。超使いづらい
が、検証しようがないのでとりあえずこれで完成とする
ーーー
延長戦
円の形をゆがめる
code:hlsl
fixed makeCircle(fixed2 uv, fixed2 offset, fixed r, fixed block){
fixed uniqNoise = ClassicNoise(fixed3(uv*block*2, 1)); // ピクセル単位の乱数
fixed uniqNoiseN = (uniqNoise + 1)*0.5;
fixed2 innerUV = frac(uv * block);
fixed2 cellID = uv * block - innerUV;
fixed2 length = offsetTo(frac(uv * block), offset);
fixed2 center = fixed2(
0.5,
0.5
);
fixed2 rad = clamp(0,1,(distance(length, center) + uniqNoiseN) * 0.5); // ここで、円の形をゆがめる
r = r + 0.1;
return smoothstep(rad*0.4, rad+0.02, r);
}
TODO:セルラーノイズに変えてみる
ううむ
https://gyazo.com/811dd769f848251f2ca438b08270791a
色素包感が出て良い感じだけど、遠くから見るとやっぱジャミジャミしてる
境界線を潰すか潰さないか超悩む
Timeの値を、線形に増やすんじゃなくて、たまに増えるのが止まる
floor(time) + easeInOutExpo(frac(time))
整数部と少数部に分けて、少数部に対して補間関数を適用することで、0, 1付近で値が動かないようにする
アニメーションする間隔はtimeの値を変える、アニメーション時の変位量は全体に係数をかける
floor(time * spd) + easeInOutExpo(frac(time*spd)) * weight
ーーー
強すぎる参考資料を見つけた
smoothstepの仕様を勘違いしていた事が判明
smoothstep(A, B, T) の時
T < Aの時、0になる
T > Bの時、1になる
A < T < Bの時、0~1を滑らかに(3次関数補間)遷移する 要は、値域は必ず0~1になる
だもんで、clampに近い使い方になりそう
clampの引数順を勘違いしていた事が判明
clamp(t, min, max)
ぴえん
ーーー
イカちゃん見てると、模様の変化は厳密には濃淡の変化。のように思える
しかし表情に色相も濃度も連動させると画が忙しいので、今回は色相変化に注力して、濃淡変化のアニメは組まない
良い感じではなかろうか
https://gyazo.com/2738c9ce94e133bb2ca03b6cbb4e2404
コラージュ画像はPicCollageで作成
コラージュ作成ツール界隈はモバイルに特化していて、Windows版無いと思ってたけど、WindowsStoreに有るのねぇ
完成!
https://youtu.be/vNddQUbw9Mw