[Shader] Part 5: Diffuse Reflection

Khi học shader, đây chính là phần mà tôi thấy thú vị nhất…. Phản xạ ánh sáng (Light Reflection)

Chúng ta sẽ tìm hiểu cách mà một vật bị “ảnh hưởng” bởi ánh sáng, dựa trên những đặc tính của bề mặt vật thể (nhẵn nhụi, gồ ghề, trong suốt, tự phát sáng…)

Trong thế giới thực, hầu hết các vật thể đều không tự phát ra ánh sáng khả kiến. Mà phải nhờ đến sự phản xạ từ ánh sáng mặt trời, hoặc ánh sáng nhân tạo.

Về cơ bản, sự phản xạ ánh sáng có thể chia làm 2 loại:

  • Phản xạ khuếch tán (Diffuse Reflection)
  • Phản xạ phản chiếu – phản chiếu gương (Specular Reflection)
Phong_Reflection
Ambient light + Diffuse reflection + Specular highlight = Phong Reflection

Reference articles: wikipedia


Mục lục

  1. Knowledge:
    1. Diffuse reflection
    2. Dot product
  2. Analysis:
    1. Light color
    2. Light direction
    3. Normal direction

Knowledge

Diffuse Reflection

Diffuse reflection hay còn có tên gọi khác là Lambertian reflectance.

Khái niệm có vẻ hơi trừu tượng nhỉ, phản xạ khuếch tán?

Phản xạ khuếch tán là sự phản xạ của ánh sáng từ bề mặt vật thể. Hầu hết các vật thể có bề mặt mờ đục và xỉn, sẽ có chỉ có “phản xạ khuếch tán” (không có Specular Highlight)

Ánh sáng được phản xạ tới tất cả các hướng mà không tồn tại specular highlight (hình lớn) và (hình trên bên phải) có sự tồn tại của specular highlight

Trong trường hợp lý tưởng, cường độ ánh sáng phản xạ (intensity) được tính toán dựa trên cosine của góc giữa normal vector (vector pháp tuyến) và lighting direction (tia sáng chiếu đến).

Reference articles: wikibooks – wikipedia

Dot Product

Trong tiếng việt, có tên gọi là tích vô hướngDot product hay còn gọi là scalar product (theo nvidia unity)

Bỏ qua những yêu tố ngoại cảnh (màu sắc, hằng số, …) bản chất việc tính cường độ ánh sáng cho bề mặt vật thể, chính là tính tích vô hướng của 2 vector N, L {\displaystyle \mathbf {a} \cdot \mathbf {b} =\left\vert \mathbf {a} \right\vert \left\vert \mathbf {b} \right\vert \cos \measuredangle (\mathbf {a} ,\mathbf {b} )}

Công thức tính cường độ ánh sáng:

Idiffuse = lightColor . kdiffuse . max(0, dot(N, L))
  • Idiffusecường độ phản xạ khuếch tán (intensity)
  • lightColor — màu sắc của ánh sáng chiếu tới (_LightColor0)
  • kdiffusehằng số của màu material (white surface: k = 1)
  • N — vector pháp tuyến (normal vector), đã được chuẩn hóa (normalized)
  • L — vector L hướng về phía nguồn sáng, đã được chuẩn hóa (normalized)
  • P — điểm, hay vertex đang xét
  • max(), dot() — là hàm của thư viện CG

Công thức tính tích vô hướng của 2 vector (a, b, c) và (d, e, f):

Dot(abc, def) = ad + be + cf

Hình dưới cho ta biết kết quả của việc tính tích vô hướng của 2 vector N, L bất kỳ

dot_product

Vậy… kết quả tính được sẽ nằm trong khoảng (-1, 1), ta quan sát được phản xạ khuếch tán rõ ràng nhất, ở nơi có dot(N, L) = 1 (là nơi vector N & vector L cùng hướng)

Nếu dot(N, L) < 0, bề mặt vật thể không hề phản xạ ánh sáng.

Nên để tránh sai sót, ta sẽ dùng hàm max() để cường độ phản xạ không bị nhận giá trị âm.

Reference articles: unitycookie


Analysis

Hm… theo công thức tính diffuse reflection bên trên. Ta sẽ có những mối bận tâm sau:

  • lightColor
  • light direction (vector L)
  • normal direction (vector N)

Light Color

uniform float4 _LightColor0;

màu của nguồn sáng hiện tại

Unity đã dùng một biến _LightColor0 để tính sẵn cho chúng ta.

Mặc dù nằm trong Built-in shader variables . Nhưng ta vẫn phải khai báo như một biến bình thường.

Light Direction

float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

hướng của ánh sáng

Ta có thể dễ dàng lấy được light direction, vì unity đã cung cấp sẵn cho ta Built-in shader variables. Ấn vào link và Ctrl + F, tìm đến _WorldSpaceLightPos0.

Phân tích _WorldSpaceLightPos0

  • có kiểu dữ liệu float4 (x, y, z, w)… ồ, lại có đại lượng w
  • với point light:
    • _WorldSpaceLightPos0.xyz: điều khiển vị trí (location) của light source
    • _WorldSpaceLightPos0.w = 1
  • với directional light:
    • _WorldSpaceLightPos0.xyz: điều khiển góc quay (rotation) của light source
    • _WorldSpaceLightPos0.w = 0
Q: Tại sao directional light lại có 4th component w = 0 nhỉ…??

Tôi sẽ giải thích ở một part khác. Hiện tại ở tutorial lần này, chúng ta chỉ thực hiện với Directional light. Vậy nên tạm thời chỉ xử lý với w = 0

Normal Direction

Trước hết, ta phải khai báo normal vector. Với semantic là NORMAL.

float3 normal : NORMAL;
Q: Lại một câu hỏi nữa, normal aka. normal vector là gì?

Tạm thời hãy hiểu, normal là một vector pháp tuyến của mặt phẳng tiếp tuyến tại vertex đang xét.

float3 normalDirection = normalizemulfloat4(i.normal, 0.0), unity_WorldToObject).xyz );

Với normal direction, ta phải xử lý cẩn thận một chút.

Đầu tiên, ta nhân normal vector với model matrix inverse (unity_WorldToObject aka. _World2Object). Rồi chuẩn hóa (normalize) nó…

Q: Ta đang đưa các vertex từ object space -> world space… Sao lại nhân với model matrix inverse?

Tôi sẽ đưa câu trả lời ở part sau…


Practice

Properties

Nào bắt đầu với Properties, ở đây ta sẽ khai báo một thuộc tính _Color, để điều chỉnh màu của phần vật thể nhận diffuse reflection , không có khó khăn gì cả:

Properties
{
	_Color("Diffuse Color", Color) = (1, 1, 1, 1)
}

CGPROGRAM

Vertex Shader

Đây là phần code xử lý bên trong vertex shader

vertexOutput vert (vertexInput i)
{
	vertexOutput o;

	//---Calculate, normalize direction
	float3 normalDirection = normalize( mul(float4(i.normal, 0.0), unity_WorldToObject).xyz );
	float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

	//---Calculate light
	float3 diffuseReflection = _Color.rgb * _LightColor0.rgb * max(0, dot(normalDirection, lightDirection));
	float3 lightFinal = diffuseReflection + UNITY_LIGHTMODEL_AMBIENT;

	o.col = float4(lightFinal, 1);
	o.pos = mul(UNITY_MATRIX_MVP, i.vertex);

	return o;
}

 

Hầu như tôi đã giải thích bên trên hết rồi,

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: