Shader 파트 73 나비가 날개를 펼친다는 표현은 거의 없어요.
쉐더를 할 시간이 얼마 안 남았어요.
하마터면 Shader를 할 뻔했다.쉐더를 할 시간이 많지 않을 것 같아서요.
100부까지 열심히 하겠습니다.10년이 걸려도 돼요.
100편의 글을 배웠다면 초보자라도 이해할 수 있을 것 같아요.
이렇게 하는 거야.
※ 초보자는 필기 레벨로 기록
기술 보도로는 도움이 안 될 것 같습니다.
미리 준비하다
아래 참조
Shader 파트 1Unite 2017 애니메이션을 볼 때가 많지 않아요. (기초지식~종이 스크레이퍼로 색깔 바꾸기)
데모
나비가 날개를 치며 행진하다.
나비의 움직임은 쉐더, 움직이고 대량 생성되는 부분은 Particale이다.
Shader 샘플
Shader "Custom/Butterfly"
{
Properties
{
[NoScaleOffset]_MainTex ("Texture", 2D) = "white" {}
[HDR]_MainColor("MainColor",Color) = (1,1,1,1)
_FlapSpeed ("Flap Speed", Range(0,20)) = 10
_FlapIntensity ("Flap Intensity", Range(0,2)) = 1
_MoveSpeed ("Move Speed", Range(0,5)) = 1
_MoveIntensity ("Move Intensity", Range(0,1)) = 0.2
_RandomFlap ("Random Flap", Range(1,2)) = 1
}
SubShader
{
Tags
{
"RenderType"="Tansparent"
}
Pass
{
Cull off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float2 uv : TEXCOORD0;
//中心座標を受け取る変数
float3 center : TEXCOORD1;
//ランダムな値を受け取る変数
float random : TEXCOORD2;
//速度を受け取る変数
float3 velocity : TEXCOORD3;
float4 color : COLOR;
float4 vertex : POSITION;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
sampler2D _MainTex;
float4 _MainColor;
float _FlapSpeed;
float _FlapIntensity;
float _MoveIntensity;
float _MoveSpeed;
float _RandomFlap;
//ランダムな値を返す
float rand(float2 co) //引数はシード値と呼ばれる 同じ値を渡せば同じものを返す
{
return frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453);
}
//非線形ブラウン運動を計算する
float fbm(float x, float t)
{
return sin(x + t) + 0.5 * sin(2.0 * x + t) + 0.25 * sin(4.0 * x + t);
}
v2f vert(appdata v)
{
v2f o;
//ローカル座標
//Particle SystemのGameObjectが存在するところが原点となり、vertexにはこの原点から見た座標が入ってくる
//そのため、パーティクルの中心座標を引いて計算を行い、もとに戻すという工程を踏む
float3 local = v.vertex - v.center;
//ランダムな値を計算
float randomFlap = lerp(_FlapSpeed / _RandomFlap, _FlapSpeed, rand(v.random));
float flap = (sin(_Time.w * randomFlap) + 0.5) * 0.5 * _FlapIntensity;
//Sign(x)はxが0より大きい場合は1、小さい場合は-1を返す
//これにより、x=0となる箇所から線対称に回転を計算できる
half c = cos(flap * sign(local.x));
half s = sin(flap * sign(local.x));
/* |cosΘ -sinΘ|
R(Θ) = |sinΘ cosΘ| 2次元回転行列の公式*/
half2x2 rotateMatrix = half2x2(c, -s, s, c);
//羽の回転を反映
local.xy = mul(rotateMatrix, local.xy);
//進行方向を向かせるための回転行列を作成
//正面は進行方向、すなわちParticleから取得したvelocity
float3 forward = normalize(v.velocity);
float3 up = float3(0, 1, 0);
float3 right = normalize(cross(forward, up));
//行列を作成
//どうやら変数に詰めるときだけ行オーダーになっている?っぽい
//なのでtransposeで転置を行う
//すなわち以下でも可
//float3x3 mat = float3x3(right.x,up.x,forward.x,
// right.y,up.y,forward.y,
// right.z,up.z,forward.z);
float3x3 mat = transpose(float3x3(right, up, forward));
//Velocity(正面方向)に応じた回転を反映
v.vertex.xyz = mul(mat, local);
//原点をもとの座標に戻す
v.vertex.xyz += v.center;
o.vertex = UnityObjectToClipPos(v.vertex);
//上下の移動量を求めて反映 ワールド座標系で上下移動させる
float move = fbm(87034 * v.random, _Time.w * _MoveSpeed) * _MoveIntensity;
o.vertex.y += move;
o.uv = v.uv;
//頂点カラー
o.color = v.color;
return o;
}
float4 frag(v2f i) : SV_Target
{
//PlaneのZ軸が正の方向になるようにテクスチャーをサンプリング
//テクスチャーをRepeatにしておく必要あり
float4 col = tex2D(_MainTex, -i.uv);
col.rgb *= _MainColor.rgb;
//頂点カラーを適用 これでParticleの色を拾うようになる
col *= i.color;
//重なったところが透明に切り抜かれてしまうので透過領域をClipしておく
clip(col.a - 0.01);
return col;
}
ENDCG
}
}
}
Custom Vertex Streams에 사용되는 값
전제로 이 Shader는Partile System
Custom Vertex Streams
을 이용한다.【참조 링크】: 셰더 하는 부분 46 Partical에서 셰더 가격을 줘야 될 것 같아요.
따라서 일반적인 플랜에도 다음과 같은 GIF의 동작이 있을 수 있다.
이 전제에서 Shader를 보면...
Partical System에서 3개의 매개변수를 수신했습니다.
struct appdata
{
float2 uv : TEXCOORD0;
//中心座標を受け取る変数
float3 center : TEXCOORD1;
//ランダムな値を受け取る変数
float random : TEXCOORD2;
//速度を受け取る変数
float3 velocity : TEXCOORD3;
float4 color : COLOR;
float4 vertex : POSITION;
};
구체적으로 다음과 같다.각 입자의 중심 좌표
・각 입자가 가지고 있는 랜덤 값
・각 입자의 속도를 나타내는 벡터
입자 측면의 설정은 다음과 같다.
원하는 값이 TEXCOORD에 들어갈 수 있도록 필요 없는 값을 넣어 순서를 조정합니다.
코드를 읽을 때 이해하기 위해서입니다.
필요한 값만
Custom Vertex Streams
로 설정하는 것도 문제없다.입자의 중심에 관하여
각 입자의 중심 좌표를 사용하여 계산하기 위해 다음과 같은 처리를 진행하였다.
float3 local = v.vertex - v.center;
~略~
v.vertex.xyz += v.center;
그 이유로 Partical System의 GameObject가 존재하는 곳이 원점이 됩니다.vertex에 이 원점에서 보이는 좌표가 있기 때문이다.
따라서 입자마다 정점 좌표
입자 중심에서 보이는 좌표로 다시 계산하다
원래 정점으로 돌아가 이런 공정을 밟았다.
이로써 후술한
各パーティクルにおける線対象な羽の動き
또는各パーティクルの正面方向に対する回転
가 가능해졌다.깃털의 운동
깃털의 운동은 꼭대기 면도기가 맡는다.
Pleane을 선 대상으로 위아래로 돌리면 깃털이 된다.
도해는 다음과 같다.
그림에서 X축의 좌표는 0 이상 또는 0 이하를 기준으로 선 객체로 나뉜다
이것은sign이라는 함수로 실현할 수 있다.
sign (x) x가 0보다 크면 1, 시간은 -1로 돌아갑니다.
float3 local = v.vertex - v.center;
~略~
//Sign(x)はxが0より大きい場合は1、小さい場合は-1を返す
//これにより、x=0となる箇所から線対称に回転を計算できる
half c = cos(flap * sign(local.x));
half s = sin(flap * sign(local.x));
/* |cosΘ -sinΘ|
R(Θ) = |sinΘ cosΘ| 2次元回転行列の公式*/
half2x2 rotateMatrix = half2x2(c, -s, s, c);
//羽の回転を反映
local.xy = mul(rotateMatrix, local.xy);
회전 정보
각 입자, 즉 나비를 회전시킬 때 허점이 없는 동작이 필요하다.
이를 실현하기 위해 속도 벡터를 정면으로 정의한다
나비가 정면에 비해 머리와 몸을 회전하는 것을 계산한다.
이를 위해 필요한 것은 회전 행렬이다.
회전 행렬은 세 개의 직교 단위 벡터로 나타낼 수 있습니다.
【인용원】: 생물 역학에서 운동 센서를 이용하다
나는 이 나비를 만들 때 선행 자료를 훑어보기 전에
다음 행렬은 회전 행렬이다.
그러나 자세히 보면 3개의 정교한 단위 벡터도 포함되어 있다.
X축 중심의 이 부분은 1열의 단위 벡터(1, 0, 0)로 표현됩니다.
x'\\
y' \\
z'\\
1\\
\end{pmatrix}
=
\begin{pmatrix}
1 & 0 & 0 & 0\\
0 & cosθ & -sinθ & 0 \\
0 & sinθ & cosθ & 0\\
0 & 0 & 0 & 1\\
\end{pmatrix}
\begin{pmatrix}
x\\
y\\
z\\
1\\
\end{pmatrix}
다시 말하자면'나비의 정면을 머리와 몸에 대고 회전시켜 계산한다'고 했다.
이것은 세 개의 정교 단위 벡터로 표시할 수 있다
이런 성질을 이용하여 해결하다.
회전된 3개의 정교 단위 벡터만 알면 된다는 것이다.
이번에는 속도 (velocity) 벡터가 정면으로 정의되었습니다
첫 번째 단위의 벡터는 갑자기 해결될 것이다.
그런 다음 회전된 공간에서 위로 향하는 벡터를 (0, 1, 0)로 정의합니다.
이것은 두 단위의 벡터를 얻었다.
이 두 단위는 벡터가 교차한다.
따라서 다른 벡터는 외적에 따라 계산할 수 있다.
여기까지의 절차는 다음과 같은 부분이다.
//進行方向を向かせるための回転行列を作成
//正面は進行方向、すなわちParticleから取得したvelocity
float3 forward = normalize(v.velocity);
float3 up = float3(0, 1, 0);
float3 right = normalize(cross(forward, up));
//行列を作成
//どうやら変数に詰めるときだけ行オーダーになっている?っぽい
//なのでtransposeで転置を行う
//すなわち以下でも可
//float3x3 mat = float3x3(right.x,up.x,forward.x,
// right.y,up.y,forward.y,
// right.z,up.z,forward.z);
float3x3 mat = transpose(float3x3(right, up, forward));
//Velocity(正面方向)に応じた回転を反映
v.vertex.xyz = mul(mat, local);
transpose
는 행렬을 바꾸는 함수이다.기본적으로 Shader는 계산할 때 열순으로 계산한다
변수를 넣을 때만 주문을 하고 사용했습니다
transpose
.굳이 쓸 필요가 없어요.
좀 귀찮아서 다시 막힐 때를 위해 나는 필기를 남긴다.
비선형 브라운 운동
나비가 흔들거리는 동작을 재현하기 위해 복잡한 계산 공식을 채택했다.
float fbm(float x, float t)
{
return sin(x + t) + 0.5 * sin(2.0 * x + t) + 0.25 * sin(4.0 * x + t);
}
이로써 신파가 불규칙적으로 소음을 섞은 계산 결과를 계산한다.Velocity 구성
나비의 행진 방향에 관해서는Partical System
Velocity over Lifetime
을 사용합니다.다음과 같이 적용
Random Between
하여 허용 범위 내에서 임의성을 가지도록 한다느낌이 좋다.Y축을 Orbital로 회전하는 처리도 추가해 보았다.
참조 링크
[Unity] Partical System에서 vertex와 texcoord로 제작된 회전 애니메이션
분형 브라운 운동과 역 도약
면도기로 3D 콘서트 공연 업데이트~'러브 라이브! 학교 아이돌 축제 올스타즈'(스스타) 개발 사례~
[Unity][URP]Y축 마루판 스크레이퍼
공간과 플랫폼 간 – Unity 좌표 변환에 대한 이야기 –
Reference
이 문제에 관하여(Shader 파트 73 나비가 날개를 펼친다는 표현은 거의 없어요.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/kento_o/articles/95ec904fef8b2c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)