3

現在、glOrtho を使用して、レンダリング中の 2D グラフをズームおよびパンしています。

ビューポートを標準の幅と高さに設定しました。次に、錐台が画面座標を世界座標と一致させるように glOrtho を設定します。

glViewport(0, 0, window_width,window_height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, window_width,window_height,0 , 100, -100);

マウスのコールバックでズーム機能を実行すると、錐台のエッジにズーム係数が乗算されます....

glOrtho( 0 * zoomOut,
window_width * zoomOut,
window_height * zoomOut,
0 * zoomOut, 
100, -100);

私の質問は....マウスの位置を中心にズームするにはどうすればよいですか?

私はこれを試しました...(ここで、mouseStoreXとmouseStoreYは最初のクリックで保存された位置です)

glOrtho( (0 -mouseStoreX )* zoomOut + mouseStoreX,
(window_width - mouseStoreX) * zoomOut + mouseStoreX,
(window_height - mouseStoreY) * zoomOut + mouseStoreY,
(0 - mouseStoreY) * zoomOut + mouseStoreY, 
100, -100);

動作しているように見えますが、新しいクリックをすると錐台が飛び跳ねます。マウス位置の保存を行うときに、ズームアウト要因を考慮していないところがあると思います。

編集:これは私がまだ苦労している私の最新のコードです...

void ZoomOrtho(){ //ON MOUSE CLICK.....

if (zooming == false){
keyStore.LMx = keyStore.Mx;   //store mouse pos for next comparison
keyStore.LMy = keyStore.My;
//get mouse pos
mouseStoreX = keyStore.Mx;//mouse pos at this moment
mouseStoreY = keyStore.My;

//get current projection matrices
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
//flip Y for opengl reasons
winY = (float)viewport[3] - winY;
//get world mouse coordinate
gluUnProject( mouseStoreX, mouseStoreY , 0.0, modelview, projection, viewport, &posX_,&posY_, &posZ_);

// calc difference between mouse world pos and centre of 'camera'
dx = posX_ - FS.centerX;
dy = posY_ - FS.centerY;

}
//ON DRAG......
zooming = true;

//do mouse movement detection and increment zoomOut
//#################################################
int xDiff = keyStore.Mx - keyStore.LMx;  //mouse drag difference in screen space just  for incrementing zoom
int yDiff = keyStore.My - keyStore.LMy;  //

if (xDiff > 0 && (zoomFactor >= 0.5 ) )   {
zoomFactor -= zoomInc;
if  (zoomFactor < 0.5 ) {zoomFactor = 0.5;}
}
else if (xDiff < 0 && (zoomFactor <= 2.0 ))  {
zoomFactor += zoomInc;
if (zoomFactor > 2.0){zoomFactor = 2.0;}
}
//#################################################


//fill structure with clipping plane values. zooms ortho projection and keeps mouse pos anchored.
FS.left =  ((FS.centerX - dx - (window_width/2.0))*zoomFactor) +dx;
FS.right = ((FS.centerX -dx + (window_width/2.0))*zoomFactor)+dx ;
FS.bottom = ((FS.centerY -dy + (window_width/2.0))*zoomFactor)+dy;
FS.top =    ((FS.centerY -dy  - (window_width/2.0))*zoomFactor) +dy;

// store last mouse pos for next comparison.
keyStore.LMx = keyStore.Mx;
keyStore.LMy = keyStore.My;

}

void zoomRelease(){

cout << " releasing" << std::endl;
//set zoom to false so we know we are not draggin mouse anymore.
zooming = false;
keyStore.LMx = 0;
keyStore.LMy = 0;

// recenter by taking midpoint between new left and right clipping planes so dx has a reference point
FS.centreX = (FS.right-FS.left)/2.0;

}

void DrawGui(){

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(FS.left, FS.right,FS.bottom, FS.top, 1, -1);

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
//do drawing

} 
4

4 に答える 4

1

これを試してみてください:

// g++ main.cpp -o main -lglut -lGL && ./main
#include <GL/glut.h>

