[PRMan Memo page 3: Curve Rendering]
Curve Rendering
PRMan สามารถ render เส้นโค้งได้โดยผ่าน primitive RiCurve ในการ render เส้นโค้งแบบนี้ ไม่ RIB file ไม่จำเป็นต้องเส้น
surface ขึ้นมา PRMan สามารถนำ pimitive RiCurve มา render ได้โดยตรง และสามารถตั้งค่าได้หลายอย่าง เช่น จะให้เส้นหันไป
ด้านใด โดยกำหนด normal vector หรือ กำหนดความกว้างของแต่ละส่วนของเส้นไม่ให้เท่ากัน รวมถึง สามารถ attach shader ลงไป
ได้เหมือนกับ surface ทั่วไป
เนื่องจากเส้นโค้งของ PRMan render ได้เร็วมาก และประหยัด memory จึงเหมาะมากในการนำมาสร้างเส้นผม หรือเส้นขน ซึ่งมีจำนวน
เส้นเยอะมาก (มากกว่าแสนเส้น)
มาลองดูกันก่อนครับว่า render ออกมาแล้วเป็นอย่างไรบ้าง

สร้างเส้นขึ้นมาหนึ่งเส้น และไฟหนึ่งดวง

ใช้คำสั่ง renderman>>attibutes>>curve rendering>>attach เพื่อเป็นการบอก mtor มาเราต้องการ render เส้นโค้งเส้นนี้

ถ้าเปิด option ขึ้นมา ก็จะมีoption ให้ตั้ง Width หรือความกว้างของเส้นได้ครับ หน่วยก็จะเป็นหน่วย cm ของ Maya ครับ

หลังจากที่attach เสร็จเรียบร้อยแล้วเส้นโค้งเราก็จะมีattribute ตัวใหม่ขึ้นมาชื่อ mtor curve width เพื่อตั้ง ความกว้างของเส้นหลัง จาก attach แล้ว จะได้ไม่ต้อง attach ใหม่บ่อยๆครับ

สร้าง shader ขึ้นมาซักอันครับ อย่างด้านบนนี้ก็สร้าง Blin ขนมา แล้วตั้งค่า specular ให้เด่นขึ้น จัดการ attach ไปที่เส้นโค้ง และลอง render ดูได้เลยครับ

ก่อน render เข้าไปที่render global หัวข้อ spool และ job setup ที่บรรทัด cleanup กด rib ให้นูนขึ้นมา การทำแบบนี้จะทำให ribfile ที่mtor สร้างขึ้นมาไม่ถูกลบทิ้งไป หลังจากที่render เสร็จแล้ว โดยปกติrib file จะ save ไว้ที่folder /rib

ลอง render ออกมาก็น่าจะได้แบบนี้ครับ
##RenderMan RIB-Structure 1.1
##Creator mtor 4.5, RAT 5.5.1 (May 9 2003 03:39:50)
##For root
##CreationDate Tue Apr 13 20:09:39 2004
version 3.04 Declare "resource" "string"
Declare "dirmap" "string"
Declare "minmax" "int"
Declare "serverresource" "string"
Declare "serverresource" "string"
Option "searchpath" "resource" ["//C/xteapot/gallery/3dmodels/PRManMemo/://C/Program Files/Pixar/rat-5.5.1/lib/shaders://C/Program Files/Pixar/rat-5.5.1/lib://C/Program Files/Pixar/prman11.3/
lib/shaders://C/Program Files/Pixar/prman-11.3/lib:.:@"] FrameBegin 1
Attribute "dice" "binary" [0]
Option "user" "float tracebreadthfactor" [0] "float tracedepthfactor" [0]
PixelSamples 3 3 Exposure 1 1 Hider "hidden" "jitter" [1] PixelFilter "catmull-rom" 3 3
#Shutter 1 1.25 Shutter 0.0416667 0.0520833 Format 640 480 1
Display "C:/xteapot/gallery/3dmodels/PRManMemo/rmanpix/untitled.0001" "it" "rgba" "int merge" [0] "string dspyParams" ["dspyRender -context C:/xteapot/gallery/3dmodels/PRManMemo/scenes/CurveRenderGen.mb -time 1 -renderer 2 -crop 0 1 0 1 -port 3143 -workspace C:/xteapot/gallery/3dmodels/PRManMemo/;"]
Clipping 0.1 1000 Projection "perspective" "fov" [54.4322] ScreenWindow -1 1 -0.75 0.75
ConcatTransform [0.707107 -0.331295 -0.624695 8.89449e-010 1.0402e-010 0.883452 -0.468521 3.20345e-
012 -0.707107 -0.331295 -0.624695 -8.97992e-010 -0.186201 -5.9713 34.42 1]
WorldBegin TransformBegin Rotate 90 0 1 0 CoordinateSystem "_XTOZ" TransformEnd
TransformBegin
Rotate -90 1 0 0
CoordinateSystem "_YTOZ"
TransformEnd
TransformBegin
Scale -1 1 1
CoordinateSystem "_world_lefthanded"
TransformEnd
TransformBegin
CoordSysTransform "_YTOZ"
CoordinateSystem "worldspace"
CoordinateSystem "_environment"
TransformEnd
ReverseOrientation
ShadingRate 5
ShadingInterpolation "smooth"
Surface "defaultsurface"
TransformBegin
Attribute "identifier" "string name" ["directionalLightShape1"]
Transform [-0.965022 -0.258939 0.0410197 0 -0.187234 0.571189 -0.799179 0 0.183509 -0.778906 0.599692
0 0 0 0 1]
LightSource "mtorDirectionalLight" "directionalLightShape1" "float intensity" [1] "color lightcolor" [1 1 1]
"float decayRate" [0]
TransformEnd
AttributeBegin
Attribute "identifier" "name" ["|curve1|curveShape1"]
ConcatTransform [1 0 0 0 0 1 0 0 00 1 0 0 0 0 1]
ShadingInterpolation "smooth"
#slim shadingmodel Blinn_1
TransformBegin
Surface "rmanshader/Blinn_1"
TransformEnd
Basis "b-spline" 1 "b-spline" 1
Curves "cubic" [10] "nonperiodic" "P" [0 0.341772 2.5443 0 0.341772 2.5443
0 0.341772 2.5443 0 2.97637 2.19325 0 8.24557 1.49114 0 7.00506 -7.36962
0 11.1198 -8.25401 0 13.1772 -8.6962 0 13.1772 -8.6962 0 13.1772 -8.6962]
"constantwidth" [0.1]
AttributeEnd
WorldEnd
FrameEnd
ด้านบนนี้คือตัวอย่างของ rib file ที่ได้ออกมาครับ สังเกตตัวทึบ นั่นคือส่วนที่เกี่ยวข้องกับการกำหนดเส้นโค้ง ค่อยข้างชัดเจนครับ เช่น สามารถกำหนด shader ได้โดยการใส่ชื่อลงไปที่บรรทัด surface และกำหนดรูปร่างของเส้นโค้งที่บรรทัด curves ในบรรทัดนี้ก็จะมีการ กำหนดลักษณะต่างๆของเส้นโค้ง เช่นชนิด degree จำนวนจุด เหล่านี้เป็นต้น โดยมีรูปแบบคือ
RIB BINDING
Curves type [nvertices] wrap parameterlist
EXAMPLE
Curves "cubic" [4] "nonperiodic" "P" [0 0 0 -1 -.5 1 2 .5 1 1 0 -1 ] "width" [.1 .04]
Curves "linear" [5] "nonperiodic" "P" [0 0 0 3 4 5 -1 -.5 1 2 .5 1 1 0 -1 ] "constantwidth" [0.075]
ดังนั้น จากรูปแบบและตัวอย่างของ rib file ทำให้เราสามารถเขียน MEL script เพื่อ generate เส้นโค้งขึ้นมาในจำนวนมากได ้เช่น เรา สามารถ generate เส้นโค้ง จาก NURBS surface ได้โดยอาศัยข้อมูลตำแหน่งของ surface point
ลองดูตัวอย่าง MEL script กันหน่อยดีกว่าครับ
//Simple curve generator exaple
//Global value
$drname = "C:/xteapot/gallery/3dmodels/PRManMemo/";
$pnum = 10; //Number of Point on each curve
$cnum = 100; //Number of curves
$sdname = "hair"; //Shader name
$rbname = "cdata"; //Prefix of the output filename$bwd = .1; //Base width $twd = .01; //Tip width $stime = 1; //Start time $etime = 50; //End time $brand = .1; //Base random position$trand = 2.5; //Tip random position
//Calculate width for each point
$wdstep = ($bwd - $twd)/($pnum - 3);
string $wdn = $bwd + " ";
for ($i=1;$i<$pnum-2;$i++) {
$wdn += ($bwd - ($i*$wdstep)) + " ";
}
//Get surfaces name
$CSF = `ls -sl`;
$CSFnum = `size $CSF`;
//Header and footer
$SHeader = "AttributeBegin\n Attribute \"identifier\" \"name\" [\"curvesgen\"]\n ConcatTransform [1 0 0 0
0 1 0 0 0 0 1 0 0 0 0 1]\n ShadingInterpolation \"smooth\"\n TransformBegin\n Surface \"rmanshader/"+
$sdname +"\"\n TransformEnd\n Basis \"b-spline\" 1 \"b-spline\" 1\n Curves \"cubic\" [";
$SFooter = "] \n AttributeEnd ";
// Open file to write
$cFName = $drname + "/rib/" + $rbname + "." + `currentTime -q` +".rib";
$fileId=`fopen $cFName "w"`;
//Write header
fprint $fileId $SHeader;
//Write number of points
for ($j=0;$j<$CSFnum;$j++) {
for ($i=0;$i<$cnum;$i++) {
string $spnum = $pnum + " ";
fprint $fileId $spnum;
}
}
fprint $fileId "] \"nonperiodic\" \"P\" [";
//Loop over number of sufaces to generate curve for each surface
for ($sinx=0;$sinx<$CSFnum;$sinx++) {
//Get surface information
string $SCSF = $CSF[$sinx];
$cmd = "getAttr "+$SCSF+".maxValueU";
$SFmaxU = eval($cmd);
$cmd = "getAttr "+$SCSF+".minValueU";
$SFminU = eval($cmd);
$cmd = "getAttr "+$SCSF+".maxValueV";
$SFmaxV = eval($cmd);
$cmd = "getAttr "+$SCSF+".minValueV";
$SFminV = eval($cmd);
//Write curve points
$cstep = $SFmaxU/$cnum;
for ($i=0;$i<$cnum;$i++) {
vector $crand[];
$brd = sphrand($brand);
$trd = sphrand($trand);
for ($k=0;$k<$pnum;$k++) {
$crand[$k] = $brd + (($trd-$brd)/$pnum*$k);
}
for ($j=0;$j<$pnum-2;$j++) {
$cmd = "pointPosition " + $SCSF + ".uv["+ $j*$SFmaxU/($pnum-2) +"]["+ $i*$SFmaxV/$cnum +"]";
$cvp = `eval($cmd)`;
float $cvpx = $cvp[0];
float $cvpy = $cvp[1];
float $cvpz = $cvp[2];
vector $cvpos = <<$cvpx,$cvpy,$cvpz>>;
$cvpos += $crand[$j];
string $cpos = ($cvpos.x) + " ";
$cpos += ($cvpos.y) + " ";
$cpos += ($cvpos.z) + " ";
fprint $fileId $cpos;
if ($j==0 || $j==$pnum-3) {
fprint $fileId $cpos;
}
}
}
}
//end of writing points loop
//Write curve width
$wds = "] \"width\" [";
fprint $fileId $wds;
for ($j=0;$j<$CSFnum;$j++) {
for ($i=0;$i<$cnum;$i++) {
fprint $fileId $wdn;
}
}
//Write footer
fprint $fileId $SFooter;
//Close file
fclose $fileId;
MEL script อันนี้จะนำข้อมูลของ surface ที่select มา generate เส้นโค้งและเขียน rib file ขึ้นมา
ตัวทึบคือค่า parameter ต่างๆที่เราสามารถกำหนดได ้เช่น shader แบบ hair ซึ่งคือ shader ซึ่งเป็น file hair.slo ใน folder rmanshader ซึ่งเป็น file ที่compile มาจาก hair.sl
surface hair (float Ka = 1, Kd = .6, Ks = .35, roughness = .15;
color rootcolor = color (.109, .037, .007);
color tipcolor = color (.519, .325, .125);
color specularcolor = (color(1) + tipcolor) / 2;
)
{
vector T = normalize (dPdv); /* tangent along length of hair */
vector V = -normalize(I); /* V is the view vector */
color Cspec = 0, Cdiff = 0; /* collect specular & diffuse light */
float cosang;
/* Loop over lights, catch highlights as if this was a thin cylinder */
illuminance (P) {
cosang = cos (abs (acos (T.normalize(L)) - acos (-T.V)));
Cspec += Cl * v * pow (cosang, 1/roughness);
Cdiff += Cl * v;
/* We multipled by v to make it darker at the roots. This
* assumes v=0 at the root, v=1 at the tip.
*/
}
Oi = Os;
Ci = Oi * (mix(rootcolor, tipcolor, v) * (Ka*ambient() + Kd*Cdiff)
+ (Ks * Cspec * specularcolor));
}
ตัวอย่าง shader ใช้กับผมซึ่งคัดมาจาก help ของ renderman ครับ
ส่วน parameter นอกนั้นก็อย่างเช่นความกว้าง และค่า random ลองตั้งดูครับ

เนื่องจาก script อันนี้เขียนขึ้นมาเพื่อสร้างเส้นโค้งตามทิศ U จึงต้อง reverse surface direction ให้ถูกทิศทางที่ต้องการครับ คลิกที่surface ทั้งหมดที่ต้องการและจัดการ execute script ครับ จะได .rib ออกมาที่folder rib

ในการใช้งานเราจะเรียกใช้งานผ่านทาง RIBBox เปิด Slim และสร้าง RIBBox ขึ้นมาหนึ่งอัน

ตั้งชื่อว่า world คือการ attach เข้ากับ object ทุกตัวใน scene และ กด Edit จะเรียก notepad ขึ้นมา

เขียนคำสั่ง ReadArchive และเขียน path ของ rib ที่เราสร้างขึ้นมาลงไปครับ และลองกด render

ก็จะเป็นเส้นในลักษณะนี้ทีนี้ลองมาทำเงากันดูหน่อยครับ

วาง spot light ลงไปและต่อ shadow map เข้าไปที่spot light ของ slim

ตั้งค่าให้เป็น Deep Shadow และเพิ่ม Pixel Samples เป็น 8 จะช่วยให้เงาของเส้นขนมีคุณภาพดีขึ้น และไม่กระพริบเมื่อ animate แต ่ก็ต้องแลกมาด้วยเวลาในการ render ที่เพิ่มมากขึ้นครับ

