概要
サンプル
GitHubサンプルプロジェクト
STYLYサンプル空間 ドメインワーピング表現を適用した板を置いた空間をサンプルとして公開しています。
ドメインワーピングとは
ドメインワーピングとは、雲や水のような表現を fbm(フラクタルブラウン運動)と呼ばれるノイズを利用した計算によって表現しようというものです。
ドメインワーピングの解説
ここでは、ドメインワーピングの模様がどのようにして作られているのかを解説いたします。
ピクセル座標pを使用してfbm(p)を生成
ピクセルの座標pを利用して、fbmを生成すると雲のような見た目になります。
シェーダーコードで書いた場合は以下になります。
float2 p = i.uv * 8; return fbm(p + 1.7);
補足
pのx座標(p.x)とpのy座標(p.y)を可視化すると以下のようになります。
fbm(p)にさらにfbmを適用し、fbm(fbm(p))を生成
fbm(p)をさらにfbmで歪ませると、以下のような模様ができます。 座標pに対してfbmを繰り返し適用し、複雑な模様を生み出すことをドメインワーピングと呼びます。
シェーダーコードで書いた場合は以下になります。
float2 p = i.uv * 8; p = float2(fbm(p + 1.7), fbm( p + 9.2)); p = p * 8.0; return fbm(p + 8.3);
ドメインワーピングに動きを与える
ドメインワーピングの引数に時間を足すと動きが生まれます。
float2 p = i.uv * 4; p = float2(fbm(p + _Time.y), fbm(p)); p = p * 8.0; return fbm(p);
今回のドメインワーピング表現はこのようにして動きを与えています。
今回の表現の解説
ドメインワーピングで模様を作る
ドメインワーピングを利用して、以下のような模様を作ります。
モザイクエフェクトをかける
ドメインワーピングで作った模様にモザイクエフェクトをかけます。
水玉でくりぬく
水玉模様でくりぬきます。
色が明るいところほど円が大きく、色が暗いところは円を小さくさせることによってコントラストをつけ、 イイ感じにしています。
時間で動かして完成
fbmのパラメータに時間を足して動きを与え、今回の表現の完成です。
Unityでの作り方
ここでは、Unityのシェーダーを利用して今回のドメインワーピング表現を作る方法を解説します。 本記事でのマウス操作はWindowsを想定しています。
シェーダーを作成
まずはProjectウィンドウで Create/Shader/Unlit Shaderを選択し、シェーダーファイルを作成します。
シェーダーファイル名はDomainWarpingShaderとします。
シェーダーの編集
作成したシェーダーファイルを開き、以下のコードをペーストします。
Shader "Unlit/DomainWarpingShader" { Properties { _GradientTex("Gradient Texture", 2D) = "white" {} _GridNumber("Grid Number", Float) = 64.0 _EllipseSize("Ellipse Size", Float) = 1.0 _Speed("Speed", Float) = 1.0 _Fbm_ScaleFactor("Fbm Scale Factor", Vector) = (1.0, 1.0, 4.0, 4.0) } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; ////////////////////////////////////////////////////////////////////////////// float random(float2 st) { return frac(sin(dot(st.xy, float2(12.9898,78.233)))* 43758.5453123); } ////////////////////////////////////////////////////////////////////////////// // Based on Morgan McGuire @morgan3d // https://www.shadertoy.com/view/4dS3Wd float noise (float2 st) { float2 i = floor(st); float2 f = frac(st); // Four corners in 2D of a tile float a = random(i); float b = random(i + float2(1.0, 0.0)); float c = random(i + float2(0.0, 1.0)); float d = random(i + float2(1.0, 1.0)); float2 u = f * f * (3.0 - 2.0 * f); return lerp(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; } ////////////////////////////////////////////////////////////////////////////// #define OCTAVES 6 // based on : https://thebookofshaders.com/13/?lan=jp float fbm (float2 st) { // Initial values float value = 0.0; float amplitude = .5; float frequency = 0.; // Loop of octaves for (int i = 0; i < OCTAVES; i++) { value += amplitude * noise(st); st *= 2.; amplitude *= .5; } return value; } ////////////////////////////////////////////////////////////////////////////// // domain warping pattern // based on : http://www.iquilezles.org/www/articles/warp/warp.htm float pattern (float2 p, float4 scale_1, float scale_2, float4 add_1, float4 add_2) { // first domain warping float2 q = float2( fbm( p + scale_1.x * add_1.xy ), fbm( p + scale_1.y * add_1.zw ) ); // second domain warping float2 r = float2( fbm( p + scale_1.z * q + add_2.xy ), fbm( p + scale_1.w * q + add_2.zw ) ); return fbm( p + scale_2 * r ); } ////////////////////////////////////////////////////////////////////////////// sampler2D _GradientTex; float4 _GradientTex_ST; float _EllipseSize; float _GridNumber; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _GradientTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } float2 remap(float In, float2 InMinMax, float2 OutMinMax) { return OutMinMax.x + (In - InMinMax.x) * (OutMinMax.y - OutMinMax.x) / (InMinMax.y - InMinMax.x); } float ellipse(float2 UV, float Size) { float d = length(2 * UV - 1); return step(d, Size); } fixed2 posterize(fixed2 In, fixed Steps) { return floor(In * Steps) / Steps; } ////////////////////////////////////////////////////////////////////////////// float _Speed; float4 _Fbm_ScaleFactor; float _EllipseContrast; fixed4 frag (v2f i) : SV_Target { #define TIME_1 (_Time.y * (-0.1) * _Speed) #define TIME_2 (_Time.y * (-0.3) * _Speed) #define TIME_3 (_Time.y * (0.15) * _Speed) #define SIN_TIME_3 (4.0 * sin(TIME_3)) //#define ScaleFactor_1 float4(1.0, 1.0, 4.0, 4.0) #define ScaleFactor_1 _Fbm_ScaleFactor #define ScaleFactor_2 4.0 #define AddFactor_1 float4(TIME_1, TIME_2, 5.2, 1.3) #define AddFactor_2 float4(SIN_TIME_3, 9.2, 9.3, 2.8) #define GRID_N _GridNumber #define UV_Repeat frac(i.uv * GRID_N) #define UV_Posterized posterize(i.uv, GRID_N) // get domain warping value float domainWarping = pattern(UV_Posterized, ScaleFactor_1, ScaleFactor_2, AddFactor_1, AddFactor_2); // remap value domainWarping = remap(domainWarping, float2(0.39, 0.83), float2(0, 1)); return ellipse(UV_Repeat, domainWarping * _EllipseSize) * tex2D(_GradientTex, domainWarping); } ENDCG } } }
マテリアルを作成
シェーダーファイルを右クリックし、Create/Materialを選択します。
板オブジェクトの作成
作成したマテリアルを貼り付けるための板オブジェクトを作成する手順を解説します。
板にマテリアルを登録する
作成したPlaneオブジェクトにマテリアルをドラッグ&ドロップして、マテリアルを登録します。
板にドメインワーピング表現が適用され、以下のような見た目になります。
色を付ける
次にこのドメインワーピング表現に色を付けます。 今回のシェーダーでは、グラデーションテクスチャを設定することで、色がつくようになっています。
テクスチャを適用すると、色が付いて以下のような見た目になります。
色がつく仕組みについて
ドメインワーピングシェーダーで円が大きい部分ほど左の色を、円が小さい部分ほど右の色が適用されます。
UnityからSTYLYにアセットをアップロードする方法
UnityからSTYLYへアセットをアップロードする方法は下記URLをご覧ください https://styly.cc/ja/manual/unity-asset-uploader/