หน้าแรก · Lab · CG multipass และ relight

CG4 Relight ด้วย normal pass

ให้ประกายไฟส่องหุ่นยนต์ด้วย N·L, albedo และ plus

CG multipass และ relight · ~8 นาที · ฟรี

1 อธิบาย

normal pass เก็บทิศที่ผิวหันไปของแต่ละ pixel เอามา dot กับทิศแสง L แล้วตัดค่าติดลบทิ้ง max(0, N·L) ก็ได้แสง diffuse แบบง่ายที่สุด (Lambert) จากนั้นคูณด้วย albedo กับสีแสง แล้ว plus ลงบน beauty

ประกายไฟอยู่ด้านขวาหน้าของหุ่น ราว 1.7 m จากอก ต่ำกว่าอกเล็กน้อย ตั้ง azimuth และ elevation ของแสงไปทางนั้น ตั้งความแรง แล้วเปลี่ยน “คูณด้วย albedo” เป็น “on” ดูค่าที่ต่างจาก Blender และสลับ view ระหว่าง “แสงที่บวก” กับ “Blender (อ้างอิง)” ว่าแสงตกถูกด้านหรือยัง

added = albedo · max(0, N̂·L) · colour · intensity

2 ลงมือลอง

โจทย์: ทำให้ประกายไฟส่องหุ่นยนต์ เล็งแสงใน comp ให้มาจากทิศของประกายไฟ แล้วทำให้ค่าที่ต่างจาก render ของ Blender ต่ำกว่าเป้าใน panel (เป้าอยู่กึ่งกลางระหว่างค่าเริ่มต้นกับค่าดีสุดที่แสงทิศเดียวทำได้ ซึ่งอยู่ที่ราว 32%)

แสงเริ่มต้นมาจากด้านที่ผิด azimuth −90° คือทิศเข้าหากล้อง 0° คือขวา เทียบ view “แสงที่บวก” กับ “Blender (อ้างอิง)” ว่าด้านไหนของหุ่นยนต์ควรสว่าง แล้วถามตัวเองว่าแสงบนทุกส่วนของหุ่นยนต์ควรเป็นสีเดียวกันหมดจริงไหม

SkyVFX Lab · CG4interactive · 1001

3 เจาะลึก

normal pass เก็บอะไร

normal pass เก็บทิศที่ผิวหันไปในแต่ละ pixel เป็นเวกเตอร์ยาว 1 หน่วย ค่า x y z อยู่ในช่อง r g b แต่ละช่องมีค่าตั้งแต่ −1 ถึง 1 จึงต้องอ่านเป็น data ไม่ใช่สี ที่เห็นเป็นสีใน figure เป็นแค่การแสดงผล

ก่อน relight ต้องรู้ว่า normal อยู่ใน space ไหน world หรือ camera และแกนเป็นแบบมือซ้ายหรือมือขวา Normal pass ของ Cycles ใน Blender เป็น world space และแกน Z ชี้ขึ้น ถ้าเข้าใจ space ผิด แสงจะมาจากด้านที่ผิดแม้จะเล็งถูกแล้ว

เช็ก space แบบเร็ว: sample พื้นที่หันขึ้นฟ้า ถ้าเป็น world space แบบ Z-up ค่าจะไปอยู่ที่ช่อง blue เกือบทั้งหมด หรือเทียบกับทรงกลมที่รู้ทิศแน่นอน

N·L: แสงตกตรงไหน แรงแค่ไหน

N·L = Nx·Lx + Ny·Ly + Nz·Lz ได้ 1 ตรงที่ผิวหันหาแสงเต็ม ๆ ได้ 0 ตรงที่ผิวหันข้างให้แสง และติดลบตรงที่ผิวหันหนีแสง นี่คือเทอม Lambert ของแสง diffuse

