Displacement Map
สร้างฉากใต้ทะเล โดยใช้ Displacement Map
Chamferbox
ขั้นตอนการสร้าง เตียง ผ้าคลุมเตียง หมอนใบนั้น
Compesite Map
ขั้นตอนการสร้างวัสดุ น้ำ Compesite Map

[Introduction to Shading Language Part 5]
Volume Shader
Volume Shader คือ Shader ที่มีความสามารถในการคำนวณ สีภายใตเนื้อของ Object ที่กึ่งโปร่งใส เช่น ไฟ ควัน ระเบิด เมฆ เป็นต้น Volume Shader ที่เราจะพูดถึงในตอนนี้เป็นลักษณะการใช้งานในรูปของ Fog หรือหมอก
ในงานจริง มีเทคนกในการจำลอง Volume Shader ในหลายลักษณะเช่นการใช Sprite (ภาพแปะบน Plane ที่หันหน้าเข้าหากล้องตลอดเวลา) หรือการใช texture แปะลงบน Sphere หรือ การใช้เทคนิก Ray Marching หรือแม้แต่การใช Fluid Effect
Volume Shader ก็เป็นทางเลือกหนึ่งในหลายๆทางครับ มีการคำรวณเบื้องต้นที่ไม่ยากมากนัก แต่ถ้าลงลึกในรายละเอียด และเทกนิกต่างๆ เช่นการทำ Volume ในรูปแบบที่ไม่เท่ากัน ก็จะต้องการการคำนวณที่ซับซ้อนมากขึ้นเรื่อยๆ
มาลองดูตัวอย่างกันก่อนครับ

ตัวอย่างนี้เป็นการจำลองสภาพหมอกโดยคำนวณจากระยะทางของผิววัตถุถึงกล้อง โดยปริมาณของหมอกจะลดลงแบบ Exponential โดยมีe เป็ยเลขฐาน
float d;
d = 1- exp(-length(I)/distance);
Ci = mix(Ci, fColor, d);
Oi = mix(Oi, color(1,1,1), d);
d คือปริมาณสีของหมอก ซึ่งมีความสัมพันธ์กับระยะทาง length(I) และ distance เมื่อ I คือระยะจากจุด P ถึงกล้อง (จุด P คือจุดบน Surface ที่ทำการ render ในขณะนั้น
มาลองดูกันครับว่าจะใช้งานกันยังไงใน Maya

เป็นฉากง่ายๆที่สร้างจาก Polygon และ Directional Light 1ดวง

เนื่องจากในการคำนวณ ต้องการระยะ I (ระยะจากจุด P ถึงกล้อง) เสมอ ดังนั้นจึงจำเป็นต้องมีsurface อะไรบางอย่าง อยู่หลังสุดเพื่อไม่ให้ฉากหลุดเป็นสีดำ จากภาพด้านบน Background สร้างจาก NURBS Plane แล้ว Parent เข้ากับกล้อง ทำให ้ไม่ว่าจะหมุนกล้องไปด้านไหนก็จะมีsurface ติดอยู่ตลอดเวลา อาจจะใช้วิธีสร้าง Sphere ขนาดใหญ่ขึ้นมาครอบเอาไว้ก็ได้เหมือนกันครับ

จากนั้นก็เริ่มใส Shader ลงไปที่Object ใส่อะไรลงไปก็ได้ครับ ด้านบนนี้ก็มีการใส Texture ลงไปนิดหน่อย จากนั้นก็จัดการโหลด Volume Shader ของเราเข้าไปได้เลย จะเห็นเป็นชื่อ xFog นั่นเองครับ ในการใช้งานเราต้อง Attach xFog เข้ากับ Object ในฉากทุกตัว หมายถึงให้คำนวณ Volume Shader ครอบคลุมพื้นที่ทุกส่วน

distance คือระยะจอง Fog ถ้า distance น้อยหมอกจะมีปริมาณมากขึ้น ส่วน fColor ก็คือสีของหมอกครับ

ภาพด้านบนนี้ก็เป็นการ render โดยตั้งค่า distance ต่างๆกันตั้งแต 75, 37.5, 18.25 จะเห็นได้ชัดเจนว่าหมอกเข้มขึ้นเรื่อยๆ
การสร้างหมอกในลักษณะนี้เป็นตัวอย่างง่ายๆในการใช้งาน Volume Shader ยังไม่มีการคำนวณที่ซับซ้อนมากนัก จะเห็นได้ว่ามีการคำนวณเพียงระยะเดียว คือ ตั้งแต surface ถึงกล้อง ไม่มีการคำนวณแสงระหว่างนั้น ดังนั้นถ้ามีการเปลี่ยนแปลงอะไรบางอย่างเช่นมีอะไซักอย่างบังแสงเอาไว Volume Shader ตัว นี้ก็ไม่สามารถรับรู้ได ้
ลองมาดูShader ที่ซับซ้อนขึ้นอีกนิดครับ
varying vector R;
varying float len;
varying point Q;
varying color expColor;
float l;
R = E - P;
len = length (R);

Q = P;
expColor = 1;
R = normalize (R);
for (l = [getvar Increment]; l < len; l = l+[getvar Increment]) {
illuminance (Q) {
expColor *= color (exp(-[getvar Density]*[getvar Increment]*comp(Cl,0)), exp(-[getvar Density]*[getvar Increment]*comp(Cl,1)), exp([
getvar Density]*[getvar Increment]*comp(Cl,2))) ;
}
Q = P + l*R;
Ci = (1-expColor) * [getvar Scale];
}
}

