opengl 反走樣 混合 多重採樣 blend multisample

來源:互聯網
上載者:User

標籤:blog   color   os   使用   io   strong   ar   for   資料   

1. 反走樣

        在點陣圖形顯示器上繪製非水平且非垂直的直線或多邊形邊界時,或多或少會呈現鋸齒狀或台階狀外觀。這是因為直線、多邊形、色彩邊界等是連續的,而光柵則是由離散的點組成,在光柵顯示裝置上表現直線、多邊形等,必須在離散位置採樣。由於採樣不充分重建後造成的資訊失真,就叫走樣(aliasing)。而用於減少或消除這種效果的技術,就稱為反走樣(antialiasing)。

2. OpenGL反走樣的實現

OpengL中的反走樣採用的是融合的技術,來實現點、線和圖形的邊沿以及霧和顏色和紋理的插值運算。OpenGL實現反走樣需要滿足兩個條件,一是啟用混合,二是啟用針對幾何圖元的反走樣處理。3. OpenGL混合Blend
混合是什麼呢?混合就是把兩種顏色混在一起。具體一點,就是把某一像素位置原來的顏色和將要畫上去的顏色,通過某種方式混在一起,從而實現特殊的效果。
假設我們需要繪製這樣一個情境:透過紅色的玻璃去看綠色的物體,那麼可以先繪製綠色的物體,再繪製紅色玻璃。在繪製紅色玻璃的時候,利用“混合”功能,把將要繪製上去的紅色和原來的綠色進行混合,於是得到一種新的顏色,看上去就好像玻璃是半透明的。
要使用OpenGL的混合功能,只需要調用:glEnable(GL_BLEND);即可。
要關閉OpenGL的混合功能,只需要調用:glDisable(GL_BLEND);即可。glBlendFunc(源因子, 目標因子)完成混合方法的定義。舉例來說:
如果設定了glBlendFunc(GL_ONE, GL_ZERO);,則表示完全使用源顏色,完全不使用目標顏色,因此畫面效果和不使用混合的時候一致(當然效率可能會低一點點)。如果沒有設定源因子和目標因子,則預設情況就是這樣的設定。
如果設定了glBlendFunc(GL_ZERO, GL_ONE);,則表示完全不使用源顏色,因此無論你想畫什麼,最後都不會被畫上去了。(但這並不是說這樣設定就沒有用,有些時候可能有特殊用途)
如果設定了glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,則表示源顏色乘以自身的alpha 值,目標顏色乘以1.0減去源顏色的alpha值,這樣一來,源顏色的alpha值越大,則產生的新顏色中源顏色所佔比例就越大,而目標顏色所佔比例則減小。這種情況下,我們可以簡單的將源顏色的alpha值理解為“不透明度”。這也是混合時最常用的方式。
如果設定了glBlendFunc(GL_ONE, GL_ONE);,則表示完全使用源顏色和目標顏色,最終的顏色實際上就是兩種顏色的簡單相加。例如紅色(1, 0, 0)和綠色(0, 1, 0)相加得到(1, 1, 0),結果為黃色。
注意:
所謂源顏色和目標顏色,是跟繪製的順序有關的。假如先繪製了一個紅色的物體,再在其上繪製綠色的物體。則綠色是源顏色,紅色是目標顏色。如果順序反過來,則紅色就是源顏色,綠色才是目標顏色。在繪製時,應該注意順序,使得繪製的源顏色與設定的源因子對應,目標顏色與設定的目標因子對應。不要被混亂的順序搞暈了。 三維混合的注意事項
 問題
