【OpenGL】Shaderインスタンス分析(一)-Wave
転送先:http://blog.csdn.net/stalendp/article/details/21993227
この文章は主に1つのShaderを分析して、それによってshaderの魅力を感じて、そして関連するshaderの関数の使い方を学びます.
まず、Shaderの実行の効果を見てみましょう.
コードは次のとおりです.
次の分析を行います.
1.ComputeScreenPosの解析:
3 Dの座標を画面上の点に変換します.2つの方法がありますので、公式の例を参照してください
ComputeScreenPosはUnityCGにあります.cgincファイルでは、次のように定義されています.
2.背景の描画
2.1)fmodは、例えば、fmod(1.5,1.0)が0.5を返すような残数を求めるために使用される.
2.2)stepはサイズの比較に用いられ、step(a,x):0 if x =a; 例えば、step(1,1.2)、は1を返します。Step(1,0.8)は0を返します。
2.3)fmodとstepを組み合わせて破線の効果を得ることができる.例えば、破線セグメント長が1のコードを得るには、次のようにします.
c1 = fmod(x, 2*width); c1=step(width,c1);//そのうちwidthは1
xの範囲が〔0,1〕であれば、c 1の値は0である.範囲は[1,2)、c 1の値は1、2は1周期である.
fmodは作成サイクルの役割を果たし、stepはサイクル内の0と1を計算する.
2.4)2.3の知識を2次元に適用すると,ブロックを算出できる.
lerp関数の使い方:lerp(a,b,f),fはパーセンテージ(取値範囲〔0,1〕);fが0の場合、lerpはa、fは1を返し、bを返す.fが0から1の間であると、aからbの間の値が返される.
コードの中のlerp(uv.x*COLOR 1,uv.y*COLOR 2,c 1*c 2);ここで,c 1とc 2の値は1ではなく0であるため,メッシュとなる場合がある.背景は次のように描画されます.
3.波紋の描画
3.1)座標の変換
uv = -1.0 + 2.0*uv;//元のuvを拡張してシフトし、新しいuvを得る.我々の操作は新しいuvで行い、最終的に表示されると元のuvにマッピングされますので、下図を参照してください.
3.2)直線を描く:
上はy軸をスクリーンの中心に移動するので、スクリーンの上半分は正で、下半分は負で、コードは以下の通りです.
3.3)直線を曲線に変えて、それを動かす:
3.4)複数の曲線を描き、波を形成する:
実はshaderと書いて、効果を重ねてデバッグすることで効果を達成することが多いです.
この文章は主に1つのShaderを分析して、それによってshaderの魅力を感じて、そして関連するshaderの関数の使い方を学びます.
まず、Shaderの実行の効果を見てみましょう.
コードは次のとおりです.
Shader "shadertoy/Waves" { //see https://www.shadertoy.com/view/4dsGzH
CGINCLUDE
#include "UnityCG.cginc"
#pragma target 3.0
struct vertOut {
float4 pos:SV_POSITION;
float4 srcPos;
};
vertOut vert(appdata_base v) {
vertOut o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.srcPos = ComputeScreenPos(o.pos);
return o;
}
fixed4 frag(vertOut i) : COLOR0 {
fixed3 COLOR1 = fixed3(0.0,0.0,0.3);
fixed3 COLOR2 = fixed3(0.5,0.0,0.0);
float BLOCK_WIDTH = 0.03;
float2 uv = (i.srcPos.xy/i.srcPos.w);
// To create the BG pattern
fixed3 final_color = fixed3(1.0);
fixed3 bg_color = fixed3(0.0);
fixed3 wave_color = fixed3(0.0);
float c1 = fmod(uv.x, 2.0* BLOCK_WIDTH);
c1 = step(BLOCK_WIDTH, c1);
float c2 = fmod(uv.y, 2.0* BLOCK_WIDTH);
c2 = step(BLOCK_WIDTH, c2);
bg_color = lerp(uv.x * COLOR1, uv.y * COLOR2, c1*c2);
// TO create the waves
float wave_width = 0.01;
uv = -1.0 + 2.0*uv;
uv.y += 0.1;
for(float i=0.0; i<10.0; i++) {
uv.y += (0.07 * sin(uv.x + i/7.0 + _Time.y));
wave_width = abs(1.0 / (150.0 * uv.y));
wave_color += fixed3(wave_width * 1.9, wave_width, wave_width * 1.5);
}
final_color = bg_color + wave_color;
return fixed4(final_color, 1.0);
}
ENDCG
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
ENDCG
}
}
FallBack Off
}
次の分析を行います.
1.ComputeScreenPosの解析:
3 Dの座標を画面上の点に変換します.2つの方法がありますので、公式の例を参照してください
ComputeScreenPosはUnityCGにあります.cgincファイルでは、次のように定義されています.
// Projected screen position helpers
#define V2F_SCREEN_TYPE float4
inline float4 ComputeScreenPos (float4 pos) {
float4 o = pos * 0.5f;
#if defined(UNITY_HALF_TEXEL_OFFSET)
o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w * _ScreenParams.zw;
#else
o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
#endif
#if defined(SHADER_API_FLASH)
o.xy *= unity_NPOTScale.xy;
#endif
o.zw = pos.zw;
return o;
}
原理解析(続き)2.背景の描画
2.1)fmodは、例えば、fmod(1.5,1.0)が0.5を返すような残数を求めるために使用される.
2.2)stepはサイズの比較に用いられ、step(a,x):0 if x =a; 例えば、step(1,1.2)、は1を返します。Step(1,0.8)は0を返します。
2.3)fmodとstepを組み合わせて破線の効果を得ることができる.例えば、破線セグメント長が1のコードを得るには、次のようにします.
c1 = fmod(x, 2*width); c1=step(width,c1);//そのうちwidthは1
xの範囲が〔0,1〕であれば、c 1の値は0である.範囲は[1,2)、c 1の値は1、2は1周期である.
fmodは作成サイクルの役割を果たし、stepはサイクル内の0と1を計算する.
2.4)2.3の知識を2次元に適用すると,ブロックを算出できる.
lerp関数の使い方:lerp(a,b,f),fはパーセンテージ(取値範囲〔0,1〕);fが0の場合、lerpはa、fは1を返し、bを返す.fが0から1の間であると、aからbの間の値が返される.
コードの中のlerp(uv.x*COLOR 1,uv.y*COLOR 2,c 1*c 2);ここで,c 1とc 2の値は1ではなく0であるため,メッシュとなる場合がある.背景は次のように描画されます.
3.波紋の描画
3.1)座標の変換
uv = -1.0 + 2.0*uv;//元のuvを拡張してシフトし、新しいuvを得る.我々の操作は新しいuvで行い、最終的に表示されると元のuvにマッピングされますので、下図を参照してください.
3.2)直線を描く:
上はy軸をスクリーンの中心に移動するので、スクリーンの上半分は正で、下半分は負で、コードは以下の通りです.
wave_width = abs(1.0 / (50.0 * uv.y));
wave_color = fixed3(wave_width * 1.9, wave_width, wave_width * 1.5);
のうち50.0は線の幅を制御するために使用され(数値が大きいほど線が細い)、効果は以下の通りです.3.3)直線を曲線に変えて、それを動かす:
uv.y += (0.07 * sin(uv.x*10 + _Time.y));
wave_width = abs(1.0 / (50.0 * uv.y));
wave_color = fixed3(wave_width * 1.9, wave_width, wave_width * 1.5);
の効果は次のとおりです.3.4)複数の曲線を描き、波を形成する:
for(float i=0.0; i<10.0; i++) {
uv.y += (0.07 * sin(uv.x + i/7.0 + _Time.y));
wave_width = abs(1.0 / (150.0 * uv.y));
wave_color += fixed3(wave_width * 1.9, wave_width, wave_width * 1.5);
}
最終効果は文章の冒頭を参照してください.実はshaderと書いて、効果を重ねてデバッグすることで効果を達成することが多いです.