Shader ตัวนี้มีการใช้งาน illuminance loop เพื่อคำรวณสีของแสงในตำแหน่งต่างๆด้วย และมีfor loop เพื่อคำนวณแสงตามแนวการมองของกล้อง โดยจะ คำนวณทีละจุดๆ แต่ละจุดห่างกันเท่ากับ Increment จะถึงกล้อง การคำนวณแบบนี้มีผลตอคุณภาพโดยตรง ถ้า Increment น้อย ก็จะได้คุณภาพดีแต่ต้อง เสียเวลาในการคำนวณหลายจุด ซึ่งจะกินเวลาในการ render อย่างมาก ในทางตรงข้ามถ้า Increment มากเกินไป ก็จะทำให้เกิดการแบ่งเป็นช่วงบนภาพกรือ เรียกว่า Banding เนื่องจากการคำนวณนี้ใช illuminance loop จึงสามารถคำนวณเงาที่เกิดจาก Depth Map ได้ด้วย

มาดูตัวอย่างใน Maya ครับ

ภาพนี้Render โดยใส SpotLight สองดวงลงไป จะเห็นเส้นของเงาเกิดขึ้นเนื่องจาก Shadow Map

มาทดลองง่ายๆกันดูครับ มีspotlight สองดวง กล้อง และ back plane เพื่อรับ volume shader

แล้วก็ใส xVolumeFog ลงไปที่Object ทุกตัวครับ แล้วก็อย่าลืมทำ spot light ให้กับไฟในฉากด้วย

ตั้งค่า Density ตามความเหมาะสมครับ ค่ามากก็จะทำให้หมอกหนาแน่นมาก

เราก็จะได้ภาพแบบนี้ออกมาไม่ยากเลย ลองมาดูต่อกันอีกหน่อย

มาลองกันดูครับว่าเราจะสามารถทำให้เกิดเงาและเล่นกับค่า Decay ได้รึเปล่า สร้างฉากง่ายๆ และก ็Attach xVolumeFog ลงไปที่object ทุกตัว

สร้าง Shadow Map ให้กับแสง ใช้ด้วยกันหรือแยกกันก็ได้ครับ

ตั้งค่า Falloff เป็น Squared เพื่อให้แสงหายไปเมื่อระยะเพิ่ม และก็ต้องเพิ่ม Kl หรือ Intensity เพื่อให้แสงส่องถึง Object ครับ

คงพอเห็นภาพครับว่า Volume Shader ทำงานอย่างไร Slim Template ตรงนี้คือที่ใช้งานทั้งหมดตั้งแต่เริ่มครับ
slim 1 extensions pixarmp {
extensions pixar pxsl {
template volume xVolumeFog {
label "xVolumeFog"
parameter color Color {
default {1 1 1}
detail varying
}
parameter float Density {
label "Density"
default .1
}
parameter float Increment {
label "Sampling Increment"
default .25
}
parameter float Scale {
label "Overall Scale"
default 1
}
RSLMain {
output "varying vector R;"
output "varying float len;"
output "varying point Q;"
output "varying color expColor;"
output "float l;"
output "R = E - P;"
output "len = length (R);"
generate
output "if ([getvar Increment] > 0) {"
output "Q = P;"
output "expColor = 1;"
output "R = normalize (R);"
output "for (l = [getvar Increment]; l < len; l = l+[getvar Increment]) {"
output "illuminance (Q) {"
output "expColor *= color (exp(-[getvar Density]*[getvar Increment]*comp(Cl,0)), exp(-[getvar Density]*[getvar Increment]*comp
(Cl,1)), exp(-[getvar Density]*[getvar Increment]*comp(Cl,2))) ;"
output "}"
output "Q = P + l*R;"
output "Ci = (1-expColor) * [getvar Scale];"

output "}"
output "}"
}
}
}
template volume xFog {
parameter float distance {
detail varying
default {1}
}
parameter color fColor {
detail varying
default {1 1 1}
}
RSLMain {
generate
output "float d;"
output "d = 1- exp(-length(I)/[getvar distance]);"
output "Ci = mix(Ci, [getvar fColor], d);"
output "Oi = mix(Oi, color(1,1,1), d);"
}
}
}
}
การใช้งาน Volume Shader เป็นการเปลืองเวลา Render พอควรทีเดียวดังนั้น การ render แยก Layer จึงเป็นสงจำเป็น ตัวอย่างด้านบน น่าจะช่วยให้พอ มองภาพการทำงานของ Volume shader ได้ในระกับหนึ่ง มีเทกนิกในการใช้งานอีกมากมาย แล้วแต่เราจะนำไปประยุกต์ใช ้ถ้ามีโอกาศจะเขียนถึงต่อไป ครับ :)

<<Back