:也許你迫不及待的想要繪製一個三維的帶有半透明物體的情境了。但是現在恐怕還不行,還有一點是在進行三維情境的混合時必須注意的,那就是深度緩衝。深度緩衝是這樣一段資料,它記錄了每一個像素距離觀察者有多近。在啟用深度緩衝測試的情況下,如果將要繪製的像素比原來的像素更近,則像素將被繪製。否則,像素就會被忽略掉,不進行繪製。這在繪製不透明的物體時非常有用——不管是先繪製近的物體再繪製遠的物體,還是先繪製遠的物體再繪製近的物體,或者乾脆以混亂的順序進行繪製,最後的顯示結果總是近的物體遮住遠的物體。然而在你需要實現半透明效果時,發現一切都不是那麼美好了。如果你繪製了一個近距離的半透明物體,則它在深度緩衝區內保留了一些資訊,使得遠處的物體將無法再被繪製出來。雖然半透明的物體仍然半透明,但透過它看到的卻不是正確的內容了。方案:要解決以上問題,需要在繪製半透明物體時將深度緩衝區設定為唯讀,這樣一來,雖然半透明物體被繪製上去了,深度緩衝區還保持在原來的狀態。如果再有一個物體出現在半透明物體之後,在不透明物體之前,則它也可以被繪製(因為此時深度緩衝區中記錄的是那個不透明物體的深度)。以後再要繪製不透明物體時,只需要再將深度緩衝區設定為可讀可寫的形式即可。嗯?你問我怎麼繪製一個一部分半透明一部分不透明的物體?這個好辦,只需要把物體分為兩個部分,一部分全是半透明 的,一部分全是不透明的,分別繪製就可以了。
注意: 即使使用了以上技巧,我們仍然不能隨心所欲的按照混亂順序來進行繪製。必須是先繪製不透明的物體,然後繪製透明的物體。否則,假設背景為藍色,近處一塊紅色玻璃,中間一個綠色物體。如果先繪製紅色半透明玻璃的話,它先和藍色背景進行混合,則以後繪製中間 的綠色物體時,想單獨與紅色玻璃混合已經不能實現了。總結:繪製順序就是首先繪製所有不透明的物體。如果兩個物體都是不透明的,則誰先誰後都沒有關係。然後,將深度緩衝區設定為唯讀。接下來,繪製所有半透明的物體。如果兩個物體都是半透明的,則誰先誰後只需要根據自己的意願(注意了,先繪製的將成為“目標顏色”,後繪製的將成為“源顏色”,所以繪製的順序將會對結果造成一些影響)。最後,將深度緩衝區設定為可讀可寫形式。調用glDepthMask(GL_FALSE);可將深度緩衝區設定為唯讀形式。調用glDepthMask(GL_TRUE);可將深度緩衝區設定為可讀可寫形式。4.OpenGL的反走樣函數

void glHint(GLenum target,GLenum hint); 

         hint定義了反走樣的方法
          GL_FASTEST 給出最有效選擇 
          GL_NICEST 給出最高品質的選擇 
          GL_DONT_CARE 沒有選擇

          target定義反走樣的對象

 

         GL_POINT_SMOOTH_HINT 指定點

            GL_LINE_SMOOTH_HINT 線
            GL_POLYGON_SMOOTH_HINT 多邊形的採樣品質 
            GL_FOG_HINT 指出霧化計算是按每個象素進行(GL_NICEST),還是按每個頂點進行(GL_FASTEST) 
            GL_PERSPECTIVE_CORRECTION_HINT 指定顏色紋理插值的品質 
            其中GL_PERSPECTIVE_CORRECTION_HINT用以糾正單純線性插值帶來的觀察錯誤。

