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);

它似乎有效,但是当我进行新的点击时,截头体会跳来跳去。我认为在存储鼠标位置时我没有考虑到 zoomOut 因素。

编辑:这是我仍在努力解决的最新代码...

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

如果您想走不同的路线并简单地使用 glTranslate 和 gluPerspective,您可以获得相同的效果。滚轮的鼠标事件(使用 PyOpenGL)可能类似于:

def MouseWheelScroll(self, event):
    """Called when the mouse's scroll wheel is scrolled up or down. This modifies the zoomFactor
    which renders the graphics closer or further away on the screen. It also translates the graphics
    slightly based on the position of the mouse. This creates an effect of zooming to the location
    of the mouse on the screen.
    """
    scrolledUp = event.GetWheelRotation() # Returns positive for up, negative for down
    self.x, self.y = event.GetPosition()

    viewport = glGetIntegerv(GL_VIEWPORT)
    width = viewport[2]
    height = viewport[3]
    centerX = width / 2.0
    centerY = height / 2.0

    # Make sure cursor is on the screen
    if ((self.x > 0 and self.x < width) and (self.y > 0 and self.y < height)):
        if (scrolledUp > 0):
            self.zoomFactor -= 2.0
            self.translation[0] -= (self.x - centerX)
            self.translation[1] += (self.y - centerY)
        else:
            self.zoomFactor += 2.0
            self.translation[0] += (self.x - centerX)
            self.translation[1] += (self.y - centerY)

        if (self.zoomFactor > 150.0):
            self.zoomFactor = 150.0
        elif (self.zoomFactor < 0.1):
            self.zoomFactor = 0.1

    self.Refresh(False)

然后,您只需要翻译图形、设置透视图,然后渲染场景。

# Translate graphics
glTranslatef(0.0, 0.0, (self.translation[1]/100.0) * (math.tan(self.cameraPosition[0]/self.cameraPosition[1])))
glTranslatef(0.0, (self.translation[0]/100.0) * (math.tan(self.cameraPosition[0]/self.cameraPosition[1])), 0.0)

# Set Perspective
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(self.zoomFactor, float(width)/float(height), self.nearPlane, self.farPlane)

# Render Scene
glMatrixMode(GL_MODELVIEW)
...Draw stuff here...
于 2014-05-15T23:03:50.247 回答
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 回答
0

我假设当您进行第二次单击时,您将其值存储到 mouseStoreXY 中。如果是这样,这就是跳跃的原因。您正在使用旧 mouseStoreXY 的偏移量进行绘制,然后突然偏移到新的。

解决方案是永久存储投影矩阵输入,然后在每一帧上逐步修改它们。

于 2013-02-21T07:19:14.947 回答