第20課:蒙板(參照nehe)
這次教程中,我們教介紹opengl的蒙板技術。到目前為止,我們已經學會如何使用alpha混合,把乙個透明物體渲染到螢幕上了,但有時使用它看起來並不是那麼的復合我們的心意。使用蒙板技術,將會使影象按照我們設定的蒙板位置精確地繪製。
直到現在,我們在把影象載入到螢幕上時都沒有檫除背景色,因為這樣簡單高效,但是效果並不總是很好。大部分情況下,把紋理混合到螢幕,紋理不是太少就是太多。當我們使用精靈圖時,我們不希望背景從精靈的縫隙中透出光來;但在顯示文字時,我們又希望文字的間隙可以顯示背景色。
基於上述原因,我們需要使用「掩模」。使用「掩膜」需要兩個步驟,首先我們在場景上放置黑白相間的紋理,白色代表透明部分,黑色代表不透明部分。接著我們使用一種特殊的混合方式,只有在黑色部分上的紋理才會顯示在場景中。
程式執行時效果如下:
下面進入教程:
我們這次將在第06課**的基礎上修改**,總體上並不會太難,希望大家能理解蒙板技術,這技術真的很好用。首先開啟myglwidget.h檔案,將類宣告更改如下:
#ifndef myglwidget_h
#define myglwidget_h
#include #include class myglwidget : public qglwidget
;#endif // myglwidget_h
我們增加了兩個布林變數m_masking和m_scene來控制是否開啟「
掩模」以及繪製哪乙個場景。然後我們增加乙個控制圖形滾動旋轉的變數m_rot,當然要去掉之前控制旋轉的變數。最後把m_filename和m_texture變成長度為5的陣列,因為我們需要載入5個紋理。
接下來,我們開啟myglwidget.cpp,在建構函式中對新增變數進行初始化,比較簡單,大家參照注釋理解,不多作解釋,具體**如下:
myglwidget::myglwidget(qwidget *parent) :
qglwidget(parent)
然後,我們略微修改下initializegl()函式,就是載入5個位圖並轉換成紋理,不多解釋了,具體**如下:
void myglwidget::initializegl() //此處開始對opengl進行所以設定
glenable(gl_texture_2d); //啟用紋理對映
glclearcolor(0.0f, 0.0f, 0.0f, 0.0f); //黑色背景
glshademodel(gl_smooth); //啟用陰影平滑
glcleardepth(1.0); //設定深度快取}
繼續,我們要進入最有趣的paintgl()函式,當然這也是重點,具體**如下:
void myglwidget::paintgl() //從這裡開始進行所以的繪製
if (m_scene)
glblendfunc(gl_one, gl_one); //把紋理2複製到螢幕上
glbindtexture(gl_texture_2d, m_texture[4]); //選擇第二個紋理
glbegin(gl_quads); //繪製四邊形
gltexcoord2f(0.0f, 0.0f);
glvertex3f(-1.1f, -1.1f, 0.0f);
gltexcoord2f(1.0f, 0.0f);
glvertex3f(1.1f, -1.1f, 0.0f);
gltexcoord2f(1.0f, 1.0f);
glvertex3f(1.1f, 1.1f, 0.0f);
gltexcoord2f(0.0f, 1.0f);
glvertex3f(-1.1f, 1.1f, 0.0f);
glend();
}else
glblendfunc(gl_one, gl_one); //把紋理1複製到螢幕
glbindtexture(gl_texture_2d, m_texture[2]); //選擇第乙個紋理
glbegin(gl_quads); //繪製四邊形
gltexcoord2f(m_rot+0.0f, 0.0f);
glvertex3f(-1.1f, -1.1f, 0.0f);
gltexcoord2f(m_rot+4.0f, 0.0f);
glvertex3f(1.1f, -1.1f, 0.0f);
gltexcoord2f(m_rot+4.0f, 4.0f);
glvertex3f(1.1f, 1.1f, 0.0f);
gltexcoord2f(m_rot+0.0f, 4.0f);
glvertex3f(-1.1f, 1.1f, 0.0f);
glend();
}glenable(gl_depth_test); //啟用深度測試
gldisable(gl_blend); //禁用混合
m_rot += 0.002f; //增加調整紋理滾動旋轉變數
if (m_rot > 1.0f)
}
函式一開始,清除背景色,重置矩陣,把物體移入螢幕2.0單位。接著我們選擇logo紋理,繪製紋理四邊形,注意到我們呼叫gltexcoord選擇紋理座標時,有的數是大於1.0的,這時候opengl預設擷取小數部分進行處理,這樣就可以得到無縫的迴圈紋理(具體效果大家看上面的圖或自己執行程式時再看)。然後我們啟用混合並禁用深度測試。
接著我們需要根據m_masking的值設定是否使用「掩模」,如果是,我們需要設定相應的混合因子。乙個「掩模」只是一幅繪製到螢幕的紋理,但只有黑色和白色,白色的部分代表透明,黑色的部分代表不透明。我們設定的混合因子gl_dst_color、gl_zero使得任何紋理(opengl並不知道這是不是「掩模」)黑色的部分會變為黑色,白色的部分會保持原來的顏色,就是變成透明,透過了原來的顏色。
然後我們檢查是繪製哪乙個場景(圖層),true繪製第二層,false繪製第一層。true時先開始繪製第二層,為了不使得它看起來太大,我們把它移入螢幕1.0單位,並把它按m_rot的值繞z軸旋轉。接著我們檢查m_marking的值,如果為true,我們就把「掩模」繪製到螢幕上,當我們完成這個操作時,將會看到乙個鏤空的紋理出現在螢幕上。然後我們變換混合因子gl_one、gl_one,這次我們告訴opengl把任何黑色部分對應的畫素複製到螢幕,這樣看起來紋理就像被鏤空一樣貼在螢幕上。要注意的是,我在變換了混合因子後才選擇的紋理。如果我們沒有使用 「掩模」,我們的影象將與螢幕顏色融合。
下面我繪製第一層與第二層的繪製基本相同,不多解釋了。最後我們啟用深度測試,禁用混合,然後增加m_rot變數,如果大於1.0,把它的值減去1.0。
最後我們修改一下鍵盤控制函式,就是加上了空格和m鍵作為切換鍵,很簡單不多解釋了,具體**如下:
void myglwidget::keypressevent(qkeyevent *event)
else
updategl();
break;
case qt::key_escape: //esc為退出鍵
close();
break;
case qt::key_space: //空格為場景(圖層)的切換鍵
m_scene = !m_scene;
break;
case qt::key_m: //m為是否"掩膜"的切換鍵
m_masking = !m_masking;
break;}}
現在就可以執行程式檢視效果了!
一點內容的補充:上面我們提到當呼叫gltexcoord選擇紋理座標時,如果大於1.0,opengl預設擷取小數部分進行處理。其實這只是opengl預設的處理模式:gl_repeat。對於紋理座標大於1.0,opengl有以下幾種處理模式:
gl_clamp - 擷取
gl_repeat - 重複(opengl預設的模式)
gl_mirrored_repeat - 映象重複
gl_clamp_to_edge - 忽略邊框擷取
gl_clamp_to_border - 帶邊框的擷取
我們可以利用gltexparameter函式來進行模式的轉換,如:x方向的轉換為gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl_clamp),變換模式只需更改第三個引數。而第二引數代表方向,gl_texture_wrap_s代表x方向,gl_texture_wrap_t代表y方向,gl_texture_wrap_r代表z方向。
WPF蒙板彈窗
先看一下效果。原理其實很簡單,啟動專案的時候,先在主窗體最根部的grid 新增乙個控制項,設定好顏色和透明度,隱藏 在這裡我用的stack panel,具體什麼都沒影響。黑色背景0.4透明度剛好呈現蒙板效果。需要蒙板彈窗的時候,呼叫方法 public static void showdialog w...
通過蒙板測試在NGUI中簡單實現蒙板效果
經常會有需要鏤空一張貼圖的時候,比如新手引導的介面。使用自定義ngui shander可以簡單的實現。但是效果還是比較初級 步驟一 建立兩個uitexture,分別為黑色底圖maskbg,蒙板mask。mask要層級低於maskbg。步驟二 準備兩個shader unlit transparent ...
Qt OpenGL教程 29 Blitter函式
第29課 blitter函式 參照nehe 這次教程中,我們將介紹類似於directdraw的blit 其實blit函式在許多繪相簿都有 我們將用 自己來實現它。它的作用非常簡單,就是把一塊紋理的貼到另一塊紋理上。想想,有了這個函式,我們就可以自由拼接紋理了,是不是很棒?這一課中,我們不但會實現bl...