Saya akan membangun ini dalam beberapa lapisan sehingga Anda dapat melihat bagaimana ia datang bersama-sama.
Mulailah dengan membuat shader baru di Unity dengan memilih Create --> Shader --> Unlit
menu Aset atau menu konteks klik kanan di jendela Proyek.
Di blok atas kami akan menambahkan _ScrollSpeeds
parameter untuk mengontrol seberapa cepat tekstur bergerak di setiap arah:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ScrollSpeeds ("Scroll Speeds", vector) = (-5, -20, 0, 0)
}
Ini memperlihatkan properti float 4-komponen baru di inspektur material, dengan nama ramah "Kecepatan Gulir" (mirip dengan menambahkan public
atau Serialized
variabel ke MonoBehaviour
skrip)
Selanjutnya kita akan menggunakan variabel ini di Vertex shader untuk menggeser koordinat tekstur ( o.uv
), dengan menambahkan hanya dua baris ke shader default:
sampler2D _MainTex;
float4 _MainTex_ST;
// Declare our new parameter here so it's visible to the CG shader
float4 _ScrollSpeeds;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
// Shift the uvs over time.
o.uv += _ScrollSpeeds * _Time.x;
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
Menampar itu pada quad (dengan tekstur jerapah gratis yang indah oleh Kenney ) dan Anda mendapatkan:
Untuk mendapatkan tekstur menggulir ke luar dalam sebuah cincin, kita bisa menggunakan mesh yang dibagi seperti spiderweb, dengan koordinat uv v meningkat dari tengah ke luar. Tapi itu akan memberikan beberapa artefak berbentuk gergaji sendiri. Sebagai gantinya, saya akan menunjukkan bagaimana kita dapat menghitung UV per fragmen.
Ini sedikit lebih mahal, baik karena operasi trigonometri & panjang (yang lebih mahal daripada matematika dasar) dan karena itu tidak seefisien untuk memprediksi & menyimpan data tekstur dalam perangkat keras ketika menghitung texcoords per fragmen, dibandingkan dengan hanya menginterpolasi mereka. antar simpul. Tetapi untuk efek khusus kecil seperti ini, tidak berlebihan
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
// Shift the UVs so (0, 0) is in the middle of the quad.
o.uv = v.uv - 0.5f;
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// Convert our texture coordinates to polar form:
float2 polar = float2(
atan2(i.uv.y, i.uv.x)/(2.0f * 3.141592653589f), // angle
length(i.uv) // radius
);
// Apply texture scale
polar *= _MainTex_ST.xy;
// Scroll the texture over time.
polar += _ScrollSpeeds.xy * _Time.x;
// Sample using the polar coordinates, instead of the original uvs.
// Here I multiply by MainTex
fixed4 col = tex2D(_MainTex, polar);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
Itu memberi kita sesuatu seperti ini (di sini saya meningkatkan parameter ubin dalam materi sehingga lebih jelas apa yang terjadi - hanya dengan mengulangi satu kali ubin di sekitar lingkaran terlihat terdistorsi dan aneh)
Terakhir, untuk mewarnai tekstur dengan gradien pengguliran, kita bisa menambahkan gradien sebagai tekstur kedua dan mengalikannya menjadi satu.
Pertama kita tambahkan parameter tekstur baru di atas:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_TintTex("Tint Texture", 2D) = "white" {}
_ScrollSpeeds ("Scroll Speeds", vector) = (-5.0, -20.0, 0, 0)
}
Dan mendeklarasikannya di blok CGPROGRAM kami sehingga CG shader dapat melihatnya:
sampler2D _MainTex;
float4 _MainTex_ST;
// Declare our second texture sampler and its Scale/Translate values
sampler2D _TintTex;
float4 _TintTex_ST;
float4 _ScrollSpeeds;
Kemudian perbarui shader fragmen kami untuk menggunakan kedua tekstur:
fixed4 frag(v2f i) : SV_Target
{
float2 polar = float2(
atan2(i.uv.y, i.uv.x) / (2.0f * 3.141592653589f), // angle
length(i.uv) // radius
);
// Copy the polar coordinates before we scale & shift them,
// so we can scale & shift the tint texture independently.
float2 tintUVs = polar * _TintTex_ST.xy;
tintUVs += _ScrollSpeeds.zw * _Time.x;
polar *= _MainTex_ST.xy;
polar += _ScrollSpeeds.xy * _Time.x;
fixed4 col = tex2D(_MainTex, polar);
// Tint the colour by our second texture.
col *= tex2D(_TintTex, tintUVs);
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
Dan sekarang jerapah kita menjadi sangat trippy:
Dengan pemilihan tekstur dan laju gulir yang sedikit lebih artistik, ini dapat membuat efek yang sangat mirip dengan yang ditunjukkan dalam pertanyaan.
Anda mungkin melihat dua artefak kecil dengan versi yang saya perlihatkan di atas:
Wajah-wajah di dekat pusat lingkaran menjadi melar / kurus / runcing, kemudian ketika mereka bergerak ke arah luar, mereka tergencet / melebar.
Distorsi ini terjadi karena kami memiliki jumlah wajah yang tetap di sekeliling perimeter, tetapi keliling yang mereka rentang semakin lebar seiring dengan meningkatnya jari-jari, sementara tingginya tetap sama.
Kita dapat memperbaikinya dengan memetakan kembali komponen vertikal dari sampel tekstur untuk mengikuti kurva logaritmik, sehingga pengulangan tekstur semakin terpisah ketika jari-jari meningkat, dan lebih dekat bersama-sama menuju pusat. (Bahkan, ini memberi kita kemunduran jerapah yang lebih kecil dan lebih kecil ...)
Ada deretan satu atau dua piksel buram di sepanjang kiri tengah quad.
Ini terjadi karena GPU melihat dua koordinat sampel tekstur yang berdekatan untuk mencari tahu penyaringan apa yang digunakan. Ketika sampel berdekatan, itu menunjukkan tekstur sedang ditampilkan besar / dekat dan menunjukkan tingkat mip paling rinci. Ketika sampel berjauhan, kita harus menunjukkan tekstur pada zoom kecil atau jauh, dan sampel dari mipmap yang lebih kecil / blur untuk memastikan kita tidak mendapatkan artefak aliasing yang berkilau.
Masalahnya ada di sini, kita berada di titik pembungkus dalam koordinat kutub, dari -180 hingga 180 derajat. Jadi kita benar-benar mengambil sampel dari titik-titik yang sangat mirip di ruang tekstur berulang kami, bahkan jika koordinat numerik mereka membuatnya terlihat seperti mereka berjauhan. Jadi kami dapat menyediakan vektor gradien sampling kami sendiri untuk memperbaikinya.
Inilah versi dengan koreksi ini:
fixed4 frag(v2f i) : SV_Target
{
float2 polar = float2(
atan2(i.uv.y, i.uv.x) / (2.0f * 3.141592653589f), // angle
log(dot(i.uv, i.uv)) * 0.5f // log-radius
);
// Check how much our texture sampling point changes between
// neighbouring pixels to the sides (ddx) and above/below (ddy)
float4 gradient = float4(ddx(polar), ddy(polar));
// If our angle wraps around between adjacent samples,
// discard one full rotation from its value and keep the fraction.
gradient.xz = frac(gradient.xz + 1.5f) - 0.5f;
// Copy the polar coordinates before we scale & shift them,
// so we can scale & shift the tint texture independently.
float2 tintUVs = polar * _TintTex_ST.xy;
tintUVs += _ScrollSpeeds.zw * _Time.x;
polar *= _MainTex_ST.xy;
polar += _ScrollSpeeds.xy * _Time.x;
// Sample with our custom gradients.
fixed4 col = tex2Dgrad(_MainTex, polar,
_MainTex_ST.xy * gradient.xy,
_MainTex_ST.xy * gradient.zw
);
// Since our tint texture has its own scale,
// its gradients also need to be scaled to match.
col *= tex2Dgrad(_TintTex, tintUVs,
_TintTex_ST.xy * gradient.xy,
_TintTex_ST.xy * gradient.zw
);
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
_Time
variabel bawaan yang dapat Anda tambahkan ke koordinat tekstur dalam shader (vertex) untuk mendapatkan efek gulir yang murah. Efek hexagon akan sangat mudah juga. Jika Anda mengedit pertanyaan Anda untuk menyoroti hanya satu efek dan bertanya "bagaimana saya menerapkan ini dalam shader Persatuan," kami mungkin dapat membantu Anda. Pastikan untuk menentukan apakah shader perlu merespons pencahayaan / bayangan, karena hal itu berdampak pada bagaimana hal itu akan ditulis.