Shader 파트 48을 시작해서 조금 더 풍성한 블루밍 스타일의 웨이브를 만들려고 합니다.
쉐더를 할 시간이 얼마 안 남았어요.
하마터면 Shader를 할 뻔했다.쉐더를 할 시간이 많지 않을 것 같아서요.
100부까지 열심히 하겠습니다.10년이 걸려도 돼요.
100편의 글을 배웠다면 초보자라도 이해할 수 있을 것 같아요.
이렇게 하는 거야.
※ 초보자는 필기 레벨로 기록
기술 보도로는 도움이 안 될 것 같습니다.
미리 준비하다
아래 참조
Shader 파트 1Unite 2017 애니메이션을 볼 때가 많지 않아요. (기초지식~종이 스크레이퍼로 색깔 바꾸기)
데모
이렇게 됐어.
시위 행진의 요소는 다음과 같다.
• 물결 같은 하얀 거품 만들기
• 파도를 하얗게 하다
• 수면 아래로 비틀기
과거 쓴 기사 내용을 조합한 내용이다.
[연결된 과거 글]
Shader 사운드 43 셀카 소음으로 도문 스타일의 파도를 만들 뻔 했어요.
Shader의 44번째 부분을 깊은 무늬로 웨이브를 칠 때의 표현을 할 때가 많지 않아요.
Shader 파트 할 게 별로 없어요. 47 수면이 비뚤어져요.
Shader 샘플
Shader "Custom/DistortionWave"
{
Properties
{
_SquareNum ("SquareNum", int) = 5
_DistortionPower("Distortion Power", Range(0, 0.1)) = 0
[HDR]_WaterColor("WaterColor", Color) = (0,0,0,0)
_DepthFactor("Depth Factor", Range(0, 10)) = 1.0
_WaveSpeed("WaveSpeed", Range(1,10)) = 1
_FoamPower("FoamPower", Range(0,1)) = 0.6
_FoamColor("FoamColor", Color) = (1, 1, 1, 1)
_EdgeColor("EdgeColor", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags
{
"Queue" = "Transparent" "RenderType" = "Transparent"
}
//不当明度を利用するときに必要 文字通り、1 - フラグメントシェーダーのAlpha値 という意味
Blend SrcAlpha OneMinusSrcAlpha
//描画結果をテクスチャーとして取得可能に
GrabPass
{
//ここで定義した名前で取得可能になる
"_GrabPassTextureForDistortionWave"
}
//揺らぎの表現を頑張る 描画結果を利用する
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 grabPos : TEXCOORD1;
float4 scrPos : TEXCOORD2;
};
sampler2D _CameraDepthTexture;
sampler2D _GrabPassTextureForDistortionWave;
float _DistortionPower;
v2f vert(appdata v)
{
v2f o = (v2f)0;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.grabPos = ComputeGrabScreenPos(o.vertex);
//ComputeScreenPosによってxyが0〜wに変換される
o.scrPos = ComputeScreenPos(o.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
//サンプリングするUVをずらす sin波でゆらゆら
float2 distortion = sin(i.uv.y * 50 + _Time.w) * 0.1f;
distortion *= _DistortionPower;
float4 depthUV = i.grabPos;
//サンプリング用のUVによる歪みは少し大きくしておく
//https://catlikecoding.com/unity/tutorials/flow/looking-through-water/
depthUV.xy = i.grabPos.xy + distortion * 1.5f;
//深度テクスチャをサンプリング
float4 depthSample = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(depthUV));
//既に描画済みのピクセルの深度情報
float backgroundDepth = LinearEyeDepth(depthSample);
//今描画しようとしているピクセルの深度情報
float surfaceDepth = UNITY_Z_0_FAR_FROM_CLIPSPACE(i.scrPos.z);
//Depthの差を利用した補間値
float depthDiff = saturate(backgroundDepth - surfaceDepth);
//w除算 普段はGPUが勝手にやってくれる
//補間値を利用してUVをずらして良いピクセルとそのままにするピクセルを塗り分け
float2 uv = (i.grabPos.xy + distortion * depthDiff) / i.grabPos.w;
return tex2D(_GrabPassTextureForDistortionWave, uv);
}
ENDCG
}
//泡の表現を頑張る
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 scrPos : TEXCOORD1;
};
float4 _WaterColor;
int _SquareNum;
float _WaveSpeed;
float _FoamPower;
float4 _FoamColor;
float4 _EdgeColor;
float _DepthFactor;
sampler2D _CameraDepthTexture;
float2 random2(float2 st)
{
st = float2(dot(st, float2(127.1, 311.7)),
dot(st, float2(269.5, 183.3)));
return -1.0 + 2.0 * frac(sin(st) * 43758.5453123);
}
v2f vert(appdata v)
{
v2f o = (v2f)0;
o.vertex = UnityObjectToClipPos(v.vertex);
//ComputeScreenPosによってxyが0〜wに変換される
o.scrPos = ComputeScreenPos(o.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float2 st = i.uv;
st *= _SquareNum; //格子状のマス目作成 UVにかけた数分だけ同じUVが繰り返し展開される
float2 ist = floor(st); //各マス目の起点
float2 fst = frac(st); //各マス目の起点からの描画したい位置
float4 waveColor = 0;
float m_dist = 100;
//自身含む周囲のマスを探索
for (int y = -1; y <= 1; y++)
{
for (int x = -1; x <= 1; x++)
{
//周辺1×1のエリア
float2 neighbor = float2(x, y);
//点のxy座標
float2 p = 0.5 + 0.5 * sin(random2(ist + neighbor) + _Time.x * _WaveSpeed);
//点と処理対象のピクセルとの距離ベクトル
float2 diff = neighbor + p - fst;
m_dist = min(m_dist, length(diff));
waveColor = lerp(_WaterColor, _FoamColor, smoothstep(1 - _FoamPower, 1, m_dist));
}
}
//深度テクスチャをサンプリング
float4 depthSample = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos));
float screenDepth = LinearEyeDepth(depthSample) - i.scrPos.w;
float edge = 1 - saturate(_DepthFactor * screenDepth);
float4 color = lerp(waveColor, _EdgeColor, edge);
return color;
}
ENDCG
}
}
}
처리 프로세스 자체는 저번 보도와 같고 아래와 같다.①GrabPass를 통해 드로잉 결과 얻기
② 도면 결과를 이용하여 깊이 정보에 따라 수면 아래의 대상을 비뚤어진다
③ 수면을 그리며 파도의 파동과 파도의 충격을 계산할 때의 색
물리적 파동
나는 과거에 쓴 바람에 펄럭이는 깃발 같은 표현 Shader의 응용에 물리적으로 울퉁불퉁한 파의 표현을 더하고 싶다.
데모
옆으로 보면 이해하기 쉬운데 이렇게 Pleane이 파도처럼 위아래로 움직여요.
Shader 샘플
Shader "Custom/DistortionWave"
{
Properties
{
_SquareNum ("SquareNum", int) = 5
_DistortionPower("Distortion Power", Range(0, 0.1)) = 0
[HDR]_WaterColor("WaterColor", Color) = (0,0,0,0)
_DepthFactor("Depth Factor", Range(0, 10)) = 1.0
_WaveSpeed("WaveSpeed", Range(1,10)) = 1
_FoamPower("FoamPower", Range(0,1)) = 0.6
_FoamColor("FoamColor", Color) = (1, 1, 1, 1)
_EdgeColor("EdgeColor", Color) = (1, 1, 1, 1)
_Frequency("Frequency ", Range(0, 3)) = 1
_Amplitude("Amplitude", Range(0, 1)) = 0.5
}
SubShader
{
Tags
{
"Queue" = "Transparent" "RenderType" = "Transparent"
}
//不当明度を利用するときに必要 文字通り、1 - フラグメントシェーダーのAlpha値 という意味
Blend SrcAlpha OneMinusSrcAlpha
//描画結果をテクスチャーとして取得可能に
GrabPass
{
//ここで定義した名前で取得可能になる
"_GrabPassTextureForDistortionWave"
}
//パスを跨いで利用できる変数や関数
CGINCLUDE
float _WaveSpeed;
float _Amplitude;
float _Frequency;
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float vertex_wave(float2 vert,float waveSpeed,float amplitude,float frequency)
{
float2 factors = _Time.x * waveSpeed + vert * frequency;
float2 offsetYFactors = sin(factors) * amplitude;
return offsetYFactors.x + offsetYFactors.y;
}
ENDCG
//揺らぎの表現を頑張る 描画結果を利用する
Pass
{
CGPROGRAM
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 grabPos : TEXCOORD1;
float4 scrPos : TEXCOORD2;
};
sampler2D _CameraDepthTexture;
sampler2D _GrabPassTextureForDistortionWave;
float _DistortionPower;
v2f vert(appdata v)
{
v2f o = (v2f)0;
v.vertex.y += vertex_wave(v.vertex.xz,_WaveSpeed,_Amplitude,_Frequency);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.grabPos = ComputeGrabScreenPos(o.vertex);
//ComputeScreenPosによってxyが0〜wに変換される
o.scrPos = ComputeScreenPos(o.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
//サンプリングするUVをずらす sin波でゆらゆら
float2 distortion = sin(i.uv.y * 50 + _Time.w) * 0.1f;
distortion *= _DistortionPower;
float4 depthUV = i.grabPos;
//サンプリング用のUVによる歪みは少し大きくしておく
//https://catlikecoding.com/unity/tutorials/flow/looking-through-water/
depthUV.xy = i.grabPos.xy + distortion * 1.5f;
//深度テクスチャをサンプリング
float4 depthSample = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(depthUV));
//既に描画済みのピクセルの深度情報
float backgroundDepth = LinearEyeDepth(depthSample);
//今描画しようとしているピクセルの深度情報
float surfaceDepth = UNITY_Z_0_FAR_FROM_CLIPSPACE(i.scrPos.z);
//Depthの差を利用した補間値
float depthDiff = saturate(backgroundDepth - surfaceDepth);
//w除算 普段はGPUが勝手にやってくれる
//補間値を利用してUVをずらして良いピクセルとそのままにするピクセルを塗り分け
float2 uv = (i.grabPos.xy + distortion * depthDiff) / i.grabPos.w;
return tex2D(_GrabPassTextureForDistortionWave, uv);
}
ENDCG
}
//泡の表現を頑張る
Pass
{
CGPROGRAM
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 scrPos : TEXCOORD1;
};
float4 _WaterColor;
int _SquareNum;
float _FoamPower;
float4 _FoamColor;
float4 _EdgeColor;
float _DepthFactor;
sampler2D _CameraDepthTexture;
float2 random2(float2 st)
{
st = float2(dot(st, float2(127.1, 311.7)),
dot(st, float2(269.5, 183.3)));
return -1.0 + 2.0 * frac(sin(st) * 43758.5453123);
}
v2f vert(appdata v)
{
v2f o = (v2f)0;
v.vertex.y += vertex_wave(v.vertex.xz,_WaveSpeed,_Amplitude,_Frequency);;
o.vertex = UnityObjectToClipPos(v.vertex);
//ComputeScreenPosによってxyが0〜wに変換される
o.scrPos = ComputeScreenPos(o.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float2 st = i.uv;
st *= _SquareNum; //格子状のマス目作成 UVにかけた数分だけ同じUVが繰り返し展開される
float2 ist = floor(st); //各マス目の起点
float2 fst = frac(st); //各マス目の起点からの描画したい位置
float4 waveColor = 0;
float m_dist = 100;
//自身含む周囲のマスを探索
for (int y = -1; y <= 1; y++)
{
for (int x = -1; x <= 1; x++)
{
//周辺1×1のエリア
float2 neighbor = float2(x, y);
//点のxy座標
float2 p = 0.5 + 0.5 * sin(random2(ist + neighbor) + _Time.x * _WaveSpeed);
//点と処理対象のピクセルとの距離ベクトル
float2 diff = neighbor + p - fst;
m_dist = min(m_dist, length(diff));
waveColor = lerp(_WaterColor, _FoamColor, smoothstep(1 - _FoamPower, 1, m_dist));
}
}
//深度テクスチャをサンプリング
float4 depthSample = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos));
//スクリーンに描画されるピクセルの深度情報
float screenDepth = LinearEyeDepth(depthSample) - i.scrPos.w;
float edge = 1 - saturate(_DepthFactor * screenDepth);
float4 color = lerp(waveColor, _EdgeColor, edge);
return color;
}
ENDCG
}
}
}
정점 Shader에 파도처럼 위아래로 흔들리는 처리가 기술되어 있다두 경로 모두 같은 처리를 설명해야 하기 때문이다
솔직하게 쓰면 중복되는 코드가 늘어난다.
그래서 사용했다
CGINCLUDEブロック
.CGINCLUDEブロック
변수와 함수를 여러 경로 간에 공유할 수 있습니다.//パスを跨いで利用できる変数や関数
CGINCLUDE
float _WaveSpeed;
float _Amplitude;
float _Frequency;
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float vertex_wave(float2 vert,float waveSpeed,float amplitude,float frequency)
{
float2 factors = _Time.x * waveSpeed + vert * frequency;
float2 offsetYFactors = sin(factors) * amplitude;
return offsetYFactors.x + offsetYFactors.y;
}
ENDCG
참조 링크
[Unity][음영] CGINCLUDE 블록의 사용 방법
Reference
이 문제에 관하여(Shader 파트 48을 시작해서 조금 더 풍성한 블루밍 스타일의 웨이브를 만들려고 합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/kento_o/articles/c7ec9522b3cabc텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)