使用glOrtho缩放到鼠标位置
Zooming to mouse position using glOrtho
当前我正在使用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
}
尝试一下:
// 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;
}
我假设当您进行第二次单击时,您将其值存储到mouseStoreXY中。如果是这样的话,这就是跳跃的原因。您使用旧mouseStoreXY的偏移进行绘制,然后突然偏移到新的。
解决方案是持久地存储投影矩阵输入,然后在每帧上递增地修改它们。
尝试一下:
// 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;
}
如果你想走另一条路,只需使用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...
相关文章:
- 使用 dlib 记录鼠标位置
- 获取窗口中的鼠标位置
- 将文本添加到鼠标位置时,请单击“给出分割故障”
- 在鼠标位置移动精灵
- 如何在Mac OSX上的窗口客户端内获取真实的鼠标位置?
- 如何始终获得QT鼠标位置
- QT QgraphicView和Qgraphicscene鼠标位置
- QT:QGraphicsScene鼠标位置始终(0,0)
- SFML鼠标位置和碰撞从文件加载
- 根据鼠标位置缩小到窗口中
- 如何根据鼠标位置旋转精灵
- OpenGL获取离当前鼠标位置最近的世界三维点的三维坐标
- C++ SDL 根据鼠标位置绘制动态矩形
- 如何检索WM_COMMAND中的鼠标位置
- Qt mouseMoveEvent-跟踪鼠标位置
- OpenGl获取鼠标位置
- 获取RGBDemo的鼠标位置坐标
- 通过互联网发送鼠标位置
- 如何使用可可获得鼠标位置差异的变化
- 鼠标位置并单击 sfml 中的检测