double centerX = 0, centerY = 0;
double width = 0, height = 0;
void mouse( int button, int state, int mx, int my )
{
    // flip mouse y axis so up is +y
    my = glutGet( GLUT_WINDOW_HEIGHT ) - my;

    // convert mouse coords to (-1/2,-1/2)-(1/2, 1/2) box
    double x = ( mx / (double)glutGet( GLUT_WINDOW_WIDTH ) ) - 0.5;
    double y = ( my / (double)glutGet( GLUT_WINDOW_HEIGHT ) ) - 0.5;

    if( GLUT_UP == state )
    {
        double preX = ( x * width );
        double preY = ( y * height );

        double zoomFactor = 1.5;
        if( button == GLUT_LEFT_BUTTON )
        {
            // zoom in
            width /= zoomFactor;
            height /= zoomFactor;
        }
        if( button == GLUT_RIGHT_BUTTON )
        {
            // zoom out
            width *= zoomFactor;
            height *= zoomFactor;
        }

        double postX = ( x * width );
        double postY = ( y * height );

        // recenter
        centerX += ( preX - postX );
        centerY += ( preY - postY );
    }

    glutPostRedisplay();
}

void display()
{
    glClear( GL_COLOR_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho
        (
        centerX - ( width / 2.0 ),
        centerX + ( width / 2.0 ),
        centerY - ( height / 2.0 ),
        centerY + ( height / 2.0 ),
        -1,
        1     
        );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glColor3ub( 255, 0, 0 );
    glBegin( GL_TRIANGLES );
    glVertex2i( 0, 0 );
    glVertex2i( 150, 0 );
    glVertex2i( 0, 150 );
    glVertex2i( 0, 0 );
    glVertex2i( -150, 0 );
    glVertex2i( 0, -150 );
    glEnd();

    glutSwapBuffers();
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "GLUT" );
    glutDisplayFunc( display );
    glutMouseFunc( mouse );

    width = glutGet( GLUT_WINDOW_WIDTH );
    height = glutGet( GLUT_WINDOW_HEIGHT );    

    glutMainLoop();
    return 0;
}
于 2013-02-21T21:55:21.690 に答える
0

2 回目のクリックを行うと、その値が mouseStoreXY に格納されると想定しています。もしそうなら、これがジャンプの原因です。古い mouseStoreXY のオフセットで描画していて、突然新しいものにオフセットしました。

解決策は、射影行列の入力を永続的に保存し、フレームごとに段階的に変更することです。

于 2013-02-21T07:19:14.947 に答える
0

これを試してみてください:

// g++ main.cpp -o main -lglut -lGL && ./main
#include <GL/glut.h>
#include <cmath>

void getMouseCoords( int mx, int my, double& x, double& y )
{
    // flip mouse y axis so up is +y
    my = glutGet( GLUT_WINDOW_HEIGHT ) - my;

    // convert mouse coords to (-1/2,-1/2)-(1/2, 1/2) box
    x = ( mx / (double)glutGet( GLUT_WINDOW_WIDTH ) ) - 0.5;
    y = ( my / (double)glutGet( GLUT_WINDOW_HEIGHT ) ) - 0.5;
}

int btn;
double baseX, baseY;
double baseWidth, baseHeight;

double centerX = 0, centerY = 0;
double width = 0, height = 0;
void mouse( int button, int state, int mx, int my )
{
    baseWidth = width;
    baseHeight = height;
    btn = button;
    getMouseCoords( mx, my, baseX, baseY );
}

void motion( int mx, int my )
{
    if( btn != GLUT_LEFT_BUTTON )
    {
        return;
    }

    double x, y;
    getMouseCoords( mx, my, x, y );

    double preX = ( baseX * width );
    double preY = ( baseY * height );

    double zoomFactor = exp( baseY - y );
    width = baseWidth * zoomFactor;
    height = baseHeight * zoomFactor;

    double postX = ( baseX * width );
    double postY = ( baseY * height );

    // recenter
    centerX += ( preX - postX );
    centerY += ( preY - postY );

    glutPostRedisplay();
}

void display()
{
    glClear( GL_COLOR_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho
        (
        centerX - ( width / 2.0 ),
        centerX + ( width / 2.0 ),
        centerY - ( height / 2.0 ),
        centerY + ( height / 2.0 ),
        -1,
        1     
        );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glColor3ub( 255, 0, 0 );
    glBegin( GL_TRIANGLES );
    glVertex2i( 0, 0 );
    glVertex2i( 150, 0 );
    glVertex2i( 0, 150 );
    glVertex2i( 0, 0 );
    glVertex2i( -150, 0 );
    glVertex2i( 0, -150 );
    glEnd();

    glutSwapBuffers();
}

int main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "GLUT" );
    glutDisplayFunc( display );
    glutMouseFunc( mouse );
    glutMotionFunc( motion );

    width = glutGet( GLUT_WINDOW_WIDTH );
    height = glutGet( GLUT_WINDOW_HEIGHT );    

    glutMainLoop();
    return 0;
}
于 2013-02-22T21:46:46.353 に答える