用計(jì)算機(jī)程序制作三維立體畫
時(shí)間:2022-10-08 02:59:00
導(dǎo)語:用計(jì)算機(jī)程序制作三維立體畫一文來源于網(wǎng)友上傳,不代表本站觀點(diǎn),若需要原創(chuàng)文章可咨詢客服老師,歡迎參考。
摘要該文介紹了三維立體畫的原理和制作方法,并給出了用C語言編寫的源程序。借助于Pbrush.exe,讀者可以自己設(shè)計(jì)和欣賞各式各樣的三維立體畫。
目前,市面上正在流行各式各樣的立體畫,其特點(diǎn)是從外表來看與一般的圖案很相似,但是雙眼緊盯著注視片刻后,一恍惚之間眼前便出現(xiàn)了畫中畫——立體像。筆者第一次看到這種畫便被發(fā)明者的創(chuàng)意所傾倒。利用眾所皆知的雙眼視差原理,竟能在一張平面紙上制造出如此奇幻。但是立體畫本身除了其發(fā)明者的靈感和畫面創(chuàng)作者的別出心裁之外,其原理上并無神秘之處。用計(jì)算機(jī)程序來實(shí)現(xiàn)它,可說是易如反掌。筆者用一個(gè)晚上時(shí)間,便在微機(jī)上用BASIC語言實(shí)現(xiàn)了簡單形體——平面圓餅的立體畫。當(dāng)然,要使該程序具有完善的功能,提高其制作速度,還是應(yīng)該用編譯語言(如C語言)來編寫。本文中給出的源程序借助于Windows中的.BMP圖形文件,可使大家自己制作任意形態(tài)的立體畫。
一、立體畫的原理
看過立體電影的人都知道,當(dāng)人的雙眼分別接收不同視角拍攝的圖像時(shí)便會產(chǎn)生立體感。這是由于人眼長期觀察的習(xí)慣造成的。和立體電影原理相同的立體攝影風(fēng)景照片也很早就已出現(xiàn)。圖1中給出了這種立體照片的示意圖。左、右照片分別是人的雙眼角度上觀察一棱錐體時(shí)左右眼看到的圖像(圖2)。左眼看到的是棱錐的頂端向右錯(cuò)動了一些的圖像,右眼的看到則是棱錐的頂端向左錯(cuò)動了一些的圖像。如果用一張硬卡片隔開兩張照片(如圖3),@@09A04000.GIF;圖1@@
@@09A04001.GIF;圖2@@
@@09A04002.GIF;圖3雙眼分別看兩張畫,會看到一個(gè)立體的棱錐體。這種立體照片的觀察方法在測繪學(xué)中也早已采用。
但是,目前的三維立體畫在形式上與這些很不相同。它是怎樣在同一張畫面上呈現(xiàn)立體的呢?首先,分析一下人們是怎樣從這些立體畫中看出“立體形體”的。從前面所說的可以知道,人眼要得到立體感,雙眼必須有視差,即雙眼看到的圖像應(yīng)該有差異。人們在看立體畫時(shí),都有“恍惚”一下的過程。在這過程中,雙眼的視中心發(fā)生了錯(cuò)動(如圖4)。這樣@@09A04003.GIF;圖4左眼看到的是畫面的“偏左像”,右眼看到的是畫面的“偏右像”。@@只要“偏左像”和“偏右像”的內(nèi)容相當(dāng)于圖1的左、右照片,雙眼就會感到立體形體。那么,能否把圖1的左、右照片分別當(dāng)做“偏左像”和“偏右像”,簡單重疊來得到立體畫呢?
顯然不行。能夠合成立體畫的“偏左像”和“偏右像”是要滿足一定條件的。
如果圖5中表現(xiàn)的棱錐體的表面上有圖案的話,
@@09A04004.GIF;圖5像素a和像素a''''應(yīng)該具有相同的顏色,因?yàn)樗鼈兪菑牟煌暯怯^察的@@同一個(gè)實(shí)體點(diǎn)。像素b和像素b''''、像素c和像素c''''的情況與此相同。把兩幅畫分別當(dāng)作“偏左圖”和“偏右圖”,部分重疊成為同一畫面時(shí),在新的畫面上這種關(guān)系仍應(yīng)該表現(xiàn)為a=a'''',b=b'''',c=c''''(如圖6)。但這時(shí)應(yīng)該注意到,在這張合成
@@09A04005.GIF;圖6畫面上,點(diǎn)a''''既是“偏右圖”上的點(diǎn)a'''',又是“偏左圖”上的點(diǎn)b。而@@一張畫面上相同坐標(biāo)點(diǎn)的像素只可能是一種顏色,因此,產(chǎn)生了新的像素關(guān)系a''''=b。另外,點(diǎn)a既是“偏左圖”上的點(diǎn)a,又是“偏右圖”上的點(diǎn)c'''',所以,a=c''''。以此類推,點(diǎn)b''''和點(diǎn)c也有類似的情況。因此出現(xiàn)了新的關(guān)系表示式,...''''=c=c''''=a=a''''=b=b''''=...。這就構(gòu)成了立體畫面上像素必須要滿足的條件:“等顏色像素鏈”。立體畫上的所有點(diǎn)都從屬于某一條“等顏色像素鏈”。這就是所有立體畫圖案都呈現(xiàn)出某種程度上的水平周期性的原因。
因此,對于任意立體形狀,只要構(gòu)造出相應(yīng)的這種“等像素鏈”,并按其規(guī)律充填圖案即可得到立體畫。但是正如前面所述,由于這種“等像素鏈”條件的約束,人們雖然可以隨意構(gòu)造出各種形體的立體畫,但其立體形體的表面圖案是不能完全隨人意愿的。
二、制作立體畫的計(jì)算機(jī)程序
由于人的雙眼的水平性,以上的“等像素鏈”只按水平方向分布,與垂直方向無關(guān)。因此,在程序中,各個(gè)像素行的處理過程是相互獨(dú)立的。制作立體畫的程序主結(jié)構(gòu)圖如圖7。
@@09A04006.GIF;圖7制作立體畫的程序主結(jié)構(gòu)圖在以上結(jié)構(gòu)圖中,關(guān)鍵是如何建立“等@@像素鏈”。具體的處理如下。對于立體形體上的每一個(gè)點(diǎn),首先求出該點(diǎn)在“偏左圖”和“偏右圖”上的坐標(biāo)。以圖1中的棱錐頂點(diǎn)為例,實(shí)際上其X坐標(biāo)是在中心點(diǎn),但由于雙眼的位置并不在其正上方,頂點(diǎn)在“偏左圖”上向右位移,在“偏右圖”上向左位移,而且其位移值的大小顯然與其高度有關(guān),即該點(diǎn)坐標(biāo)越高位移值就越大。a,b,c等點(diǎn)也都有這些位移。在求出一個(gè)點(diǎn)在“偏左圖”和“偏右圖”上的坐標(biāo)后,再算出在合成圖(如圖6)上的對應(yīng)坐標(biāo)
,以建立“等像素”關(guān)系,如a=a''''。當(dāng)立體形體的一個(gè)水平剖面上的全部點(diǎn)經(jīng)過以上處理后,合成圖的各條“等像素鏈”關(guān)系也就自然形成了。
另外,由于有可能出現(xiàn)高點(diǎn)遮蓋低點(diǎn)的情況,“等像素鏈”的構(gòu)造應(yīng)該從低點(diǎn)到高點(diǎn)逐層進(jìn)行,高點(diǎn)的“等像素”關(guān)系將替代低點(diǎn)的“等像素”關(guān)系。這也是程序主結(jié)構(gòu)圖中“首先,對于沒有任何形體存在的背景平面構(gòu)造‘等像素鏈’”的原因。
下面給出了根據(jù)以上結(jié)構(gòu)圖用C語言編寫的源程序。程序中,每一個(gè)坐標(biāo)點(diǎn)對應(yīng)一個(gè)結(jié)構(gòu)型數(shù)據(jù),它包含“前像素”、“后像素”兩個(gè)指針?!扒跋袼亍敝羔樦赶蛟撟鴺?biāo)點(diǎn)作為“偏右圖”上的一點(diǎn),在“偏左圖”所對應(yīng)的點(diǎn)的坐標(biāo)?!昂笙袼亍敝羔樦赶蛟撟鴺?biāo)點(diǎn)作為“偏左圖”上的一點(diǎn),在“偏右圖”所對應(yīng)的點(diǎn)的坐標(biāo)。程序中,“立體形體水平剖面的高低坐標(biāo)數(shù)據(jù)”、“原始圖案素材”和輸出的“立體畫”的文件格式都是采用了Windows3.1的Pbrush產(chǎn)生的BMP圖形文件格式。圖幅大小要求都是640×400,用16種顏色方式。其中,立體形體上各點(diǎn)的高低坐標(biāo)用圖形文件中的顏色值表示,因此該圖形文件的圖形與帶顏色的等高線圖安全相同。通常情況下,在16色的BMP文件中顏色值從小到大的順序?yàn)?黑色、暗紅色、暗綠色、暗黃色、暗藍(lán)色、暗紫色、暗青色、暗灰色、灰色、明紅色、明綠色、明黃色、明藍(lán)色、明紫色、明青色、白色。本程序采用最簡單的“圖案充填”方案,即各條“鏈”上的像素點(diǎn)皆采用該“鏈”上的第一個(gè)像素的顏色。程序中的常數(shù)EYE-SPACE表示“偏左圖”和“偏右圖”之間的偏差,BO-DOT是表明“鏈”的首或尾的指針標(biāo)志。
該程序寄生在Windows3.1中的Pbrush軟件上。借助于它來構(gòu)筑立體形體(即立體形體水平剖面高低坐標(biāo)數(shù)據(jù)文件圖8),設(shè)計(jì)原始圖案(圖9)。程序運(yùn)行后,逐行輸入并處理以上兩個(gè)文件中的圖形,然后輸出立體畫結(jié)果文件(圖10)。最后,用Pbrush來觀賞立體畫result.bmp。當(dāng)然,要設(shè)計(jì)出令人賞心悅目的立體畫,必須在立體形體和圖案素材的選擇和搭配上做到天衣無縫,獨(dú)具匠心。
@@09A04007.GIF;圖8@@
@@09A04008.GIF;圖9@@
@@09A04009.GIF;圖10程序清單@@
/*--from1995.4.19--to1995.5.18----*/include<stdio.h>
#defineCOMPRESSION0
#defineSIZE-OF-BITMAPFILEHEADER14
#defineSIZE-OF-BITMAPINFOHEADER40
#defineSIZE-OF-RGBQUAD4
#definePIXEL-DATE-OFFSET14+40+4*16
/*SIZE-OF-BITMAPFILEHEADER+SIZE-OF-BITMAPINFOHEADER+BITS-PER-PIXEL
*NUM-COLOR*/
#defineNUM-COLOR16
#defineNUM-LINE400
#defineWIDTH640
#defineBITS-PER-PIXEL4
#definePIXEL-PER-BYTE2/*8/BITS-PER-PIXEL*/
#defineBYTE-PER-LINE320/*((WIDTH*BITS-PER-PIXEL-1)/32+1)*4*/
#defineNO-DOTWIDTH+1
#defineEYE-SPACE128
struct{
unsigndecharcolor;
unsignedintpri-x;
unsignedintnxt-x;
}dot[WIDTH];
main()
{
structtagBITMAPFILEHEADER{
unsignedcharbfType1,bfType2;/*alwaysequalto''''BM''''*/
unsignedlongintbfSize;/*sizeoffile*/
unsignedintbfReserved1,bfReserved2;/*settozero*/
unsigedlongintbfoffits;/*byteoffsetfromBITMAPFILEHEADERtobitmapp
ixel
datainthefile*/
}BITMAPFILEHEADER;
structtagBITMAPINFOHEADER{
unsignedlongintbiSize,/*sizeofBITMAPINFOHEADER*/
biWidth;/*widthinpixelsbiHeight;/*heightinpixels*/
unsignedintbiPlanes,/*always1*/
biBitCount;/*colorbitsperpixelmustbe1,4,8or24*/
unsignedlongintbiCompression,/*BI-RGB,BI-RLE8or4*/
biSizeImage,/*totalbytesinimage*/
biXPelsPerMeter,/*0,oropt,hres.*/
biYPelsPerMeter,/*0,oropt,hres.*/
biClrUsed,/*normally0,cansetalowerno.colorsthanbiBitCount*/
biClrImportant;/*normally0*/
}BITMAPINFOHEADER;
structtagRGBQUAD{
unsignedcharrgbBlue,/*blueintensity,0-255*/
rgbGreen,/*greenintensity,0-255*/
rgbRed,/*redintensity,0-255*/
rgbReserved;/*reserved,settoZero*/
}RGBQUAD[NUM-COLOR];
char*fn-layer="layer.bmp";
char*fn-org="origin.bmp";
char*fn-result="result.bmp";
FILE*flayer,*fOrigin,*fResult;
unsignedchartmp-byte1,tmp-byte2;
unsignedintline,i-byte,i-pixel,x;
unsignedintlayer;
intleft-x,right-x;tmp-x;
unsignedlongintcur-offset;
unsignedcharh[WIDTH],org-color[WIDTH];
puts("---WINTRICK---");
puts("---byLiJisong---");
if((fLayer=fopen(fn-layer,"rb"))!=NULL){
fread(&BITMAPFILEHEADER,SIZE-OF-BITMAPFILEHADER,1,fLayer);
fread(&BITMAPINFOHEADER,SIZE-OF-BITMAPINFOHEADER,1,fLayer);
if(BITMAPFILEHEADER.bfType1==''''B''''&&BITMAPFILEHEADER.bfType2==''''M''''
&&BITMAPINFOHEADER.biWidth==WIDTH&&BITMAPINFOHEADER.biHeight==NUM-
LINE
&&BITMAPINFOHEADER.biBitCount==BITS-PER-PIXEL
&&BITMAPINFOHEADER.biCompression==COMPRESSION)
fread(RGBQUAD,SIZE-OF-RGBQUAD,NUM-COLOR,fLayer);
else{
fclose(fLayer);
printf("File%sisnotfitforthisprogram!\n",fn-layer);
getch();
exit(1);
}
}
else{
printf("File%sdoesnotexist!\n",fn-layer);
getch();
exit(2);
}
if((fOrigin=fopen(fn-org,"rb"))!=NULL){
fread(&BITMAPFILEHEADER,SIZE-OF-BITMAult);
}
參考文獻(xiàn)
孫志輝、王萃寒、王茜.實(shí)用Windows3.1詳解.北京:電子工業(yè)出版社,1994.