Quantcast
Channel: 初心者タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 21089

【Unity(Shader)】Shader初心者が送る水面表現②(波の再現)

$
0
0

Shaderで波の表現

前回の続きです。

【Unity(Shader)】Shader初心者が送る水面表現①(屈折)

前回は屈折表現を勉強したので、今回は波のゆらゆらする感じを再現します。

正直なところ、まだ理解できておらずいろいろ試して仮説立てて書いているので、
あまり参考にしない方がいいです。

むしろ、解釈が違ってたりしてたら教えてくださ~いって感じのノリです。

デモ

Wave2.gif

屈折表現と良い感じにシナジーを発揮して、波のゆらゆら感が際立ちました。
わかりやすいようにかなり早めに動かしてます。

Shader

今回も先駆者様のコードを参考に、どういう仕組みになっているのか理解していきます。

【参考リンク】:【Unity】【シェーダ】シェーダで頂点を変形させて波打つ水面を作る

Shader"Wave"{Properties{_DistortionTex("Distortion Texture(RG)",2D)="grey"{}_Color("WaterColor",Color)=(0,0,0,0)_DistortionPower("Distortion Power",Range(0,1))=0_ScrollSpeed("Scroll Speed",Range(0,0.5))=0.01_Frequency("Frequency ",Range(0,3))=1_Amplitude("Amplitude",Range(0,1))=0.5_WaveSpeed("WaveSpeed",Range(0,20))=10}SubShader{Tags{"Queue"="Transparent""RenderType"="Transparent"}CullBackZWriteOnZTestLEqualColorMaskRGBGrabPass{"_GrabPassTexture"}Pass{CGPROGRAM#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
structappdata{half4vertex:POSITION;half4texcoord:TEXCOORD0;half4normal:NORMAL;};structv2f{half4vertex:SV_POSITION;half2uv:TEXCOORD0;half4grabPos:TEXCOORD1;};sampler2D_DistortionTex;half4_DistortionTex_ST;sampler2D_GrabPassTexture;half4_Color;half_DistortionPower;half_ScrollSpeed;float_Frequency;float_Amplitude;float_WaveSpeed;v2fvert(appdatav){v2fo=(v2f)0;float2factors=_Time.x*_WaveSpeed+v.vertex.xz*_Frequency;float2offsetYFactors=(sin(factors)*_Amplitude);v.vertex.y+=offsetYFactors.x+offsetYFactors.y;o.vertex=UnityObjectToClipPos(v.vertex);o.uv=TRANSFORM_TEX(v.texcoord,_DistortionTex);o.grabPos=ComputeGrabScreenPos(o.vertex);returno;}fixed4frag(v2fi):SV_Target{// w除算half2uv=half2(i.grabPos.x/i.grabPos.w,i.grabPos.y/i.grabPos.w);// Distortionの値に応じてサンプリングするUVをずらすhalf2distortion=UnpackNormal(tex2D(_DistortionTex,i.uv+_Time*_ScrollSpeed)).rg;distortion*=_DistortionPower;uv+=distortion;half4refraction=tex2D(_GrabPassTexture,uv);refraction*=_Color;returnrefraction;}ENDCG}}}

頂点を上下に動かす

波をうねうねさせるには頂点を動かす必要があります。

WaveUneUne.gif

GIFのような状態はそれぞれの頂点が上下(Y軸方向に)に動くことで再現できます。

ただ、各頂点が上下に動くだけではGIFのようにはなりません。
このように、ただの板が上下するだけです。
Plane.gif

そこで、それぞれの頂点を異なるタイミングで上下させます。

【参考リンク】:【Unityシェーダ入門】シェーダで旗や水面をなびかせる

下記箇所でv.vertex.xzを乗算しているのはそのためです。
この計算によりfactorsにはそれぞれの頂点のxz座標をベースにした計算結果が入ります。
それぞれの頂点のxz座標を演算の要素に含むことで、
各頂点の座標の差異を利用して異なる値を作りだすことができました。

float2factors=_Time.x*_WaveSpeed+v.vertex.xz*_Frequency;float2offsetYFactors=sin(factors)*_Amplitude;

利用する座標を限定してみる

もっとわかりやすくするためにx座標、z座標のみを演算の要素として盛り込んだパターンを見てみます。
それぞれ、利用した座標軸方向のみで異なる動きをしているのがわかるかと思います。

x座標のみ利用

float2factors=_Time.x*_WaveSpeed+v.vertex.x*_Frequency;float2offsetYFactors=sin(factors)*_Amplitude;

WaveX.gif

z座標のみ利用

float2factors=_Time.x*_WaveSpeed+v.vertex.z*_Frequency;float2offsetYFactors=sin(factors)*_Amplitude;

WaveZ.gif

float2をfloatにぶち込んだ時

強い人にフィードバック頂いたので加筆します。

下記コードでふと疑問に思いました。
v.vertex.y += offsetYFactors.x + offsetYFactors.y;

  
v.vertex.y += offsetYFactors;となぜしていないのか?という疑問です。

offsetYFactorsはfloat2で値を2つ持ってるから、
加算代入したらその値の両方を加算代入できるはず!

と思いましたが、よくよく考えたらそんなことできるはずありませんでした。

実際に試してみると、x座標のみ利用した場合と同じ挙動になりました。
WaveX.gif

これは、内部でfloat2→floatの変換を勝手に行ってくれているそうで、
下記と同様の結果になるそうです。
v.vertex.y += offsetYFactors.x;

まとめ

最初、shaderを見たとき、下記箇所の意味がわからず途方に暮れていました。
v.vertex.y += offsetYFactors.x + offsetYFactors.y;

"あくまでも各頂点は上下に繰り返し移動しているだけで、
offsetYFactors.x + offsetYFactors.yの箇所はタイミングをずらすためのコードである"
と理解してスッキリしました。

次回は反射の表現も付け加えてみたいです。(重そう)


Viewing all articles
Browse latest Browse all 21089

Trending Articles