OPenGL模板缓冲区示例程序
模板測試是把像素存儲在模板緩沖區的值與一個參考值進行比較。根據測試的結果,對模板緩沖區中得這個值進行相應的修改。
Note:模板測試只有在存在模板緩沖區的情況下才會執行,如果不存在模板緩沖區,模板測試能夠通過。
模板測試最常用的用途就是屏蔽掉屏幕中的一些不規則區域,避免在這些區域中進行繪圖。
模板測試過程:
(1)如果使用glut工具包(或者freeglut),要這樣進行指定:
[cpp]?view plaincopy
[cpp]?view plaincopy
[cpp]?view plaincopy
GL_NEVER,?
GL_LESS,?
GL_LEQUAL,?
GL_GREATER,?
GL_GEQUAL,?
GL_EQUAL,?
GL_NOTEQUAL,?
and GL_ALWAYS.
ref指定參考值。
mask指定掩碼,只在掩碼為1的位上進行比較。
OpenGL2.0新增加了glStencilFuncSeparate函數,允許對多邊形的正面和背面分別指定模板函數參數。
[cpp]?view plaincopy
[cpp]?view plaincopy
該函數指定了三種情況下“模板值”該如何變化。第一個參數表示模板測試未通過時該如何變化;第二個參數表示模板測試通過,但深度測試未通過時該如何變化;第三個參數表示模板測試和深度測試或者未執行深度測試均通過時該如何變化。(如果沒有啟用模板測試,則認為模板測試總是通過;如果沒有啟用深度測試,則認為深度測試總是通過)
變化可以是:
GL_KEEP(不改變,這也是默認值),
GL_ZERO(回零),
GL_REPLACE(使用測試條件中的設定值來代替當前模板值),
GL_INCR(增加1,但如果已經是最大值,則保持不變),
GL_INCR_WRAP(增加1,但如果已經是最大值,則從零重新開始),
GL_DECR(減少1,但如果已經是零,則保持不變),
GL_DECR_WRAP(減少1,但如果已經是零,則重新設置為最大值),
GL_INVERT(按位取反)。
OpenGL2.0新增加了glStencilOpSeparate函數,允許對多邊形的正面和背面分別指定獨立的模板測試。
接下來的繪制操作就會影響所繪制區域的像素在模板緩沖中的值。
(6)模板查詢
可以用glGetInteger函數獲取與模板相關的參數值:
[cpp]?view plaincopy
模板測試實例:
示例程序使用了一個螺紋線模板去填充一個矩形框。可以單擊鼠標右鍵彈出菜單選擇填充的形式,也可以按鍵盤的UP,DOWN,LEFT,RIGHT按鍵旋轉坐標系,可以發現模板測試與glPolygonStipple不一樣,當坐標系旋轉一定角度后,填充的模板也會跟著旋轉。
要查詢模板測試是否啟用:
[cpp] view plain copy
glIsEnabled(GL_STENCIL_TEST); ?
[cpp]?view plaincopy
模板測試實例:
示例程序使用了一個螺紋線模板去填充一個矩形框。可以單擊鼠標右鍵彈出菜單選擇填充的形式,也可以按鍵盤的UP,DOWN,LEFT,RIGHT按鍵旋轉坐標系,可以發現模板測試與glPolygonStipple不一樣,當坐標系旋轉一定角度后,填充的模板也會跟著旋轉。
[cpp]?view plaincopy
[cpp]?view plaincopy
// GlutStencilDemo.cpp : 定義控制臺應用程序的入口點。
//
#include "stdafx.h"
#include <gl/glut.h>
#include <math.h>
//圓周率宏
#define GL_PI 3.1415f
//獲取屏幕的寬度
GLint SCREEN_WIDTH=0;
GLint SCREEN_HEIGHT=0;
//設置程序的窗口大小
GLint windowWidth=400;
GLint windowHeight=300;
//繞x軸旋轉角度
GLfloat xRotAngle=0.0f;
//繞y軸旋轉角度
GLfloat yRotAngle=0.0f;
//受支持的點大小范圍
GLfloat sizes[2];
//受支持的點大小增量
GLfloat step;
GLint iMode=0;
//菜單回調函數
void processMenu(int value){
switch(value){
case 1:
iMode=0;
break;
case 2:
iMode=1;
break;
}
//重新繪制
glutPostRedisplay();
}
//顯示回調函數
void renderScreen(void){
//將窗口顏色清理為黑色
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//將模板緩沖區值全部清理為1
glClearStencil(1);
//使能模板緩沖區
glEnable(GL_STENCIL_TEST);
? ? //把整個窗口清理為當前清理顏色:黑色。清除深度緩沖區、模板緩沖區
? ? glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
? ? //將當前Matrix狀態入棧
? ? glPushMatrix();
? ? //坐標系繞x軸旋轉xRotAngle
? ? glRotatef(xRotAngle,1.0f,0.0f,0.0f);
? ? //坐標系繞y軸旋轉yRotAngle
? ? glRotatef(yRotAngle,0.0f,1.0f,0.0f);
//進行平滑處理
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH,GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH,GL_NICEST);
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH,GL_NICEST);
//第一次模板不繪制圖形,沒有通過模板測試的像素對應模板緩沖區的模板值加1,這樣繪制螺旋線的地方模板緩沖區值變為了0x2,沒有繪制螺旋線的地方模板緩沖區值還為原來的值0x1
? ? glStencilFunc(GL_NEVER, 0x0, 0x0);
? ? glStencilOp(GL_INCR, GL_INCR, GL_INCR);
? ? glColor3f(1.0f, 1.0f, 1.0f);
? ? glBegin(GL_LINE_STRIP);
GLdouble dAngle = 0;
GLdouble dRadius = 0.1;
//繪制螺旋線,但是不顯示出來,僅用來修改模板緩沖區的模板值
? ? ? ? for(dAngle = 0; dAngle < 400.0; dAngle += 0.1)
? ? ? ? {
? ? ? ? ? ? glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle));
? ? ? ? ? ? dRadius *= 1.002;
? ? ? ? }
? ? glEnd();
? ? ? ? ? ??
? ? if(1==iMode)
glStencilFunc(GL_EQUAL, 0x1, 0x3);//參考值0x1==(模板值&0x3)則繪制,即繪制的是第一次使用模板沒有繪圖的部分.
else
glStencilFunc(GL_EQUAL, 0x2, 0x3);//參考值0x2==(模板值&0x3)則繪制,即繪制的是第一次使用模板繪圖的部分.
? ? glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
? ? glColor3f(0.0f, 1.0f, 1.0f);
? ? glRectf(-40.0f, -40.0f, 40.0f, 40.0f);//使用模板繪制矩形
? ? //恢復壓入棧的Matrix
? ? glPopMatrix();
? ? //交換兩個緩沖區的指針
? ? glutSwapBuffers();
}
//設置Redering State?
void setupRederingState(void){
? ? //設置清理顏色為黑色
? ? glClearColor(0.0f,0.0,0.0,1.0f);
? ? //設置繪畫顏色為綠色
? ? glColor3f(0.0f,1.0f,0.0f);
//使能深度測試
glEnable(GL_DEPTH_TEST);
//獲取受支持的點大小范圍
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
//獲取受支持的點大小增量
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);
printf("point size range:%f-%f\n",sizes[0],sizes[1]);
printf("point step:%f\n",step);
}
//窗口大小變化回調函數
void changSize(GLint w,GLint h){
? ? //橫寬比率
? ? GLfloat ratio;
? ? //設置坐標系為x(-100.0f,100.0f)、y(-100.0f,100.0f)、z(-100.0f,100.0f)
? ? GLfloat coordinatesize=100.0f;
? ? //窗口寬高為零直接返回
? ? if((w==0)||(h==0))
? ? ? ? return;
? ? //設置視口和窗口大小一致
? ? glViewport(0,0,w,h);
? ? //對投影矩陣應用隨后的矩陣操作
? ? glMatrixMode(GL_PROJECTION);
? ? //重置當前指定的矩陣為單位矩陣
? ? glLoadIdentity();
? ? ratio=(GLfloat)w/(GLfloat)h;
? ? //正交投影
? ? if(w<h)
? ? ? ? glOrtho(-coordinatesize,coordinatesize,-coordinatesize/ratio,coordinatesize/ratio,-coordinatesize,coordinatesize);
? ? else
? ? ? ? glOrtho(-coordinatesize*ratio,coordinatesize*ratio,-coordinatesize,coordinatesize,-coordinatesize,coordinatesize);
? ? //對模型視圖矩陣堆棧應用隨后的矩陣操作
? ? glMatrixMode(GL_MODELVIEW);
? ? //重置當前指定的矩陣為單位矩陣
? ? glLoadIdentity();
}
//按鍵輸入處理回調函數
void specialKey(int key,int x,int y){
? ? if(key==GLUT_KEY_UP){
? ? ? ? xRotAngle-=5.0f;
? ? }
? ? else if(key==GLUT_KEY_DOWN){
? ? ? ? xRotAngle+=5.0f;
? ? }
? ? else if(key==GLUT_KEY_LEFT){
? ? ? ? yRotAngle-=5.0f;
? ? }
? ? else if(key==GLUT_KEY_RIGHT){
? ? ? ? yRotAngle+=5.0f;
? ? }
? ? //重新繪制
? ? glutPostRedisplay();
}
int main(int argc, char* argv[])
{
//初始化glut?
? ? glutInit(&argc,argv);
? ? //使用雙緩沖區、深度緩沖區、模板緩沖區
? ? glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
? ? //獲取系統的寬像素
? ? SCREEN_WIDTH=glutGet(GLUT_SCREEN_WIDTH);
? ? //獲取系統的高像素
? ? SCREEN_HEIGHT=glutGet(GLUT_SCREEN_HEIGHT);
//創建窗口,窗口名字為OpenGL Stencil Demo
? ? glutCreateWindow("OpenGL Stencil Demo");
? ? //設置窗口大小
? ? glutReshapeWindow(windowWidth,windowHeight);
? ? //窗口居中顯示
? ? glutPositionWindow((SCREEN_WIDTH-windowWidth)/2,(SCREEN_HEIGHT-windowHeight)/2);
//創建菜單
glutCreateMenu(processMenu);
glutAddMenuEntry("Display Stencil",1);
glutAddMenuEntry("Don't dsplay Stencil",2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
? ? //窗口大小變化時的處理函數
? ? glutReshapeFunc(changSize);
? ? //設置顯示回調函數?
? ? glutDisplayFunc(renderScreen);
? ? //設置按鍵輸入處理回調函數
? ? glutSpecialFunc(specialKey);
? ? //設置全局渲染參數
? ? setupRederingState();
? ? glutMainLoop();
? ? return 0;
}
?
本博客還有另外一個講解模板緩沖區的例子,參見:http://blog.163.com/danshiming@126/blog/static/109412748201632895137788/
?
[cpp]?view plaincopy
模板測試實例:
示例程序使用了一個螺紋線模板去填充一個矩形框。可以單擊鼠標右鍵彈出菜單選擇填充的形式,也可以按鍵盤的UP,DOWN,LEFT,RIGHT按鍵旋轉坐標系,可以發現模板測試與glPolygonStipple不一樣,當坐標系旋轉一定角度后,填充的模板也會跟著旋轉。
總結
以上是生活随笔為你收集整理的OPenGL模板缓冲区示例程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何校准小米手环时间
- 下一篇: OpenGL的glScissor示例程序