ฉันจะสร้างมันขึ้นมาในไม่กี่ชั้นเพื่อให้คุณสามารถดูว่ามันมารวมกัน
เริ่มต้นด้วยการสร้าง shader ใหม่ใน Unity โดยเลือกCreate --> Shader --> Unlit
ในเมนูสินทรัพย์หรือคลิกขวาที่เมนูบริบทในหน้าต่างโครงการ
ในบล็อกด้านบนเราจะเพิ่ม_ScrollSpeeds
พารามิเตอร์เพื่อควบคุมความเร็วของการเคลื่อนไหวของพื้นผิวในแต่ละทิศทาง:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ScrollSpeeds ("Scroll Speeds", vector) = (-5, -20, 0, 0)
}
สิ่งนี้จะเปิดเผยคุณสมบัติโฟลตแบบ 4 องค์ประกอบใหม่ในตัวตรวจสอบวัสดุที่มีชื่อ "Scroll Speeds" ที่เป็นมิตร (คล้ายกับการเพิ่มpublic
หรือSerialized
ตัวแปรให้กับMonoBehaviour
สคริปต์)
ต่อไปเราจะใช้ตัวแปรนี้ใน Vertex shader เพื่อเลื่อนพิกัดพื้นผิว ( o.uv
) โดยเพิ่มเพียงสองบรรทัดใน shader เริ่มต้น:
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;
}
ตบที่รูปสี่เหลี่ยม (มีเนื้อยีราฟฟรีน่ารักโดย Kenney ) แล้วคุณจะได้รับ:
ในการทำให้พื้นผิวเลื่อนออกไปด้านนอกในวงแหวนเราสามารถใช้การแบ่งตาข่ายเหมือนใยแมงมุมโดยมีค่า uv v เพิ่มขึ้นจากกึ่งกลาง แต่นั่นจะให้สิ่งประดิษฐ์ที่มีรูปทรงใบเลื่อยด้วยตัวเอง ฉันจะแสดงให้เห็นว่าเราสามารถคำนวณยูวีของเราได้อย่างไรต่อชิ้นส่วน
นี่เป็นค่าใช้จ่ายที่สูงกว่าเล็กน้อยทั้งเนื่องจากการดำเนินการตรีโกณมิติและความยาว (ซึ่งมีราคาแพงกว่าคณิตศาสตร์พื้นฐาน) และเนื่องจากมันไม่ได้มีประสิทธิภาพในการทำนาย & แคชข้อมูลพื้นผิวในฮาร์ดแวร์เมื่อคำนวณ texcoords ต่อชิ้นส่วนเมื่อเปรียบเทียบกับการแก้ไข ระหว่างจุดยอด แต่สำหรับเอฟเฟกต์พิเศษแบบนี้มันไม่มากเกินไป
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;
}
นั่นทำให้เราเป็นแบบนี้ (ที่นี่ฉันเพิ่มพารามิเตอร์การเรียงในวัสดุเพื่อให้ชัดเจนยิ่งขึ้นว่าเกิดอะไรขึ้น - การตัดกระเบื้องซ้ำรอบ ๆ วงกลมดูบิดเบี้ยวและแปลก)
สุดท้ายเพื่อย้อมสีพื้นผิวโดยการไล่ระดับสีเลื่อนเราสามารถเพิ่มการไล่ระดับสีเป็นพื้นผิวที่สองและคูณพวกเขาเข้าด้วยกัน
ก่อนอื่นเราเพิ่มพารามิเตอร์ texture ใหม่ที่ด้านบน:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_TintTex("Tint Texture", 2D) = "white" {}
_ScrollSpeeds ("Scroll Speeds", vector) = (-5.0, -20.0, 0, 0)
}
และประกาศในบล็อก CGPROGRAM ของเราเพื่อให้ CG shader เห็นได้:
sampler2D _MainTex;
float4 _MainTex_ST;
// Declare our second texture sampler and its Scale/Translate values
sampler2D _TintTex;
float4 _TintTex_ST;
float4 _ScrollSpeeds;
จากนั้นอัปเดตส่วนย่อยของเราเพื่อใช้พื้นผิวทั้งสอง:
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;
}
และตอนนี้ยีราฟของเราได้รับ trippy จริงๆ:
ด้วยการเลือกพื้นผิวและอัตราการเลื่อนที่ละเอียดกว่าเล็กน้อยทำให้สามารถสร้างเอฟเฟกต์ที่คล้ายกับที่แสดงในคำถามได้
คุณอาจสังเกตเห็นสิ่งประดิษฐ์เล็ก ๆ สองชิ้นกับรุ่นที่ฉันแสดงด้านบน:
ใบหน้าที่อยู่ใกล้ศูนย์กลางของวงกลมจะได้รับการยืด / ผอม / แหลมจากนั้นเมื่อพวกเขาเคลื่อนที่ไปด้านนอกพวกเขาจะถูกแบน / กว้าง
ความผิดเพี้ยนนี้เกิดขึ้นเพราะเรามีใบหน้าจำนวนหนึ่งรอบปริมณฑล แต่จำนวนเส้นรอบวงที่พวกมันขยายออกกว้างขึ้นเมื่อรัศมีเพิ่มขึ้นขณะที่ความสูงยังคงเท่าเดิม
เราสามารถแก้ไขสิ่งนี้ได้โดยทำการแมปองค์ประกอบแนวตั้งของตัวอย่างพื้นผิวใหม่เพื่อติดตามโค้งลอการิทึมดังนั้นการทำซ้ำของพื้นผิวจะแยกออกไปอีกเมื่อรัศมีเพิ่มขึ้นและเข้าใกล้จุดศูนย์กลางมากขึ้น (อันที่จริงแล้วสิ่งนี้ทำให้เรามียีราฟน้อยลงและเล็กลง ... )
มีแถวหนึ่งหรือสองพิกเซลที่พร่ามัวไปทางซ้ายกลางของรูปสี่เหลี่ยม
สิ่งนี้เกิดขึ้นเนื่องจาก GPU ดูที่พิกัดตัวอย่างเนื้อสัมผัสสองอันเพื่อหาว่าตัวกรองใดที่จะใช้ เมื่อกลุ่มตัวอย่างอยู่ใกล้กันมันจะแสดงพื้นผิวที่แสดงขนาดใหญ่ / ปิดและแสดงระดับ mip ที่มีรายละเอียดมากที่สุด เมื่อตัวอย่างอยู่ห่างไกลกันมันเดาว่าเราจะต้องแสดงพื้นผิวด้วยการซูมขนาดเล็กหรือห่างออกไปและมันจะสุ่มตัวอย่างจากแผนที่ขนาดเล็ก / พร่าเลือนเพื่อให้แน่ใจว่าเราจะไม่ได้รับวัตถุนามแฝงประกาย
ปัญหาอยู่ตรงนี้เราอยู่ที่จุดพันรอบพิกัดพิกัดจาก -180 ถึง 180 องศา ดังนั้นเราจึงสุ่มตัวอย่างจากจุดที่คล้ายกันมากในพื้นที่ผิวซ้ำของเราถึงแม้ว่าพิกัดตัวเลขของพวกเขาทำให้พวกเขาดูเหมือนว่าพวกเขาห่างกัน ดังนั้นเราสามารถให้เวกเตอร์ไล่ระดับสีสุ่มตัวอย่างของเราเองเพื่อแก้ไขสำหรับสิ่งนี้
นี่คือรุ่นที่มีการแก้ไขเหล่านี้:
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
ตัวแปรในตัวที่คุณสามารถเพิ่มลงในพิกัดพื้นผิวของคุณในส่วน (จุดสุดยอด) เพื่อให้ได้เอฟเฟกต์การเลื่อนที่มีราคาถูก เอฟเฟกต์รูปหกเหลี่ยมก็ค่อนข้างตรงไปตรงมาเช่นกัน หากคุณแก้ไขคำถามของคุณเพื่อเน้นเพียงเอฟเฟกต์เดียวและถามว่า "ฉันจะใช้สิ่งนี้ใน Unity shader ได้อย่างไร" เราอาจช่วยคุณได้ ตรวจสอบให้แน่ใจว่าได้ระบุว่า shader จำเป็นต้องตอบสนองต่อแสง / เงาเนื่องจากมีผลกระทบต่อวิธีการเขียน