閱讀403 返回首頁    go 微軟 go windows


visual C++遊戲繪圖之透明效果製作原理

作者:晉文格墨    郵箱: chairperson@sina.cn   


透明效果


由於所有的圖文件都是以矩形來儲存的,我們也許會需要把一張易拉罐圖片貼到窗口的背景圖上,而這種情況下如果直接進行貼圖,結果如下圖:


這似乎不是我們想要的結果。


為了得到透明效果,我們需要運用到BitBlt()貼圖函數以及其參數Raster的值來將圖片中不必要的部分去掉(又稱去背),使得圖中的主題可以與背景完美融合。


製作透明效果有很多種方法,但是基本上都是利用貼圖時不同的Raster運算,通過轉換而產生相同的透明效果。在這裏先來介紹一種透明運算的方法。


我們以圖中的易拉罐為例子,首先準備一張位圖,如下圖。


圖中的左邊的圖是要去背並貼到背景上的前景圖。右邊的黑白圖稱為“屏蔽圖”,在透明的過程中會用到它。要把去背的位圖與屏蔽圖合並成同一張圖,透明的時候再按照需要來進行裁切。可以把它分成兩張圖,但是這樣程序必須運行兩次圖文件加載的操作。


有了屏蔽圖就可以利用貼圖函數來產生透明效果了,所需的貼圖步驟如下:

<1>將屏蔽圖與背景圖做"AND"運算,Raster值為SRCAND,貼到目的地DC中。

<2>將前景圖與背景圖做"OR"運算,Raster值為SRCPAINT,貼到目的地DC中。


為什麼經過上麵兩個操作就能產生透明的效果呢?看下圖就理解了:





下麵具體說明上麵兩個步驟所產生的圖點色彩的變化。


1.屏蔽圖與背景圖做"AND"運算

<1>屏蔽圖中的黑色部分與背景圖做"AND"運算:


<2>屏蔽圖中的白色部分與背景圖做"AND"運算:


進過這一運算所產生的結果如下圖




2.前景圖與背景圖做"OR"運算


<1>前景圖中的彩色部分與圖第一步得到的“黑色易拉罐”圖做"OR"運算:


<2>前景圖中的黑色部分與第一步得到的“黑色易拉罐”圖做"OR"運算:


經過這一運算後所顯示的畫麵就是所需的透明圖了,如下圖所示:




