青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

eryar

PipeCAD - Plant Piping Design Software.
PlantAssistant - Translate AVEVA RVM/SP3D VUE to glTF, STEP, etc.
posts - 606, comments - 590, trackbacks - 0, articles - 0

GLUT Trackball Demo

Posted on 2017-06-07 23:01 eryar 閱讀(2188) 評論(2)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE

GLUT Trackball Demo

eryar@163.com

1.Introduction

在三維場景中建立模型后,為了方便用戶從各個角度觀察模型,從而需要對三維視圖進行控制。常見的視圖交互控制方式有:Trackball控制器、飛行控制器,還有三維游戲常用的第一人稱控制器。這些視圖控制器的根本是對模型視圖矩陣MODELVIEW進行變換。

Trackball控制器以一種用戶友好的交互方式來變換視圖,原理是由Trackball激發,Trackball如下圖所示:

wpsD30B.tmp

Figure 1. Trackball

通過手指在球面上滾動,就可以對三維視圖進行控制。現在需要用鼠標的拖動來模擬Trackball以實現對三維視圖的控制。在OpenGL中實現Trackball控制視圖分為以下幾步:

1.將鼠標移動時的屏幕坐標點映射到單位球上;
wpsD32B.tmp

2.將開始旋轉視圖時鼠標點到球心的向量與鼠標移動過程中的坐標點球心的向量叉乘,即可得到旋轉軸;

wpsD32C.tmp
根據叉乘的定義,可以得到旋轉角度:
wpsD32D.tmp

有了旋轉軸和旋轉角度,就可以對視圖進行旋轉操作了。

2.GLUT Test

為了簡明地說明Trackball的原理,這里只使用了GLUT庫和OpenCASCADE中的四元數和向量相關的類。如果其他開源庫也有向量計算和四元數據計算類,也可以將代碼很快移植到使用其他庫,如矩陣計算庫Eigen等。下面給出GLUT的示例代碼:

