Fragment Shader คือขั้นตอนที่สามารถโปรแกรมได้ของไปป์ไลน์กราฟิก ซึ่งกำหนดสีสุดท้ายของแต่ละชิ้นส่วน (พิกเซล) ของภาพ ตามข้อมูลจาก Khronos Group, 2025 เชดเดอร์ชิ้นส่วนรับข้อมูลที่ถูกประมาณค่าระหว่างกลางจาก Vertex Shader และดำเนินการคำนวณแสง การทำพื้นผิว และเอฟเฟกต์สี Fragment Shader ถูกเรียกสำหรับแต่ละพิกเซล ทำให้เป็นขั้นตอนที่ใช้ทรัพยากรมากที่สุดในไปป์ไลน์กราฟิก
ประเด็นสำคัญ
Fragment Shader (เชดเดอร์ชิ้นส่วนหรือพิกเซล) คือขั้นตอนที่สามารถโปรแกรมได้ของไปป์ไลน์กราฟิกซึ่งคำนวณสีสุดท้ายของแต่ละชิ้นส่วนของภาพ ชิ้นส่วนคือพิกเซลที่อาจกลายเป็นพิกเซลที่มองเห็นได้บนหน้าจอหลังจากผ่านการทดสอบความลึกและสเตนซิล
Fragment Shader ทำงานหลังการแรสเตอร์ไรซ์ เมื่อพรีมิทีฟ 3D (สามเหลี่ยม) ได้ถูกแปลงเป็นชุดของชิ้นส่วนแล้ว เชดเดอร์ได้รับ แอตทริบิวต์ที่ถูกประมาณค่าระหว่างกลาง — พิกัดพื้นผิว, ปกติ, สีที่ถูกคำนวณใน Vertex Shader สำหรับจุดยอดของสามเหลี่ยมและถูกประมาณค่าเชิงเส้นสำหรับแต่ละพิกเซลภายในสามเหลี่ยม
ก่อนการถือกำเนิดของเชดเดอร์ที่สามารถโปรแกรมได้ (ก่อน DirectX 8 / OpenGL 2.0) การคำนวณสีพิกเซลดำเนินการโดยไปป์ไลน์คงที่พร้อมชุดการดำเนินการที่จำกัด Fragment Shader ที่สามารถโปรแกรมได้ ปรากฏในปี 2001 และขยายขีดความสามารถด้านกราฟิกอย่างรุนแรง: นักพัฒนาได้รับการควบคุมสีของแต่ละพิกเซลอย่างสมบูรณ์ ทำให้สามารถใช้แสงเสมือนจริง วัสดุที่ซับซ้อน และเอฟเฟกต์หลังการประมวลผล
Fragment Shader ถูกเรียกใช้โดย GPU สำหรับแต่ละชิ้นส่วนที่สร้างโดยแรสเตอร์ไรเซอร์ แต่ละการเรียกเชดเดอร์ประมวลผลหนึ่งชิ้นส่วน อ่านข้อมูลนำเข้า ดำเนินการโค้ดผู้ใช้ และเขียนค่าเอาต์พุต — สีของชิ้นส่วนในรูปแบบ RGBA
ข้อมูลนำเข้าของ Fragment Shader รวมถึงแอตทริบิวต์ที่ถูกประมาณค่าระหว่างกลางจาก Vertex Shader (พิกัดพื้นผิว, ปกติ, สี), ตัวแปร uniform (แหล่งกำเนิดแสง, เมทริกซ์) และตัวอย่างพื้นผิว ข้อมูลส่งออกคือ เวกเตอร์สี (gl_FragColor ใน OpenGL ES 2.0 หรือตัวแปรที่ผู้ใช้กำหนดใน ES 3.0) ซึ่งถูกเขียนลงในบัฟเฟอร์สี
#version 300 es
precision mediump float;
in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
fragColor = texture(uTexture, vTexCoord);
}
Fragment Shader รับผิดชอบคุณภาพทางภาพของภาพ เอฟเฟกต์ทั้งหมดที่ผู้ใช้เห็นบนหน้าจอ — สี, เงา, การสะท้อน, ความโปร่งใส — ถูกคำนวณในขั้นตอนนี้ของไปป์ไลน์กราฟิก
การดำเนินการที่พบบ่อยที่สุดคือการสุ่มสีจากพื้นผิวโดยใช้พิกัด UV ที่ถูกประมาณค่าระหว่างกลาง Sampler2D และฟังก์ชัน texture() อนุญาตให้รับสีพิกเซลจากแผนที่พื้นผิว การกรอง (bilinear, trilinear, anisotropic) ถูกควบคุมผ่านพารามิเตอร์ของตัวอย่างและส่งผลต่อความคมชัดของภาพในมุมมองที่แตกต่างกัน
แบบจำลองการแรเงาแบบ Phong ถูกคำนวณใน Fragment Shader ต่อพิกเซล ซึ่งให้ไฮไลต์ที่เรียบเนียนกว่าการให้แสงที่จุดยอด (การแรเงาแบบ Gouraud) แสงแบบ Phong ประกอบด้วยสามองค์ประกอบ: โดยรอบ (ambient), การกระจาย (diffuse) และการสะท้อนแบบ specular
// Fragment shader with Phong lighting
in vec3 vNormal;
in vec3 vPosition;
uniform vec3 uLightDir;
uniform vec3 uLightColor;
void main() {
vec3 norm = normalize(vNormal);
float diff = max(dot(norm, uLightDir), 0.0);
fragColor = vec4(uLightColor * diff, 1.0);
}
Fragment Shader อนุญาตให้ใช้การประมวลผลภายหลัง: การแก้ไขสีผ่านตารางค้นหา (LUT), การเบลอ (blur), เอฟเฟกต์เรืองแสง (bloom) และ tonemapping สำหรับการเรนเดอร์ HDR เอฟเฟกต์ทั้งหมดนี้ทำงานที่ระดับพิกเซลและทำงานแบบเรียลไทม์
ประสิทธิภาพของ Fragment Shader เป็นปัจจัยหลักที่จำกัด FPS ในเกมมือถือสมัยใหม่ เนื่องจากเชดเดอร์ถูกเรียกสำหรับแต่ละพิกเซล แม้การเพิ่มความซับซ้อนของโค้ดเพียงเล็กน้อยก็อาจทำให้อัตราเฟรมลดลงอย่างเห็นได้ชัด
สำหรับ GPU มือถือ (Qualcomm Adreno, ARM Mali) แนะนำให้: ใช้ mediump precision สำหรับตัวแปร float, รวมการสุ่มตัวอย่างพื้นผิว, ใช้การทดสอบ early-z เพื่อทิ้งชิ้นส่วนที่มองไม่เห็นก่อนการทำงานของเชดเดอร์
| วิธีการ | คำอธิบาย | ประโยชน์ |
|---|---|---|
| Mediump precision | ความแม่นยำ 16 บิตแทน 32 บิต | เร็วขึ้นถึง 2 เท่า |
| Early-Z | ทดสอบความลึกก่อนเชดเดอร์ | ลดการเรียก |
| Texture atlasing | พื้นผิวเดียวแทนหลายอัน | สลับน้อยลง |
เชดเดอร์ทั้งสองประเภทสามารถโปรแกรมได้โดยนักพัฒนา แต่ทำงานในขั้นตอนต่างๆ ของไปป์ไลน์และแก้ปัญหาต่างกัน Fragment Shader ใช้ทรัพยากรมากกว่าอย่างมีนัยสำคัญเนื่องจากจำนวนการเรียก
| พารามิเตอร์ | Fragment Shader | Vertex Shader |
|---|---|---|
| จำนวนการเรียก | หลายล้าน (ความละเอียดหน้าจอ) | หลายพัน (จำนวนจุดยอด) |
| ข้อมูลนำเข้า | แอตทริบิวต์ที่ถูกประมาณค่าระหว่างกลาง | แอตทริบิวต์จุดยอด |
| หน้าที่หลัก | คำนวณสีของชิ้นส่วน | แปลงเรขาคณิต |
| การเข้าถึงพื้นผิว | เต็มที่ (หลายตัวอย่าง) | จำกัด |
| ผลกระทบต่อประสิทธิภาพ | สูง (ขึ้นอยู่กับความละเอียด) | ปานกลาง (ขึ้นอยู่กับเรขาคณิต) |
Fragment Shader อาจเรียบง่าย (การสุ่มตัวอย่างพื้นผิว) หรือซับซ้อน (แสงหลายชั้น) ลองดูตัวอย่างที่ใช้งานได้สองตัวอย่าง: การทำพื้นผิวพื้นฐานและเอฟเฟกต์การไล่ระดับสีโดยใช้เวลา
#version 300 es
precision mediump float;
in vec2 vTexCoord;
in vec3 vColor;
uniform sampler2D uDiffuseMap;
out vec4 fragColor;
void main() {
vec4 texColor = texture(uDiffuseMap, vTexCoord);
fragColor = texColor * vec4(vColor, 1.0);
}
#include <metal_stdlib>
using namespace metal;
struct FragmentIn {
float2 texCoord;
float3 normal;
};
fragment float4
fragmentMain(FragmentIn in [[stage_in]],
texture2d<float> tex [[texture(0)]]) {
constexpr sampler s(filter = linear);
float4 color = tex.sample(s, in.texCoord);
return color;
}
คำถามที่พบบ่อย
Fragment Shader คือโปรแกรมขนาดเล็กบน GPU ที่กำหนดว่าพิกเซลแต่ละพิกเซลบนหน้าจอจะเป็นสีอะไร ถ้า Vertex Shader กำหนด รูปร่างของวัตถุ แล้ว Fragment Shader กำหนดว่าวัตถุนั้นมีลักษณะอย่างไร — พื้นผิว, แสง, สี
Fragment Shader ถูกเรียกสำหรับทุกพิกเซลบนหน้าจอ บนอุปกรณ์ที่มีความละเอียด 2532x1170 (iPhone) นี่เกือบ 3 ล้านการเรียก ต่อเฟรม ที่ 60 FPS เชดเดอร์ทำงาน 180 ล้านครั้งต่อวินาที ซึ่งต้องใช้พลังการคำนวณมหาศาล
ใน Fragment Shader มีการใช้งาน: การทำพื้นผิว, แสง (Phong, PBR), เงา, การสะท้อน, การหักเห, bloom, ความลึกของภาพ, การแก้ไขสี, ฟิลเตอร์ LUT และการสร้างพื้นผิวเชิงกระบวนวิธี
ใช้ mediump precision สำหรับ float, ลดจำนวนการสุ่มตัวอย่างพื้นผิว, ใช้ early-z culling, รวมการดำเนินการเชดเดอร์ และหลีกเลี่ยงการแยกสาขาแบบมีเงื่อนไขภายในเชดเดอร์
มันคือสิ่งเดียวกัน คำว่า Fragment Shader ใช้ใน OpenGL / Vulkan ในขณะที่ Pixel Shader ใช้ในคำศัพท์ของ Direct3D (Microsoft) ในแง่การทำงานแล้วเหมือนกัน: ทั้งคู่คำนวณสีของแต่ละชิ้นส่วน/พิกเซล
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม