2009年4月8日 星期三

(3)結合C和RenderMan API來輸出*.rib

這裡要先介紹一個很不錯的免費RenderMan:Pixie,可以去他的官方網站:http://www.renderpixie.com/ 下載。

很多人以為RenderMan=Pixar,事實上~RenderMan只是一套規格,符合這套規格的都可以稱做RenderMan。

這裡用的程式編輯器是Visual Studio.Net 2005。安裝好Pixie後,除了把lib, include, dll...等,copy到Visual Studio.Net 2005對應的目錄下,還要在工具列上的專案→屬性→連結器→輸入→其他相依性,輸入ri.lib sdr.lib。然後,開啟Visual Studio 2005→檔案→新增→專案,選擇"Win32主控台應用程式"按下確定,在彈出視窗左邊的選擇應用程式設定→其他選項→空專案。這裡小轉是將project名稱命名為"RenderMan_Cube"。

然後在原始檔案新增一個C++檔案,key入下面的code(參考資料為"The RenderMan Companion [Steve Upstill]"):

#include <ri.h>
#include <stdio.h>
#define NFRAMES 10 /* number of frame in the animation */
#define NCUBES 5 /* # of minicubes on a side of the color cube */
#define FRAMEROT 5.0 /* # of degrees to rotate cube between frames */

#define L -0.5
#define R 0.5
#define D -0.5
#define U 0.5
#define F 0.5
#define N -0.5

void UnitCube()
{
static RtPoint Cube[6][4]={
{{L,D,F}, {R,D,F}, {R,D,N}, {L,D,N}},
{{L,D,F}, {L,U,F}, {L,U,N}, {L,D,N}},
{{R,U,N}, {L,U,N}, {L,U,F}, {R,U,F}},
{{R,U,N}, {R,U,F}, {R,D,F}, {R,D,N}},
{{R,D,F}, {R,U,F}, {L,U,F}, {L,D,F}},
{{L,U,N}, {R,U,N}, {R,D,N}, {L,D,N}}
};
int i;

for(i=0;i<6;i++)
RiPolygon(4, RI_P, (RtPointer)Cube[i],RI_NULL);
}

void ColorCube(int n, float s)
{
int x, y, z;
RtColor color;//宣告顏色變數
RtObjectHandle cube;//選告物件變數

if(n<=0)
return;

cube = RiObjectBegin();
UnitCube();

RiObjectEnd();

RiAttributeBegin();
RiTranslate(-0.5, -0.5, -0.5);
RiScale(1.0/n, 1.0/n, 1.0/n);//縮放

for(x=0; x<n; x++)
for(y=0; y<n; y++)
for(z=0; z<n; z++)
{
color[0]=((float)x+1)/((float)n);
color[1]=((float)y+1)/((float)n);
color[2]=((float)z+1)/((float)n);

RiColor(color);//指定個別cube的顏色
RiTransformBegin();//將transform的code"包"起來
RiTranslate(x+0.5, y+0.5, z+0.5);
RiScale(s, s, s);
RiObjectInstance(cube);
RiTransformEnd();
}
RiAttributeEnd();
}

void main()
{
int frame;
float scale;
char filename[20];

RiBegin(RI_NULL); /*Start the renderer*/
RiLightSource("distantlight", RI_NULL);//指定light shader明成還有其參數

/*Viewing transformation*/
RiProjection("perspective", RI_NULL);//就是perspective,沒辦法更白話了 XD
RiTranslate(0.0, 0.0, 1.5);//位移
RiRotate(40.0, -1.0, 1.0, 0.0);//旋轉

for(frame=1; frame<=NFRAMES; frame++)
{
sprintf(filename, "anim%d.jpg", frame);
RiFrameBegin(frame);
RiDisplay(filename, "framebuffer", "rgb", RI_NULL);
RiWorldBegin();
scale=(float)(NFRAMES-(frame-1))/(float)NFRAMES;
RiRotate(FRAMEROT*frame, 0.0, 0.0, 1.0);//以z軸為中心旋轉
RiSurface("matte",RI_NULL);//指定surface shader名稱還有其參數
ColorCube(NCUBES, scale);
RiWorldEnd();
RiFrameEnd();
}
RiEnd();
}


有用過OpenGL的話,應該整個覺得很熟悉(話說小轉第一次用RenderMan API時,覺得根本就是OpenGL吧)。RenderMan的function名稱都是"Ri"開頭,變數名稱為"Rt"開頭。用紅色mark起來的那兩行程式碼,會在下面介紹其功用。

執行後可以看到10個buffer(因為code中的frame數=10),有5x5x5個cube在旋轉,且邊旋轉邊縮小(下兩張圖為示意):




◎如果將RiDisplay(filename, "framebuffer", "rgb", RI_NULL);中的"framebuffer"改成"file"來執行,則會在project底下產生10張*.jpg,且檔案名稱為filename。




























◎如果將RiBegin(RI_NULL);RI_NULL改成一個*.rib的名稱(這裡小轉是用"rotate_cubes.rib"),則會在project底下輸出一個名稱為rotate_cubes的*.rib(如上上圖)。

◎將rotate_cubes.rib複製到Pixie\bin,並在命令提示字元裡,將路徑切換到Pixie\bin底下,輸入 rndr rotate_cubes.rib,則會在這個目錄底下產生如剛才的10張圖檔。

注意:Pixar的RenderMan的render程式為prman,而Pixie的則為rndr。





































來看看這個rotate_cubes.rib,用文字編輯器開啟,可以看到如下的code(因為這code落落長,所以只截取部份):


## Pixie 2.2.5

## Generated Tue Apr 07 23:41:15 2009

LightSource "distantlight" 1
#就是light shader以及其參數囉


Projection "perspective"
Translate 0 0 1.5
Rotate 40 -1 1 0
FrameBegin 1
#第一個frame開始!到下一個FrameEnd前,都是這個frame會render出來的東西

Display "anim1.jpg" "file" "rgb"
#輸出*.jpg,若是將file改成frmaebuffer,則會直接在一個視窗呈現(如第1張圖)

WorldBegin
Rotate 5 0 0 1
Surface "matte"
ObjectBegin 1
Polygon "P" [-0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 ]
Polygon "P" [-0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 ]
Polygon "P" [0.5 0.5 -0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 0.5 0.5 ]
Polygon "P" [0.5 0.5 -0.5 0.5 0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 ]
Polygon "P" [0.5 -0.5 0.5 0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 0.5 ]
Polygon "P" [-0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 ]
ObjectEnd
AttributeBegin
Translate -0.5 -0.5 -0.5
Scale 0.2 0.2 0.2
Color [0.2 0.2 0.2]
TransformBegin
Translate 0.5 0.5 0.5
Scale 1 1 1
ObjectInstance 1
TransformEnd
Color [0.2 0.2 0.4]
TransformBegin
Translate 0.5 0.5 1.5
Scale 1 1 1
ObjectInstance 1
TransformEnd
Color [0.2 0.2 0.6]
TransformBegin
Translate 0.5 0.5 2.5
Scale 1 1 1
ObjectInstance 1
TransformEnd

~~~我是code分隔線~~~

AttributeEnd
WorldEnd
FrameEnd
#這是對應上面的FrameBegin

FrameBegin 2
#第二個frame開始!
Display "anim2.jpg" "file" "rgb"
WorldBegin
Rotate 10 0 0 1
Surface "matte"
ObjectBegin 2
Polygon "P" [-0.5 -0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 ]
Polygon "P" [-0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 ]
Polygon "P" [0.5 0.5 -0.5 -0.5 0.5 -0.5 -0.5 0.5 0.5 0.5 0.5 0.5 ]
Polygon "P" [0.5 0.5 -0.5 0.5 0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 ]
Polygon "P" [0.5 -0.5 0.5 0.5 0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 0.5 ]
Polygon "P" [-0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 -0.5 ]
ObjectEnd
AttributeBegin
Translate -0.5 -0.5 -0.5
Scale 0.2 0.2 0.2
Color [0.2 0.2 0.2]
TransformBegin
Translate 0.5 0.5 0.5

~~~我是code分隔線~~~

其實....看的出來都是很白話的code,就懶的各個做解釋了XD。也很明顯的可以觀察出*.rib和*.cpp的對應關係。

2 則留言:

  1. 写的结构层次很清晰,很适合我这种想入门的人。
    另外想问一下您,现在renderman与mentalray相比有何优势?mentalray也可以自定义shader啊。

    回覆刪除
  2. 這我就不是很清楚了...@@,對mental ray沒啥研究的說。不過倒是有聽說RenderMan比mental ray穩定,而且可以操控的細部參數也比較多。

    回覆刪除