Nasıl bir araya geldiğini görebilmeniz için bunu birkaç katman halinde oluşturacağım.
Create --> Shader --> Unlit
Varlıklar menüsünde veya Proje penceresindeki sağ tıklama bağlam menüsünü seçerek Unity'de yeni bir gölgelendirici oluşturarak başlayın .
Üst blokta _ScrollSpeeds
, dokunun her yönde ne kadar hızlı hareket ettiğini kontrol etmek için bir parametre ekleyeceğiz :
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ScrollSpeeds ("Scroll Speeds", vector) = (-5, -20, 0, 0)
}
Bu, malzeme denetçisinde "Scroll Speeds" (Scroll Speeds) adıyla yeni bir 4 bileşenli float özelliğini ortaya çıkarır ( betiğe bir public
veya Serialized
değişken eklemeye benzer MonoBehaviour
)
Ardından o.uv
, varsayılan gölgelendiriciye yalnızca iki satır ekleyerek doku değişkenlerini ( ) kaydırmak için Vertex gölgelendiricisinde bu değişkeni kullanacağız :
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;
}
Bir dörtlü tokatlayın ( Kenney tarafından güzel bir ücretsiz zürafa dokusu ile ) ve şunları elde edersiniz:
Bir halkada dokunun dışa doğru kaymasını sağlamak için, örümcek ağı gibi alt bölümlere ayrılmış bir kafes kullanabiliriz, uv v koordinatı merkezden dışarı doğru artar. Ancak bu, kendi başına testere şekilli bazı eserler verecektir. Bunun yerine, parça başına UV'leri nasıl hesaplayabileceğimizi göstereceğim.
Bu, hem trig & length işlemleri (temel matematikten daha pahalı) hem de parça başına texcoordları hesaplarken donanımdaki doku verilerini tahmin etmek ve önbelleğe almak kadar etkili olmadığından, sadece enterpolasyona kıyasla biraz daha maliyetlidir. köşeler arasında. Ancak bunun gibi küçük bir özel efekt için aşırı değil.
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;
}
Bu bize böyle bir şey verir (burada malzemedeki döşeme parametrelerini arttırdım, böylece ne olduğunu daha net - çemberin sadece tek bir tekrarını sarmak bozuk ve garip görünüyor)
Son olarak, dokuyu kayan bir gradyanla renklendirmek için, degradeyi ikinci bir doku olarak ekleyebilir ve birlikte çoğaltabiliriz.
İlk önce yeni texture parametresini en üste ekliyoruz:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_TintTex("Tint Texture", 2D) = "white" {}
_ScrollSpeeds ("Scroll Speeds", vector) = (-5.0, -20.0, 0, 0)
}
Ve CGPROGRAM bloğumuzda ilan edin, böylece CG gölgelendirici görebilsin:
sampler2D _MainTex;
float4 _MainTex_ST;
// Declare our second texture sampler and its Scale/Translate values
sampler2D _TintTex;
float4 _TintTex_ST;
float4 _ScrollSpeeds;
Ardından, her iki dokuyu kullanmak için parça gölgelendiricimizi güncelleyin:
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;
}
Ve şimdi zürafamız gerçekten trippy oluyor:
Biraz daha sanatsal doku seçimi ve kaydırma oranları ile, bu soruda gösterilene oldukça benzer bir etki yaratabilir.
Yukarıda gösterdiğim sürümle iki küçük eser görebilirsiniz:
Dairenin merkezine yakın yüzler gergin / sıska / sivri hale gelir, daha sonra dışarı doğru hareket ettikçe ezilir / genişler.
Bu bozulma, çevre çevresinde sabit sayıda yüzümüz olduğu için olur, ancak yükseklikleri aynı kalırken, yayıldıkları çevre yarıçap arttıkça genişler.
Logaritmik bir eğri izlemek için doku örneğinin dikey bileşenini yeniden düzenleyerek bunu düzeltebiliriz, bu nedenle yarıçap arttıkça doku tekrarları daha da ayrı ve merkeze daha yakın olur. (Aslında, bu bize daha küçük ve daha küçük zürafaların sonsuz bir gerilemesini veriyor ...)
Dörtlü sol ortada bir veya iki bulanık pikselden oluşan bir satır var.
Bunun nedeni, GPU'nun hangi filtrelemenin kullanılacağını anlamak için iki bitişik doku örneği koordinatına bakmasıdır. Numuneler birbirine yakın olduğunda, dokunun büyük / kapalı olarak görüntülendiğini ve en ayrıntılı mip seviyesini gösterir. Örnekler birbirinden ayrıldığında, dokuyu küçük bir zumda veya çok uzakta göstermemiz gerektiğini tahmin ediyor ve ışıltılı yumuşatma yapaylıkları elde etmememiz için daha küçük / bulanık bir mipmap'tan örnekler.
Sorun burada, kutupsal koordinatlarda -180 ila 180 derece arasında sarmal noktadayız. Dolayısıyla, sayısal koordinatları onları birbirinden uzak görünmelerine neden olsa bile, aslında yinelenen doku alanımızdaki benzer noktalardan örnek alıyoruz. Bunu düzeltmek için kendi örnekleme gradyan vektörlerimizi sağlayabiliriz.
İşte bu düzeltmeleri içeren bir sürüm:
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
kaydırma efektini kir elde etmek için (köşe) gölgelendiricideki doku koordinatlarınıza ekleyebileceğiniz yerleşik bir değişkene sahiptir . Altıgen etkisi de oldukça basit olacaktır. Sorunuzu yalnızca bir etkiyi vurgulayacak şekilde düzenlerseniz ve "Bunu bir Unity gölgeleyicisinde nasıl uygulayacağım" diye sorarsanız, muhtemelen size yardımcı olabiliriz. Gölgelendiricinin ışıklandırmaya / gölgelemeye yanıt vermesi gerekip gerekmediğini belirttiğinizden emin olun, çünkü bunun nasıl yazılacağı üzerinde etkisi vardır.