ได้เงาออกมาง่ายๆแบบนี้ครับ อันนี้ไม่ได้ตั้ง shading rate ในระดับละเอียดและ resolution ของ shadow map ไม่สูงมากนักเงาจึงออก มาเบรอๆครับ
ลองมาดูอีกซักตัวอย่าง

surface สองอันนี้เกิดจากการ extrude วงกลมไปบนเส้นโค้งครับ แล้วก ็execute script และทำตามขึ้นตอนก่อนหน้านี้

ก็ควรจะได้เส้นโค้งแบบนี้ออกมาครับ
MEL script อันนี้เป็นเพียงตัวอย่างครับ สามารถ generate ได้เพียง frame เดียวเท่านั้น จึงทำให้ไม่สามารถทำ animation ได ้ไม ่สามารถปรับค่าในรายละเอียดต่างๆได้เช่นความหงิก การเกลี่ยความกวาง และอื่นๆ ใครที่มีความสามารถในการเขียน MEL script ลองเอา ไปเขียนต่อดูครับ ไม่น่าจะยากเกินไปนัก
การเขียน MEL เพื่อ generate ในลักษณะนี้ข้อดีคือ เข้าใจง่าย ใครเขียน MEL เป็นก็เขียนได้เลย แก้ไขความผิดพลาดที่จะเกิดได้ง่าย แต่ข้อเสียที่สำคัญคือ ทำงานค่อนข้างช้า และ จะมีปัญหาเมื่อตั้งจำนวนเส้น และจำนวน surface ไว้มาก การคำนวณจะเสียเวลามาก แต ่หลังจากคำนวณแล้วก็สามารถนำมา render ได้เร็วครับ
อีกวิธีที่เราสามารถ Genrate เส้นได้คือเขียน slim plugin หรือเขียน rib generator การเขียนในลักษณะนี้จะเขาใจยาก และต้องใช ความสามารถในการเขียนภาษา C++ พอสมควรครับ เนื่องจากต้อง compile ออกมาเป็น dll และเรียกเข้าไปใน slim แต่ข้อดีคือ ทำงาน ได้เร็ว แล้วสามารถเขียน rib ในรูปแบบ binary ซึ่งมีประสิทธิภาพมากกว่าแบบ ASCII ได ้การเขียน rib generator แบบนี้น่าสนใจมาก ครับ สามารถนำไปประยุกต์ใช้งานรูปแบบอื่นๆได้ด้วย เช่นการเขียน rib สำหรับเก็บตัวละครจำนวนมาก เป็นต้น
โอกาศหน้าจะเขียนเรื่อง RIB generator มาเสนอให้อ่านกันครับ
<<Back
|