第三章 使用者介面與互動式技術使用者介面設計
3.1 使用者介面設計
一個好的圖形使用者介面應具備以下特點:
易於被使用者理解並接受;
易於操作、使用;
高效率、可靠性和實用性。
一致性原則:
一致性原則是指在設計系統的各個環節時,應遵從統一和簡單的規則,保證不出現例外和特殊的情況,無論資訊顯示還是命令輸入都應如此。
按使用者認為最正常、最合乎邏輯的方式去做,這比保持單純的一致性更重要。
減少記憶量:
使用者介面的操作應該組織得容易理解和記憶。
重要的原則是喚醒使用者的識別而不是記憶。
邏輯輸入裝置——拾取裝置
拾取裝置:拾取裝置用於選擇情境中即將進行變換、編輯和處理的部分。
3.2略
3.3 互動式繪圖技術
基本互動繪圖技術:
回顯 約束 網格 引力域 橡皮筋技術 草擬技術 拖動 旋轉 形變
三維互動技術:
三維圖形資料的輸入
三維定位
三維定向
3.4 OpenGL實現橡皮筋技術
橡皮筋技術的實現方法:
利用顏色的異或操作,對原有圖形並不是擦除,而是再繪製一條同樣的直線段並與原圖形進行異或操作,此時原圖形會從螢幕上消失;
利用雙緩衝技術,繪製圖形時分別繪製到兩個緩衝,交替顯示。
滑鼠實現
滑鼠響應函數
glutMouseFunc
滑鼠移動相應函數
glutMotionFunc
glutPassiveMotionFunc
鍵盤實現
鍵盤相應函數
glutKeyboardFunc
3.5 OpenGL實現拾取操作
設定拾取緩衝區
void glSelectBuffer(GLsizei n, GLunint *buff);
進入選擇模式
GLint glRenderMode(GLenum mode);
名字堆棧操作
初始化名字堆棧(glInitNames)
將一個名字壓入堆棧(glPushName)
替換名字堆棧的棧頂元素(glLoadName)
將棧頂元素彈出(glPopName)
設定合適的變換過程
gluPickMatrix(xPick, yPick, widthPick, heightPick, *vp);
為每個圖元分配名字並繪製
切換回渲染模式
分析選擇緩衝區中的資料
3.6 OpenGL中的菜單功能
菜單註冊函數
glutCreateMenu(ProcessMenu);
在菜單中加入功能表項目
void glutAddMenuEntry(char *name, GLint value);
將菜單與某個滑鼠按鍵關聯
void glutAttachMenu(button);
#include <gl/glut.h>
int iPointNum = 0; //已確定點的數目
int x1=0,x2=0,y1=0,y2=0; //確定的點座標
int winWidth = 400, winHeight = 300; //視窗的寬度和高度
void Initial(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
void ChangeSize(int w, int h)
{
winWidth = w; winHeight = h;
glViewport(0, 0, w, h); //指定視窗顯示地區
glMatrixMode(GL_PROJECTION); //設定投影參數
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
if(iPointNum >= 1) {
glBegin(GL_LINES); //繪製直線段
glVertex2i(x1,y1);
glVertex2i(x2,y2);
glEnd();
}
glutSwapBuffers(); //交換緩衝區
}
void MousePlot(GLint button, GLint action, GLint xMouse, GLint yMouse)
{
if(button == GLUT_LEFT_BUTTON && action == GLUT_DOWN) {
if(iPointNum == 0 || iPointNum == 2){
iPointNum = 1;
x1 = xMouse; y1 = winHeight - yMouse;
}
else {
iPointNum = 2;
x2 = xMouse; y2 = winHeight - yMouse;
glutPostRedisplay(); //指定視窗重新繪製
}
}
if(button == GLUT_RIGHT_BUTTON && action == GLUT_DOWN){
iPointNum = 0;
glutPostRedisplay();
}
}
void PassiveMouseMove (GLint xMouse, GLint yMouse)
{
if(iPointNum == 1) {
x2 = xMouse;
y2 = winHeight - yMouse;
glutPostRedisplay();
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //使用雙緩衝及RGB模型
glutInitWindowSize(400,300);
glutInitWindowPosition(100,100);
glutCreateWindow("橡皮筋技術");
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize); //指定視窗在整形回呼函數
glutMouseFunc(MousePlot); //指定滑鼠響應函數
glutPassiveMotionFunc(PassiveMouseMove); //指定滑鼠移動響應函數
Initial();
glutMainLoop();
return 0;
}
#include <gl/glut.h>
int iPointNum = 0; //已確定點的數目
int x1=0,x2=0,y1=0,y2=0; //確定的點座標
int winWidth = 400, winHeight = 300; //視窗的寬度和高度
void Initial(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
void ChangeSize(int w, int h)
{
winWidth = w; winHeight = h;
glViewport(0, 0, w, h); //指定視窗顯示地區
glMatrixMode(GL_PROJECTION); //設定投影參數
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
if(iPointNum >= 1) {
glBegin(GL_LINES); //繪製直線段
glVertex2i(x1,y1);
glVertex2i(x2,y2);
glEnd();
}
glutSwapBuffers(); //交換緩衝區
}
void PassiveMouseMove (GLint xMouse, GLint yMouse)
{
if(iPointNum == 1) {
x2 = xMouse;
y2 = winHeight - yMouse;
glutPostRedisplay();
}
}
void Key(unsigned char key, int x, int y)
{
switch(key){
case 'p':
if(iPointNum == 0 || iPointNum == 2) {
iPointNum = 1;
x1 = x; y1 = winHeight - y;
}
else {
iPointNum = 2;
x2 = x; y2 = winHeight - y;
glutPostRedisplay();
}
break;
default: break;
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //使用雙緩衝及RGB模型
glutInitWindowSize(400,300);
glutInitWindowPosition(100,100);
glutCreateWindow("橡皮筋技術");
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize); //指定視窗在整形回呼函數
glutKeyboardFunc(Key); //指定鍵盤響應函數
glutPassiveMotionFunc(PassiveMouseMove); //指定滑鼠移動響應函數
Initial();
glutMainLoop();
return 0;
}
#include <gl/glut.h>
#include "stdio.h"
const GLint pickSize = 32;
int winWidth = 400, winHeight = 300;
void Initial(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
void DrawRect(GLenum mode)
{
if(mode == GL_SELECT) glPushName(1); //壓入堆棧
glColor3f(1.0f,0.0f,0.0f);
glRectf(60.0f,50.0f,150.0f,150.0f);
if(mode == GL_SELECT) glPushName(2); //壓入堆棧
glColor3f(0.0f,1.0f,0.0f);
glRectf(230.0f,50.0f,330.0f,150.0f);
if(mode == GL_SELECT) glPushName(3); //壓入堆棧
glColor3f(0.0f,0.0f,1.0f);
glRectf(140.0f,140.0f,240.0f,240.0f);
}
void ProcessPicks(GLint nPicks, GLuint pickBuffer[])
{
GLint i;
GLuint name, *ptr;
printf("選中的數目為%d個/n",nPicks);
ptr=pickBuffer;
for(i=0;i<nPicks; i++){
name=*ptr; //選中圖元在堆棧中的位置
ptr+=3; //跳過名字和深度資訊
ptr+=name-1; //根據位置資訊獲得選中的圖元名字
if(*ptr==1) printf("你選擇了紅色圖元/n");
if(*ptr==2) printf("你選擇了綠色圖元/n");
if(*ptr==3) printf("你選擇了藍色圖元/n");
ptr++;
}
printf("/n/n");
}
void ChangeSize(int w, int h)
{
winWidth = w;
winHeight = h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
DrawRect(GL_RENDER);
glFlush();
}
void MousePlot(GLint button, GLint action, GLint xMouse, GLint yMouse)
{
GLuint pickBuffer[pickSize];
GLint nPicks, vp[4];
if(button == GLUT_LEFT_BUTTON && action == GLUT_DOWN){
glSelectBuffer(pickSize,pickBuffer); //設定選擇緩衝區
glRenderMode(GL_SELECT); //啟用選擇模式
glInitNames(); //初始化名字堆棧
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT, vp);
//定義一個10×10的選擇地區
gluPickMatrix(GLdouble(xMouse), GLdouble(vp[3]-yMouse),10.0,10.0,vp);
gluOrtho2D(0.0,winWidth,0.0,winHeight);
DrawRect(GL_SELECT);
//恢複投影變換
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();
//獲得選擇集並輸出
nPicks = glRenderMode(GL_RENDER);
ProcessPicks(nPicks, pickBuffer);
glutPostRedisplay();
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400,300);
glutInitWindowPosition(100,100);
glutCreateWindow("拾取操作");
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize);
glutMouseFunc(MousePlot);
Initial();
glutMainLoop();
return 0;
}
最後的程式在vs2005種編譯出錯:
錯誤 1 error C2057: expected constant expression e:/vc/opengl1/opengl1/opengl.c 65
錯誤 2 error C2466: cannot allocate an array of constant size 0 e:/vc/opengl1/opengl1/opengl.c 65
錯誤 3 error C2133: 'pickBuffer' : unknown size e:/vc/opengl1/opengl1/opengl.c 65
錯誤 4 error C2143: syntax error : missing ')' before 'type' e:/vc/opengl1/opengl1/opengl.c 78
錯誤 5 error C2198: 'gluPickMatrix' : too few arguments for call e:/vc/opengl1/opengl1/opengl.c 78
修改兩處:
1、GLuint pickBuffer[32];//[pickSize];
2、gluPickMatrix((GLdouble)xMouse, (GLdouble)(vp[3]-yMouse),10.0,10.0,vp);