Material & Shader
Shader là chương trình GPU định nghĩa cách vẽ pixel — Material là instance của Shader với giá trị cụ thể như màu sắc, texture và độ bóng (smoothness).
Hãy tưởng tượng...
Shader là công thức pha sơn (màu gỗ, màu kim loại, màu kính...). Material là mỗi hộp sơn cụ thể — cùng công thức sơn kim loại nhưng một hộp màu vàng, một hộp màu bạc, một hộp độ bóng cao hơn. Bạn có thể tạo ra hàng nghìn Material từ chỉ một Shader, mỗi cái trông khác nhau. Một GameObject dùng Mesh Renderer để "tô màu" mesh bằng Material được chỉ định.
Khái niệm chi tiết
Shader là chương trình HLSL (High Level Shading
Language) chạy trực tiếp trên GPU. Nó gồm ít nhất hai phần: Vertex Shader (biến đổi
vị trí đỉnh từ 3D sang màn hình 2D) và Fragment/Pixel Shader (tính màu cuối cùng của
mỗi pixel). Unity trừu tượng hoá điều này qua ShaderLab syntax và Surface Shader
hoặc URP’s Lit/Unlit Shader Graph.
Material là asset tham chiếu đến một Shader và lưu giá
trị cho các properties của Shader đó: màu chính (_BaseColor), texture (
_BaseMap), độ metallic (_Metallic), độ nhám (
_Smoothness)… Mỗi Renderer có thể có một hay nhiều Material slot tương ứng với
số sub-mesh.
Về hiệu năng, Material instancing rất quan trọng:
nhiều object dùng cùng một Material asset sẽ được gom vào một draw call (GPU
instancing hoặc static batching). Nếu dùng renderer.material (tạo bản sao riêng)
thay vì renderer.sharedMaterial, mỗi object sẽ có draw call riêng và tốn nhiều bộ
nhớ hơn.
Unity cung cấp sẵn các Shader tiêu chuẩn: URP/Lit (PBR đầy đủ),
URP/Unlit (không tính ánh sáng), Sprites/Default (2D),
Particles/Standard Unlit (particle). Shader Graph và HLSL code cho phép tạo hiệu
ứng hoàn toàn tuỳ chỉnh.
Sơ đồ quan hệ Shader → Material → Renderer
📄 Shader (HLSL program)
URP/Lit — định nghĩa properties + render logic
Material A
_BaseColor = Red
_Metallic = 0.9
Material B
_BaseColor = Blue
_Metallic = 0.0
Material C
_BaseColor = Gold
_Metallic = 1.0
🏠 House
Mat A
🚗 Car
Mat B
🏆 Trophy
Mat C
🔑 Key
Mat C
Trophy + Key dùng chung Mat C → 1 draw call (batching)
Hướng dẫn thực hành
Tạo Material mới
Project → chuột phải → Create → Material. Đổi tên rõ ràng (Metal_Gold, Ground_Grass...).
Chọn Shader phù hợp
Inspector → Shader dropdown: URP/Lit cho PBR, URP/Unlit cho vật phát sáng tự nhiên, Sprites/Default cho 2D.
Gán Texture và điều chỉnh properties
Kéo thả texture vào slot Base Map, điều chỉnh Metallic (0=plastic, 1=metal), Smoothness (0=matte, 1=mirror).
Gán Material vào MeshRenderer
Kéo Material vào slot Materials[0] của MeshRenderer, hoặc kéo thẳng lên GameObject trong Scene View.
Thay đổi property qua script
renderer.sharedMaterial.SetColor("_BaseColor", color) — hoặc dùng MaterialPropertyBlock để tránh tạo bản sao Material.
Trình mô phỏng tương tác
Điều chỉnh các tham số PBR để xem cầu thay đổi bề mặt — mô phỏng Material Inspector trong Unity.
// Material Properties
_BaseColor = "#4488ff"
_Metallic = 0.50
_Smoothness = 0.70
_Emission = 0.00
Shader: URP/Lit
Nhựa bóng màu xanh
Ví dụ Code
Cơ bảnThay đổi màu và độ metallic của Material tại runtime.
using UnityEngine;
public class MaterialController : MonoBehaviour
{
Renderer rend;
void Start()
{
rend = GetComponent<Renderer>();
// sharedMaterial: dùng chung với tất cả object → không tạo bản sao
rend.sharedMaterial.SetColor("_BaseColor", Color.red);
// material (không shared): tạo bản sao riêng cho object này
rend.material.SetFloat("_Metallic", 0.9f);
rend.material.SetFloat("_Smoothness", 0.8f);
}
public void Flash(Color color)
{
// Kỹ thuật nhấp nháy: set emission color
rend.material.SetColor("_EmissionColor", color * 2f);
DynamicGI.SetEmissive(rend, color * 2f);
}
}Ví dụ Code
Nâng caoMaterialPropertyBlock — thay đổi property từng object mà không tạo bản sao Material, không phá batching.
using UnityEngine;
// Tô màu từng instance khác nhau mà KHÔNG phá GPU Instancing/Batching
public class InstanceColorizer : MonoBehaviour
{
static readonly int ColorID = Shader.PropertyToID("_BaseColor");
static readonly int EmitID = Shader.PropertyToID("_EmissionColor");
MaterialPropertyBlock mpb;
Renderer rend;
void Awake()
{
rend = GetComponent<Renderer>();
mpb = new MaterialPropertyBlock();
}
public void SetColor(Color color)
{
rend.GetPropertyBlock(mpb); // Đọc trạng thái hiện tại
mpb.SetColor(ColorID, color); // Chỉnh màu
rend.SetPropertyBlock(mpb); // Áp dụng — không tạo Material mới
}
public void SetEmission(Color emitColor)
{
rend.GetPropertyBlock(mpb);
mpb.SetColor(EmitID, emitColor);
rend.SetPropertyBlock(mpb);
}
}📌 Ghi nhớ nhanh
- ▸Shader = công thức, Material = instance với giá trị cụ thể
- ▸sharedMaterial: dùng chung, không tốn RAM thêm
- ▸MaterialPropertyBlock: per-instance, không phá batching
- ▸Metallic=1+Smoothness=1 = gương hoàn hảo
- ▸Shader.PropertyToID() nhanh hơn truyền string mỗi frame
⚠️ Lỗi thường gặp
❌ Dùng renderer.material trong vòng lặp spawn
Mỗi lần tạo bản sao Material mới → rò rỉ bộ nhớ
✅ Dùng MaterialPropertyBlock hoặc sharedMaterial
❌ Quên bật Emission trong Material settings
SetColor("_EmissionColor",...) không có tác dụng nếu chưa bật
✅ Material Inspector → tick "Emission" checkbox trước