下麵我們來看看實現上述透明貼圖效果的源代碼


  1. #include "stdafx.h"  
  2. //全局變量聲明  
  3. HINSTANCE hInst;  
  4. HBITMAP bg,sprite;        //聲明兩個位圖對象,分別存儲背景圖與前景易拉罐  
  5. HDC  mdc;       //聲明一個內存DC"mdc",用來暫存位圖  
  6. //全局函數聲明  
  7. ATOM     MyRegisterClass(HINSTANCE hInstance);  
  8. BOOL     InitInstance(HINSTANCEint);  
  9. LRESULT CALLBACK    WndProc(HWNDUINTWPARAMLPARAM);  
  10. void     MyPaint(HDC hdc);  
  11. ////****Winmain函數,程序入口點函數**************************************  
  12. int APIENTRY WinMain(HINSTANCE hInstance,  
  13.                      HINSTANCE hPrevInstance,  
  14.                      LPSTR     lpCmdLine,  
  15.                      int       nCmdShow)  
  16. {  
  17. MSG msg;  
  18. MyRegisterClass(hInstance);  
  19. if (!InitInstance (hInstance, nCmdShow))   
  20. {  
  21. return FALSE;  
  22. }  
  23. //消息循環  
  24. while (GetMessage(&msg, NULL, 0, 0))   
  25. {  
  26. TranslateMessage(&msg);  
  27. DispatchMessage(&msg);  
  28. }  
  29. return msg.wParam;  
  30. }  
  31. //****設計一個窗口類,類似填空題,使用窗口結構體*************************  
  32. ATOM MyRegisterClass(HINSTANCE hInstance)  
  33. {  
  34. WNDCLASSEX wcex;  
  35. wcex.cbSize = sizeof(WNDCLASSEX);   
  36. wcex.style   = CS_HREDRAW | CS_VREDRAW;  
  37. wcex.lpfnWndProc    = (WNDPROC)WndProc;  
  38. wcex.cbClsExtra  = 0;  
  39. wcex.cbWndExtra  = 0;  
  40. wcex.hInstance   = hInstance;  
  41. wcex.hIcon   = NULL;  
  42. wcex.hCursor     = NULL;  
  43. wcex.hCursor     = LoadCursor(NULL, IDC_ARROW);  
  44. wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  
  45. wcex.lpszMenuName   = NULL;  
  46. wcex.lpszClassName  = "canvas";  
  47. wcex.hIconSm     = NULL;  
  48. return RegisterClassEx(&wcex);  
  49. }  
  50. //****初始化函數*************************************  
  51. // 1.建立與窗口DC兼容的內存DC  
  52. // 2.從文件加載背景圖與恐龍圖  
  53. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  
  54. {  
  55. HWND hWnd;  
  56. HDC hdc;  
  57. hInst = hInstance;  
  58. hWnd = CreateWindow("canvas""繪圖窗口" , WS_OVERLAPPEDWINDOW,  
  59. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);  
  60. if (!hWnd)  
  61. {  
  62. return FALSE;  
  63. }  
  64. MoveWindow(hWnd,10,10,600,450,true);  
  65. ShowWindow(hWnd, nCmdShow);  
  66. UpdateWindow(hWnd);  
  67. hdc = GetDC(hWnd);                     //獲得窗口DC  
  68. mdc = CreateCompatibleDC(hdc);           //創建與窗口兼容的內存DC(mdc)  
  69. bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,600,450,LR_LOADFROMFILE);   
  70. //J加載背景圖到bg中  
  71. sprite = (HBITMAP)LoadImage(NULL,"sprite.bmp",IMAGE_BITMAP,170,99,LR_LOADFROMFILE);   
  72. //加載易拉罐圖到sprite中  
  73. MyPaint(hdc);  
  74. ReleaseDC(hWnd,hdc);  
  75. return TRUE;  
  76. }  
  77. //****自定義繪圖函數*********************************  
  78. //透明貼圖  
  79. void MyPaint(HDC hdc)  
  80. {  
  81. SelectObject(mdc,bg);  
  82. BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);    //先將背景圖貼到顯示窗口中  
  83. SelectObject(mdc,sprite);                      //選用易拉罐圖到"mdc"中  
  84. BitBlt(hdc,50,50,225,225,mdc,225,0,SRCAND);//進行製作貼圖的第一步驟,即將屏蔽圖與背景圖做"AND"運算,屏蔽圖在整張易拉罐圖中,最左上角起始位置點得坐標為(225,0),BitBlt()函數中最後一個Raster參數值設置為SRCAND。  
  85. BitBlt(hdc,50,50,225,225,mdc,0,0,SRCPAINT);//進行製作透明貼圖的第二步驟,即將前景圖與背景圖做"OR"運算,前景圖在整張易拉罐圖中,最左上角起始位置的坐標為(0,0),BitBlt()函數最後一個參數值設置為SRCPAINT。  
  86. }  
  87. //****消息處理函數**********************************  
  88. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  89. {  
  90. PAINTSTRUCT ps;  
  91. HDC hdc;  
  92. switch (message)  
  93. {  
  94. case WM_PAINT:   //窗口重繪消息  
  95. hdc = BeginPaint(hWnd, &ps);  
  96. MyPaint(hdc);  
  97. EndPaint(hWnd, &ps);  
  98. break;  
  99. case WM_DESTROY:     //窗口結束消息  
  100. DeleteDC(mdc);  
  101. DeleteObject(bg);  
  102. DeleteObject(sprite);  
  103. PostQuitMessage(0);  
  104. break;  
  105. default:     //其他消息  
  106. return DefWindowProc(hWnd, message, wParam, lParam);  
  107.    }  
  108.    return 0;  
  109. }  



最後程序的運行結果為:


通過BitBlt()貼圖函數及Raster運算值的設定,很簡單地就做出了想要的透明效果,這種方法在設計2D遊戲的一些畫麵內容時使用相當頻繁。




最後更新:2017-04-03 14:54:20

  上一篇:go proxy silbing 原理分析
  下一篇:go 技術人員談管理之成本管理案例論文