ค่าติดลบต้อง clamp ที่ 0 ไม่อย่างนั้นตอน plus จะกลายเป็นการลบแสงออก ผิวด้านหลังจะมืดลงเป็นขอบดำ ใน Nuke ทำ dot ได้ด้วย Expression หรือ ColorMatrix ที่แถวหนึ่งเป็นทิศ L แล้วใช้ช่องนั้น

  1. 1Shuffle N เข้า rgb
  2. 2dot กับ L
  3. 3Clamp ล่างที่ 0
  4. 4× albedo × สีแสง
  5. 5Plus บน beauty

albedo, สีแสง และ plus

max(0, N·L) อย่างเดียวเป็น mask ขาวดำ ถ้าเอาไป plus ตรง ๆ ทุกวัสดุจะได้แสงเทาเท่ากัน ผิวจริงสะท้อนแสงตามสีของมัน จึงต้องคูณด้วย diffuse colour pass (albedo) แล้วคูณด้วยสีและความแรงของแสง

ผลที่ได้คือแสงที่เพิ่มเข้ามา ใช้ Merge plus บน beauty ไม่ใช้ over และไม่ใช้ lift เพราะ lift ยกดำทั้งภาพ ส่วน relight ควรเพิ่มแสงเฉพาะตรงที่แสงตก

ส่วนบอกอะไร
max(0, N·L)แสงตกตรงไหน และแรงแค่ไหนตามมุมผิว
albedoผิวสะท้อนแสงเป็นสีอะไร
สีและความแรงแสงสีส้มของประกายไฟ และแสงสว่างแค่ไหน
Merge plusเพิ่มแสงลงบน beauty โดยไม่แตะส่วนที่ไม่ได้แสง

สิ่งที่ relight ใน comp ทำไม่ได้

relight จาก normal ไม่มีเงาและไม่มี bounce ไม่มีอะไรบังแสง ส่วนที่ควรถูกบังก็ยังได้แสงอยู่ จึงเหมาะกับแสงเสริมเล็ก ๆ เช่นประกายไฟ muzzle flash หรือแสงจากจอ ที่การไม่มีเงาสังเกตได้ยาก แต่ถ้าแสงอยู่ใกล้ ทิศแสงจะเปลี่ยนไปตามจุดบนตัว ทิศเดียวจึงเป็นแค่ค่าเฉลี่ย ถ้าจะเล็งทีละ pixel ต้องใช้ position (P) pass ด้วย ถ้าต้องการเงาใน comp ต้อง render แสงบน geometry ใน 3D

ใน figure นี้ภาพอ้างอิงเป็น point light ที่มีทั้งเงาและ bounce ส่วนแสงของเราเป็น directional แบบ Lambert อย่างเดียว ค่าที่ต่างจึงลดถึง 0 ไม่ได้ ดีที่สุดที่โมเดลนี้ทำได้ราว 32% และเป้าอยู่กึ่งกลางระหว่างค่าเริ่มต้นกับค่านั้น ทิศจากอกหุ่นไปหาประกายไฟคือ azimuth ราว −41° และ elevation ราว −6° แต่ point light เปลี่ยนทิศไปตามจุดบนตัวหุ่นยนต์ ทิศเดียวจึงเป็นแค่ค่าเฉลี่ย

relight ใน comp ใช้เป็นแสงเสริมเล็ก ๆ ถ้าช็อตต้องเห็นเงาจากแสงนั้น ต้อง render แสงนั้นบน geometry ในระบบ 3D หรือขอ render แสงนั้นจากฝั่ง CG

4 ในงานจริง

ทำใน Nuke

  1. Shuffle2: ดึง layer N เข้า rgb อ่านเป็น data ไม่ grade ก่อน
  2. Expression (r*Lx + g*Ly + b*Lz) หรือ ColorMatrix ที่แถวหนึ่งเป็นทิศ L เพื่อได้ N·L
  3. Clamp: ตัดด้านล่างที่ 0 ให้ผิวที่หันหนีแสงไม่ติดลบ
  4. Merge2 (multiply) กับ diffuse colour pass แล้วใช้ Multiply ตั้งสีส้มและความแรงของแสง
  5. Merge2 (plus) ลงบน beauty
  6. ทางเลือก: node ReLight อ่าน layer normal และ position (knob normal vectors และ point positions) แล้วส่องด้วย light 3D ดูให้แน่ว่ามันส่งอะไรออกมาก่อน merge