5.OpenGL的反走樣執行個體1---點的反走樣#include<windows.h>#include<gl/glut.h>#include<math.h>#define x_Screen 800#define y_Screen    600#define little 50#define middle 20#define large   8void myBackground(){glClearColor(0.0,0.0,0.0,1.0);glColor3f(1.0,1.0,1.0);} void myDisplay(){glEnable ( GL_DEPTH_TEST );//如果沒有消除鋸齒,則點為方形的。如果我們啟動消除鋸齒設定,則點是一個圓點。glEnable(GL_POINT_SMOOTH);glEnable(GL_LINE_SMOOTH);glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Make round points, not square pointsglHint(GL_LINE_SMOOTH_HINT, GL_NICEST);  // Antialias the linesglEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);int i;glBegin(GL_POINTS);for(i=0;i<little;i++)glVertex2f(50.0+rand()%x_Screen,50.0+rand()%y_Screen);glEnd();glPointSize(2);glBegin(GL_POINTS);for(i=0;i<middle;i++)glVertex2f(50.0+rand()%x_Screen,50.0+rand()%y_Screen);glEnd(); glPointSize(8);glBegin(GL_POINTS);for(i=0;i<large;i++)glVertex2f(50.0+rand()%x_Screen,50.0+rand()%y_Screen);glEnd(); glBegin(GL_POLYGON);for(i=0;i<64;i++)glVertex2f(600+50.0*cos((float)i/10) ,500+50.0*sin((float)i/10) );glEnd();glLineWidth(3);glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);glEnable(GL_BLEND);glEnable(GL_LINE_SMOOTH);glBegin(GL_LINE_STRIP);for(i=0;i<19;i++){glVertex2f(rand()%10+i*70,rand()%50+50.0+(i%2)*80); }glEnd(); glutSwapBuffers();}void myChange(int w,int h){ glViewport(0,0,w,h);glMatrixMode(GL_PROJECTION);glLoadIdentity(); gluOrtho2D(0.0,x_Screen,0.0,y_Screen);glMatrixMode(GL_MODELVIEW);glLoadIdentity();}  void main(){glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);glutInitWindowSize(x_Screen,y_Screen);glutCreateWindow("Star");glutDisplayFunc(myDisplay);glutReshapeFunc(myChange);myBackground();glutMainLoop(); }6.OpenGL的反走樣執行個體2---線的反走樣#include <GL/glut.h>#include <stdio.h> static float rotAngle = 0.; void init(void){GLfloat values[2];glGetFloatv(GL_LINE_WIDTH_GRANULARITY, values);printf("GL_LINE_WIDTH_GRANULARITY value is %3.1f\n", values[0]); glGetFloatv(GL_LINE_WIDTH_RANGE, values);printf("GL_LINE_WIDTH_RANGE values are %3.1f %3.1f\n", values[0], values[1]); glEnable(GL_LINE_SMOOTH);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); glLineWidth(1.5); glClearColor(0.0, 0.0, 0.0, 0.0);} void display(void){   glClear(GL_COLOR_BUFFER_BIT);    glColor3f(0.0, 1.0, 0.0);   glPushMatrix();   glRotatef(-rotAngle, 0.0, 0.0, 0.1);   glBegin(GL_LINES);   glVertex2f(-0.5, 0.5);   glVertex2f(0.5, -0.5);   glEnd();   glPopMatrix();      glColor3f(0.0, 0.0, 1.0);   glPushMatrix();   glRotatef(rotAngle, 0.0, 0.0, 0.1);   glBegin(GL_LINES);   glVertex2f(0.5, 0.5);   glVertex2f(-0.5, -0.5);   glEnd();   glPopMatrix();      glFlush();} void reshape(int w, int h){glViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();if (w <= h) gluOrtho2D (-1.0, 1.0, -1.0*(GLfloat)h/(GLfloat)w, 1.0*(GLfloat)h/(GLfloat)w);else gluOrtho2D (-1.0*(GLfloat)w/(GLfloat)h, 1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();} void keyboard(unsigned char key, int x, int y){switch (key) {case ‘r‘: case ‘R‘:rotAngle += 20.;if (rotAngle >= 360.0) rotAngle = 0.0;glutPostRedisplay(); break;case 27:exit(0);break;default:break;}} int main(int argc, char** argv){glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowSize(200, 200);glutCreateWindow(argv[0]);init();glutReshapeFunc(reshape);glutKeyboardFunc(keyboard);glutDisplayFunc(display);glutMainLoop();return 0;}

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

1.       使用顏色混合來消除一些鋸齒, 主要針對點和線以及不相互重疊的多邊形的反鋸齒。

反鋸齒設定代碼如下:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_BLEND);

glEnable(GL_POINT_SMOOTH);

glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);

glEnable(GL_LINE_SMOOTH);

glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

glEnable(GL_POLYGON_SMOOTH);

glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

取消反鋸齒代碼如下:

glDisable(GL_BLEND);

glDisable(GL_LINE_SMOOTH);

glDisable(GL_POINT_SMOOTH);

glDisable(GL_POLYGON_SMOOTH);

2.       多重採樣(Multisample)

並不是所有的平台都支援通過顏色混合來消除多邊形鋸齒,此外,多邊形混合還有順序的問題,使用起來不方便。OpenGL引入了多重採樣來解決多邊形鋸齒的問題,並增加了一個包含顏色、嘗試以及模組緩衝值的幀緩衝。開啟多重採樣功能的代碼如下:

//申請一個採用了雙重緩衝,包含顏色,深度的幀緩衝和多重採樣。

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE);

   glEnable(GL_MULTISAMPLE);//開啟多重緩衝

   glDisable(GL_MULTISAMPLE);//關閉多重緩衝

  

   註: 多重採樣和混合不能同時開啟, 這兩種方法只能互斥使用。即使用任何一個方法前需要禁用另一個方法。

opengl 反走樣 混合 多重採樣 blend multisample

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.