/*
Copyright(C) 2017 Shing Liu(eryar@163.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/


#include <gp_XYZ.hxx>
#include <gp_Trsf.hxx>
#include <gp_Quaternion.hxx>

#include <gl/glut.h>

#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")

GLint VIEWPORT_WIDTH = 0;
GLint VIEWPORT_HEIGHT = 0;

gp_XYZ U;
gp_XYZ V;

gp_Quaternion R;
gp_Quaternion Q;


void init(void)
{
    GLfloat aSpecularMaterial[]  = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat aLightPosition[] = {1.0, 1.0, 1.0, 0.0};
    GLfloat aWhiteLight[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat aModelAmbient[] = {0.1, 0.1, 0.1, 1.0};

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);

    glMaterialfv(GL_FRONT, GL_SPECULAR, aSpecularMaterial);
    glMaterialf(GL_FRONT, GL_SHININESS, 60.0);

    glLightfv(GL_LIGHT0, GL_POSITION, aLightPosition);
    glLightfv(GL_LIGHT0, GL_SPECULAR, aWhiteLight);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, aWhiteLight);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, aModelAmbient);

    // Enable lighting
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutSolidTeapot(1.0);

    // draw mouse motion point.
    glBegin(GL_LINES);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(U.X() * 2.0, U.Y() * 2.0, U.Z() * 2.0);
    glEnd();

    glutSwapBuffers();
}

void reshape(GLint theWidth, GLint theHeight)
{
    VIEWPORT_WIDTH = theWidth;
    VIEWPORT_HEIGHT = theHeight;

    // Reset viewport and projection parameter
    glViewport(0, 0, theWidth, theHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (theWidth <= theHeight)
    {
        glOrtho(-1.5, 1.5, -1.5 * theHeight / theWidth, 1.5 * theHeight / theWidth, -10.0, 10.0);
    }
    else
    {
        glOrtho(-1.5 * theWidth / theHeight, 1.5 * theWidth / theHeight, -1.5, 1.5, -10.0, 10.0);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void mapToSphere(GLint theX, GLint theY, gp_XYZ& thePnt)
{
    GLfloat aX = (theX - 0.5 * VIEWPORT_WIDTH) / VIEWPORT_WIDTH;
    GLfloat aY = (0.5 * VIEWPORT_HEIGHT - theY) / VIEWPORT_HEIGHT;

    GLfloat aSinx = sin(M_PI * aX * 0.5);
    GLfloat aSiny = sin(M_PI * aY * 0.5);
    GLfloat aSxy2 = aSinx * aSinx + aSiny * aSiny;

    thePnt.SetX(aSinx);
    thePnt.SetY(aSiny);
    thePnt.SetZ(aSxy2 < 1.0 ? sqrt(1.0 - aSxy2) : 0.0);

}

void mouse(GLint theButton, GLint theState, GLint theX, GLint theY)
{
    mapToSphere(theX, theY, U);

    glutPostRedisplay();
}

void motion(GLint theX, GLint theY)
{
    mapToSphere(theX, theY, V);

    gp_XYZ W = U.Crossed(V);
    if (W.Modulus() < gp::Resolution())
    {
        return;
    }

    GLfloat aAngle = W.Modulus() / (U.Modulus() * V.Modulus());
    aAngle = asin(aAngle);

    glRotatef(aAngle * 180.0 / M_PI, W.X(), W.Y(), W.Z());

    glutPostRedisplay();

    U = V;
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(500, 300);
    glutCreateWindow("Trackball Demo");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);

    glutMainLoop();

    return 0;
}

上述程序運行結果如下動圖所示:

trackball1

從上圖可知,當旋轉幾次后視圖并沒有得到預期的結果。因為程序將鼠標映射后坐標與球心得到的向量進行了顯示,發現當旋轉幾次后,這個向量并沒有跟隨鼠標。

3.Transform

通過觀察上面代碼程序運行的結果,可以發現鼠標映射函數得到的映射點始終是位于XOY平面上的一個半球面上。當視圖被旋轉后,視圖的坐標系已經發生了變化,而映射點并沒有。為了跟蹤這個變換用四元數進行累乘來記錄這一系列的旋轉變換。最后在映射函數中將映射點變換到已經改變的視圖坐標系中。

即在鼠標移動處理函數中增加記錄變換:

    gp_Quaternion q(W, aAngle);
    R.Multiply(q);

在mapToSphere函數中增加:

gp_Trsf aTrsf;
aTrsf.SetRotation(Q.Inverted());
aTrsf.Transforms(thePnt);

列出升級后的全部代碼如下所示:

/*
Copyright(C) 2017 Shing Liu(eryar@163.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/


#include <gp_XYZ.hxx>
#include <gp_Trsf.hxx>
#include <gp_Quaternion.hxx>

#include <gl/glut.h>

#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")

GLint VIEWPORT_WIDTH = 0;
GLint VIEWPORT_HEIGHT = 0;

gp_XYZ U;
gp_XYZ V;

gp_Quaternion R;
gp_Quaternion Q;


void init(void)
{
    GLfloat aSpecularMaterial[]  = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat aLightPosition[] = {1.0, 1.0, 1.0, 0.0};
    GLfloat aWhiteLight[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat aModelAmbient[] = {0.1, 0.1, 0.1, 1.0};

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);

    glMaterialfv(GL_FRONT, GL_SPECULAR, aSpecularMaterial);
    glMaterialf(GL_FRONT, GL_SHININESS, 60.0);

    glLightfv(GL_LIGHT0, GL_POSITION, aLightPosition);
    glLightfv(GL_LIGHT0, GL_SPECULAR, aWhiteLight);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, aWhiteLight);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, aModelAmbient);

    // Enable lighting
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutSolidTeapot(1.0);

    // draw mouse motion point.
    glBegin(GL_LINES);
        glVertex3f(0.0, 0.0, 0.0);
        glVertex3f(U.X() * 2.0, U.Y() * 2.0, U.Z() * 2.0);
    glEnd();

    glutSwapBuffers();
}

void reshape(GLint theWidth, GLint theHeight)
{
    VIEWPORT_WIDTH = theWidth;
    VIEWPORT_HEIGHT = theHeight;

    // Reset viewport and projection parameter
    glViewport(0, 0, theWidth, theHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (theWidth <= theHeight)
    {
        glOrtho(-1.5, 1.5, -1.5 * theHeight / theWidth, 1.5 * theHeight / theWidth, -10.0, 10.0);
    }
    else
    {
        glOrtho(-1.5 * theWidth / theHeight, 1.5 * theWidth / theHeight, -1.5, 1.5, -10.0, 10.0);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void mapToSphere(GLint theX, GLint theY, gp_XYZ& thePnt)
{
    GLfloat aX = (theX - 0.5 * VIEWPORT_WIDTH) / VIEWPORT_WIDTH;
    GLfloat aY = (0.5 * VIEWPORT_HEIGHT - theY) / VIEWPORT_HEIGHT;

    GLfloat aSinx = sin(M_PI * aX * 0.5);
    GLfloat aSiny = sin(M_PI * aY * 0.5);
    GLfloat aSxy2 = aSinx * aSinx + aSiny * aSiny;

    thePnt.SetX(aSinx);
    thePnt.SetY(aSiny);
    thePnt.SetZ(aSxy2 < 1.0 ? sqrt(1.0 - aSxy2) : 0.0);

    gp_Trsf aTrsf;
    aTrsf.SetRotation(Q.Inverted());
    aTrsf.Transforms(thePnt);
}

void mouse(GLint theButton, GLint theState, GLint theX, GLint theY)
{
    mapToSphere(theX, theY, U);

    Q = R;

    glutPostRedisplay();
}

void motion(GLint theX, GLint theY)
{
    mapToSphere(theX, theY, V);

    gp_XYZ W = U.Crossed(V);
    if (W.Modulus() < gp::Resolution())
    {
        return;
    }

    GLfloat aAngle = W.Modulus() / (U.Modulus() * V.Modulus());
    aAngle = asin(aAngle);

    glRotatef(aAngle * 180.0 / M_PI, W.X(), W.Y(), W.Z());

    glutPostRedisplay();

    gp_Quaternion q(W, aAngle);
    R.Multiply(q);

    U = V;
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(500, 300);
    glutCreateWindow("Trackball Demo");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);

    glutMainLoop();

    return 0;
}

這次程序運行和預期結果一致,旋轉很流暢:

trackball2

4.Conclusion

程序員總是有很強的控制欲,希望一切盡在掌握之中。在三維場景中建立模型后,如何對視圖進行控制來方便地觀察模型呢?最常見的控制方式就是Trackball. OpenSceneGraph、Eigen等開源庫都有相關的實現。

Trackball的實現主要是將鼠標點映射到一個球面上,然后使用叉乘得到旋轉軸和旋轉角度。為了旋轉的流暢,使用四元數記錄了一系列的旋轉變換,最后通過將映射點進行坐標變換得到滿意的效果。

5.References

1. Virtual Trackball. http://gukewen.sdu.edu.cn/panrj/courses/4-AngelCGE2-Virtual-Trackball.pdf

2. Object Mouse Trackball https://www.khronos.org/opengl/wiki/Object_Mouse_Trackball

Feedback

# re: GLUT Trackball Demo  回復  更多評論   

2017-06-16 17:23 by ccsdu2009
用glfw

# re: GLUT Trackball Demo  回復  更多評論   

2017-06-16 19:37 by eryar
@ccsdu2009
這個是學習用的。

好用的庫有很多,像OpenSceneGraph, OpenCASCADE.

哈哈~~
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美怡红院视频| 午夜性色一区二区三区免费视频| 久久天天躁狠狠躁夜夜av| 国产欧美日韩一区二区三区在线观看 | 欧美xx69| 亚洲精品资源| 日韩一级欧洲| 免费日韩成人| 美女脱光内衣内裤视频久久影院| 亚洲欧洲一区二区在线观看 | 欧美中文字幕久久| 免费的成人av| 欧美成人免费在线观看| 99re66热这里只有精品4| 99天天综合性| 国产亚洲欧美在线| 欧美成人精品h版在线观看| 欧美大片91| 午夜久久久久久| 久久五月婷婷丁香社区| 99日韩精品| 欧美专区18| 日韩午夜av| 欧美亚洲日本一区| 亚洲精品日韩欧美| 亚洲午夜一级| 亚洲国产精品t66y| 一本色道久久88综合日韩精品| 国产日韩欧美在线播放| 亚洲国产精品成人精品| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 这里只有精品视频在线| 国产日韩欧美在线观看| 亚洲精品国产日韩| 国产欧美亚洲一区| 91久久久久久久久| 国产视频欧美视频| 99精品国产福利在线观看免费| 精品二区视频| 亚洲永久免费| 9色国产精品| 久久综合久久综合这里只有精品| 亚洲一区二区三区免费观看| 另类欧美日韩国产在线| 欧美在线观看视频| 欧美日韩国产一中文字不卡| 久久综合久久美利坚合众国| 国产精品久久国产三级国电话系列| 欧美激情综合| 亚洲国产高清自拍| 久久精品99国产精品| 午夜老司机精品| 欧美精品亚洲精品| 欧美国产日韩视频| 国产一区在线看| 亚洲一区二区三区高清| 在线中文字幕一区| 欧美激情视频在线免费观看 欧美视频免费一| 久久成人18免费网站| 欧美亚洲成人免费| 亚洲精品国产品国语在线app| 亚洲黄一区二区| 老**午夜毛片一区二区三区| 蜜桃久久精品一区二区| 狠久久av成人天堂| 久久se精品一区精品二区| 久久精品91| 国产视频一区二区在线观看| 午夜宅男欧美| 久久久亚洲欧洲日产国码αv | 男女视频一区二区| 欧美77777| 亚洲精品欧美日韩专区| 免费视频最近日韩| 亚洲国产片色| 99亚洲一区二区| 欧美日韩中文另类| av成人老司机| 亚洲欧美综合v| 国产老肥熟一区二区三区| 性欧美超级视频| 免费日韩av| 99这里只有精品| 国产精品久久久久久久久久久久| 亚洲一区二区在线播放| 欧美伊人久久| 亚洲国产99| 欧美日韩不卡| 亚洲欧美日韩在线| 久久久久久亚洲精品中文字幕| 精品不卡一区二区三区| 免播放器亚洲| 亚洲午夜影视影院在线观看| 久久国产精品久久精品国产| 在线观看亚洲专区| 欧美欧美在线| 亚洲影院色在线观看免费| 巨乳诱惑日韩免费av| 亚洲美女视频在线观看| 国产精品入口福利| 玖玖精品视频| 亚洲天堂免费在线观看视频| 免费日韩成人| 亚洲欧美一区二区三区极速播放 | 国产免费成人av| 久久伊人亚洲| 亚洲一本大道在线| 欧美成人午夜视频| 亚洲欧美韩国| 亚洲黄页视频免费观看| 欧美网站在线观看| 久久九九电影| 中文高清一区| 亚洲第一级黄色片| 亚洲欧美日韩国产综合精品二区| 亚洲国产一二三| 国产女同一区二区| 欧美国产极速在线| 久久久www成人免费精品| 亚洲毛片一区二区| 久久综合亚洲社区| 欧美一级久久| 国产精品99久久久久久人| 国内精品久久久| 国产精品你懂的在线欣赏| 美女精品在线观看| 欧美中文在线视频| 99热这里只有成人精品国产| 欧美夫妇交换俱乐部在线观看| 欧美在线视频观看| 亚洲一区二区影院| 99热免费精品| 亚洲三级免费| 亚洲国产婷婷香蕉久久久久久99| 国产欧美高清| 国产精品一区视频| 国产精品久久久久久妇女6080| 欧美欧美午夜aⅴ在线观看| 久久视频在线免费观看| 欧美影院视频| 欧美在线免费看| 欧美在线免费一级片| 亚洲欧美日韩中文播放| 亚洲一区二区三区四区视频 | 亚洲日本在线观看| 欧美激情精品久久久久久久变态 | 久久网站热最新地址| 亚洲欧美美女| 欧美一区二区三区男人的天堂| 亚洲欧美综合v| 香蕉免费一区二区三区在线观看| 亚洲视频狠狠| 亚洲免费一在线| 午夜一级久久| 欧美中文字幕在线播放| 久久国产福利| 久久亚洲春色中文字幕| 久久五月天婷婷| 亚洲成色777777在线观看影院| 欧美国产成人在线| 亚洲第一视频网站| 欧美国产极速在线| 亚洲精品系列| 亚洲午夜精品久久久久久app| 午夜亚洲福利| 久久欧美中文字幕| 欧美国内亚洲| 欧美性猛交xxxx免费看久久久| 国产精品美女| 好吊色欧美一区二区三区四区| 亚洲国产你懂的| 一区二区欧美日韩| 欧美一激情一区二区三区| 久久久99久久精品女同性| 能在线观看的日韩av| 亚洲人www| 午夜精品视频网站| 久久综合一区二区| 欧美日韩亚洲一区三区 | 国产日韩欧美不卡| 影视先锋久久| 一区二区三区欧美在线| 久久精品国产2020观看福利| 欧美顶级大胆免费视频| 一区二区三区国产在线观看| 欧美在线日韩精品| 欧美精选午夜久久久乱码6080| 国产亚洲视频在线| 99riav1国产精品视频| 欧美一区二区免费观在线| 欧美国产日韩一二三区| 亚洲尤物在线视频观看| 久久这里只有精品视频首页| 欧美日韩免费网站| 在线精品视频免费观看| 亚洲欧美国产77777| 欧美激情1区2区| 欧美一区二区黄| 欧美午夜片在线免费观看| 在线免费日韩片|