พลาดบ่อย → แก้ยังไง

  • ✗ relight โดยไม่คูณ albedo ทุกวัสดุได้แสงเทาเท่ากัน✓ คูณ N·L ด้วย diffuse colour pass ก่อน plus
  • ✗ ไม่ clamp N·L ที่ 0 ผิวด้านหลังได้แสงติดลบเป็นขอบมืด✓ Clamp ด้านล่างที่ 0 ทุกครั้ง
  • ✗ normal อยู่คนละ space กับที่คิด (camera กับ world) แสงมาผิดด้าน✓ เช็ก space และแกนก่อน relight ด้วยพื้นหรือทรงกลมที่รู้ทิศ
  • ✗ หวังให้ relight จาก normal สร้างเงา✓ relight ไม่มีเงา ถ้าต้องการเงาต้อง render แสงบน geometry ใน 3D หรือขอจาก CG
  • ✗ เติมแสงด้วย lift หรือ over✓ ใช้ Merge plus ให้แสงเพิ่มเฉพาะที่แสงตก ดำที่เหลือไม่ขยับ

เช็กก่อนส่งช็อต

  • ด้านที่สว่างของหุ่นยนต์หันหาประกายไฟ
  • ไม่มีขอบมืดจากค่าติดลบบนผิวที่หันหนีแสง
  • แสงบนหุ่นยนต์ออกสีตามสีผิวแต่ละส่วน ไม่ใช่เทาเท่ากันหมด
  • ดำตรงที่แสงไม่ตกไม่ถูกยก
  • เช็ก normal space แล้ว ไม่ได้เดาเอา
  • ตรงที่ควรมีเงาจากแสงนี้ จัดการด้วยวิธีอื่นแล้ว

5 เช็กตัวเอง

เช็กตัวเอง 1 ข้อ

relight แล้วทุกส่วนของหุ่นยนต์ได้แสงสีเทาเท่ากันหมด ไม่ว่าสีพ่นจะเป็นสีอะไร ลืมขั้นไหน

สิ่งที่ได้เรียน

🔒 ตอบคำถามด้านบนก่อน แล้วการ์ดนี้จะเปิด

คำถามเพิ่ม

1. ได้แสงจาก relight แล้ว ควรรวมลง beauty แบบไหน

2. แขนหุ่นยนต์ควรบังแสงประกายไฟไม่ให้ถึงลำตัว relight จาก normal จะให้ผลอย่างไร

ตัวเลขมาจากไหน: ภาพทั้งหมด render ด้วย Blender 5.2 Cycles จากฉากทะเลทรายและหุ่นยนต์ของเราเอง (tools/assets/passes_cg.py) แล้วคำนวณในเบราว์เซอร์ Normal pass (world space) และ Diffuse Color pass ของหุ่นมาจาก render เดียวกัน ภาพอ้างอิงเป็น render Cycles แยกของ point light สีส้มที่ตำแหน่งประกายไฟ (มีเงาและแสงสะท้อน) แสงใน comp ของเราเป็นแสงทิศเดียวแบบ Lambert อย่างเดียว (แบบสอนหลักการ) จึงลดค่าที่ต่างถึง 0 ไม่ได้ ค่าดีสุดประมาณจากการค้นทิศเป็นตารางทุก 10° (พร้อมความแรงที่พอดีที่สุดในแต่ละทิศ) แล้วตั้งเป้าไว้กึ่งกลางระหว่างค่าเริ่มต้นกับค่าดีสุด