Vertex Shader คือขั้นตอนที่สามารถโปรแกรมได้ของไปป์ไลน์กราฟิก (graphics pipeline) ที่ประมวลผลแต่ละจุดยอดของโมเดล 3D อย่างอิสระ ตามข้อมูลจาก Khronos Group, 2025 vertex shader รับอินพุตเป็นแอตทริบิวต์ของจุดยอด — พิกัด, ปกติ, สี และพิกัดพื้นผิว — และแปลงตามตรรกะที่กำหนด Vertex Shader ทำงานสำหรับแต่ละจุดยอดอย่างอิสระ ทำให้สามารถคำนวณแบบขนานได้อย่างมีประสิทธิภาพบนแกน GPU นับพัน
ประเด็นสำคัญ
Vertex Shader คือขั้นตอนที่สามารถโปรแกรมได้ของไปป์ไลน์กราฟิกที่ประมวลผลแต่ละจุดยอดของโมเดล 3D เป็นรายบุคคล จุดยอด (vertex) คือจุดในปริภูมิสามมิติที่มีแอตทริบิวต์: พิกัด xyz, ปกติ, สี และพิกัดพื้นผิว UV
แตกต่างจากไปป์ไลน์ฟังก์ชันคงที่ (fixed-function pipeline) ซึ่งการแปลงดำเนินการตามอัลกอริทึมที่ตายตัว Vertex Shader ให้ผู้พัฒนาควบคุมการแปลงจุดยอดได้อย่างสมบูรณ์ ซึ่งช่วยให้สามารถใช้งาน แอนิเมชันเชิงกระบวนการ การเปลี่ยนรูปโมเดล การสกินโครงกระดูก และการแปลงทางคณิตศาสตร์ใดๆ ทางฝั่ง GPU
ไปป์ไลน์กราฟิก OpenGL ES รวมลำดับขั้นตอนจากข้อมูลอินพุตไปจนถึงภาพสุดท้าย Vertex Shader อยู่หลังจากขั้นตอนการประกอบจุดยอด (vertex assembly) และก่อนขั้นตอนการแรสเตอร์ไรซ์ แต่ละจุดยอดที่ส่งจาก CPU ผ่านบัฟเฟอร์จุดยอดจะผ่าน Vertex Shader เพียงครั้งเดียว และผลลัพธ์จะถูกส่งต่อไปยังขั้นตอนถัดไปสำหรับการประกอบพรimitives
| ขั้นตอนไปป์ไลน์ | วัตถุประสงค์ |
|---|---|
| Vertex Specification | การถ่ายโอนข้อมูลจุดยอดและแอตทริบิวต์จาก VBO |
| Vertex Shader | การประมวลผลแต่ละจุดยอด, การแปลงพิกัด |
| Tessellation | การแบ่งเรขาคณิตเป็นพรimitivesย่อยแบบเลือกได้ |
| Geometry Shader | การสร้างหรือลบพรimitivesแบบเลือกได้ |
| Rasterization | การแปลงพรimitivesเป็นแฟรกเมนต์สำหรับการเติมสี |
Vertex Shader รับแอตทริบิวต์จุดยอดจากบัฟเฟอร์จุดยอด (VBO) ผ่านตัวชี้แอตทริบิวต์จุดยอดที่กำหนดค่าในโค้ด CPU ผู้พัฒนาเขียนโค้ด shader ใน GLSL (OpenGL Shading Language) หรือภาษาที่เทียบเท่า ซึ่งไดรเวอร์ GPU จะคอมไพล์เป็นคำสั่งเครื่องสำหรับชิปเฉพาะ
สำหรับแต่ละจุดยอด Vertex Shader จะดำเนินการสามอย่างตามลำดับ: การอ่านแอตทริบิวต์อินพุต — การใช้การแปลงที่กำหนดโดยผู้พัฒนา — การเขียนผลลัพธ์ไปยังตัวแปรเอาต์พุต เอาต์พุตขั้นต่ำที่จำเป็นคือ ตำแหน่งจุดยอดในสเปซคลิป (gl_Position) ข้อมูลเอาต์พุตอื่นๆ ทั้งหมด (สี, ปกติ, พิกัดพื้นผิว) จะถูกประมาณค่าและส่งต่อไปยังขั้นตอนถัดไป — Fragment Shader
#version 300 es
in vec3 aPosition;
in vec2 aTexCoord;
uniform mat4 uMVP;
out vec2 vTexCoord;
void main() {
gl_Position = uMVP * vec4(aPosition, 1.0);
vTexCoord = aTexCoord;
}
Vertex Shader แก้ปัญหางานต่างๆ มากมายของไปป์ไลน์กราฟิกที่เกี่ยวข้องกับการแปลงเรขาคณิต แต่ละงานดำเนินการผ่านการดำเนินการทางคณิตศาสตร์บนเวกเตอร์และเมทริกซ์ ซึ่งทำงานแบบขนานสำหรับจุดยอดนับพันพร้อมกัน
งานพื้นฐานและทั่วไปที่สุดคือการคูณพิกัดจุดยอดด้วยเมทริกซ์ model, view และ projection (MVP) เมทริกซ์ MVP แปลงจุดยอดจากสเปซโมเดลท้องถิ่นไปยังสเปซคลิป (clip space) ซึ่งจากนั้นจะถูกทำให้เป็นมาตรฐานและแปลงเป็นพิกัดหน้าจอในขั้นตอนอัตโนมัติของไปป์ไลน์
สำหรับตัวละครที่เคลื่อนไหว Vertex Shader จะใช้แอนิเมชันโครงกระดูก (skinning) แต่ละจุดยอดจะผูกติดกับกระดูกหลายชิ้นด้วยน้ำหนักที่กำหนด Vertex blending — ผลรวมถ่วงน้ำหนักของการแปลงจากกระดูกที่ผูกไว้ — ช่วยให้ผิวของตัวละครเปลี่ยนรูปได้อย่างราบรื่นเมื่อโครงกระดูกเคลื่อนที่
Vertex Shader สามารถปรับเปลี่ยนเรขาคณิตตามเวลาหรือพารามิเตอร์ uniform อื่นๆ โดยไม่ต้องให้ CPU มีส่วนร่วม Wave deformation, การเคลื่อนที่ด้วยสัญญาณรบกวน Perlin และเอฟเฟกต์ระลอกน้ำ — เอฟเฟกต์ทั้งหมดนี้ทำงานใน vertex shader โดยไม่ต้องโหลดเรขาคณิตจาก RAM ซ้ำ
แม้ว่า shader ทั้งสองประเภทจะเป็นขั้นตอนที่สามารถโปรแกรมได้ของไปป์ไลน์กราฟิก แต่ Vertex Shader และ Fragment Shader แก้ปัญหาที่แตกต่างกันโดยพื้นฐานและทำงานในขั้นตอนที่ต่างกันของการประมวลผลภาพ
| ลักษณะ | Vertex Shader | Fragment Shader |
|---|---|---|
| ข้อมูลอินพุต | แอตทริบิวต์จุดยอดจาก VBO | ข้อมูลที่ประมาณค่าจาก VS |
| จำนวนการเรียก | จำนวนจุดยอด | จำนวนแฟรกเมนต์ |
| งานหลัก | การแปลงเรขาคณิต | การคำนวณสีพิกเซล |
| ภาระการคำนวณ | ความซับซ้อนของเรขาคณิต | ความละเอียดหน้าจอ |
| การเข้าถึงพื้นผิว | จำกัด (ผ่าน texture lookup) | เข้าถึงได้เต็มที่ |
ความแตกต่างหลักคือ ความถี่ในการเรียก Vertex Shader ถูกเรียกหนึ่งครั้งต่อจุดยอด ในขณะที่ Fragment Shader ถูกเรียกสำหรับแต่ละแฟรกเมนต์ (พิกเซล) ในฉากที่มีความละเอียดสูง จำนวนการเรียก Fragment Shader จะมากกว่าจำนวนการเรียก Vertex Shader เป็นพันเท่า ทำให้การปรับแต่ง pixel shader มีความสำคัญยิ่งขึ้น
ประสิทธิภาพของ Vertex Shader มีความสำคัญอย่างยิ่งสำหรับแอปพลิเคชันแบบเรียลไทม์ โดยเฉพาะในการพัฒนาแอปมือถือที่มีข้อจำกัดด้านการใช้พลังงาน ปัจจัยประสิทธิภาพหลักคือจำนวนจุดยอด ความซับซ้อนของโค้ด shader และแบนด์วิดท์หน่วยความจำ GPU
เพื่อลดภาระบน Vertex Shader จะใช้วิธีการต่อไปนี้ Level of Detail (LOD) — การสลับไปใช้โมเดลเวอร์ชันที่ลดความซับซ้อนเมื่อกล้องเคลื่อนที่ออกจากวัตถุ Instancing — การวาดเรขาคณิตเดียวกันหลายครั้งด้วยเมทริกซ์การแปลงที่แตกต่างกันในการเรียกวาดครั้งเดียว (draw call)
// Vertex Shader ที่รองรับ instancing
in vec3 aPosition;
in mat4 aInstanceMatrix;
uniform mat4 uViewProjection;
void main() {
vec4 worldPos = aInstanceMatrix * vec4(aPosition, 1.0);
gl_Position = uViewProjection * worldPos;
}
Vertex Shader ใน API กราฟิกต่างๆ มีตรรกะคล้ายกัน แต่มีไวยากรณ์และหลักการตั้งชื่อที่แตกต่างกัน มาดูการใช้งาน vertex shader พื้นฐานใน GLSL สำหรับ OpenGL ES 3.0 และใน Metal Shading Language สำหรับ iOS และ macOS
#version 300 es
in vec4 position;
in vec3 normal;
in vec2 texcoord;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
out vec3 vNormal;
out vec2 vTexCoord;
out vec3 vPosition;
void main() {
vec4 mvPosition = modelViewMatrix * position;
vPosition = mvPosition.xyz;
vNormal = normalMatrix * normal;
vTexCoord = texcoord;
gl_Position = projectionMatrix * mvPosition;
}
#include <metal_stdlib>
using namespace metal;
struct VertexIn {
float3 position [[attribute(0)]];
float3 normal [[attribute(1)]];
};
struct VertexOut {
float4 position [[position]];
float3 worldNormal;
};
vertex VertexOut
vertexMain(VertexIn in [[stage_in]],
constant float4x4& mvp [[buffer(1)]]) {
VertexOut out;
out.position = mvp * float4(in.position, 1.0);
out.worldNormal = in.normal;
return out;
}
คำถามที่พบบ่อย
Vertex Shader คือโปรแกรมบน GPU ที่ประมวลผลแต่ละจุดยอดของโมเดล 3D และแปลงพิกัดเป็น พิกัดหน้าจอ ลองนึกภาพโมเดลเป็นตาข่ายของจุดต่างๆ vertex shader จะเคลื่อนจุดเหล่านี้ตามกฎทางคณิตศาสตร์ที่กำหนด
Vertex Shader ประมวลผลจุดยอดและรับผิดชอบเรขาคณิต ในขณะที่ Fragment Shader กำหนดสีของแต่ละพิกเซล แบบแรกถูกเรียกสำหรับแต่ละจุดยอด (พันครั้ง) แบบหลังถูกเรียกสำหรับแต่ละพิกเซล (ล้านครั้ง)
Vertex Shader เขียนด้วยภาษาที่สอดคล้องกับ API กราฟิก: GLSL สำหรับ OpenGL ES, Metal Shading Language สำหรับ Metal API บน iOS/macOS, HLSL สำหรับ Direct3D ในทางแนวคิดแล้ว ทั้งหมดดำเนินการเดียวกันบนจุดยอด
ความซับซ้อนของ vertex shader ส่งผลโดยตรงต่อ FPS: คำสั่งต่อจุดยอดมากขึ้น = เวลาประมวลผลนานขึ้น การปรับแต่ง รวมถึงการลดจำนวนจุดยอดผ่าน LOD การใช้ instancing และการลดการแตกกิ่งแบบมีเงื่อนไขในโค้ด shader
งานหลักในเกม: การแปลงพิกัดผ่านเมทริกซ์ MVP, skinning ตัวละครที่เคลื่อนไหว, การเปลี่ยนรูปเชิงกระบวนการของเสื้อผ้าและเส้นผม, การมอร์ฟระหว่างสีหน้า และเอฟเฟกต์อนุภาคพร้อมแอนิเมชันบน GPU
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม