我正在尝试在OpenGL中实现一个2D相机,其行为类似于Google地图相机,特别是“缩放到鼠标点”的功能。
到目前为止,我已经成功实现了平移和缩放 - 但只有当缩放锁定在窗口/小部件的中心时才可以。如果我尝试在鼠标位置缩放,则视图似乎会“跳动”,并且在缩放级别增加后,我缩放的物品不再位于鼠标光标下方。
我的相机类如下 - 代码量很大,但很抱歉我无法使它更小!
在每个帧的开始处调用
更新:我似乎已经注意到了两个问题:
我还使用Qt,如果这有任何区别的话,我只是有一个基本的QGLWidget,我使用鼠标滚轮事件来进行缩放,我获取滚轮事件的delta,然后根据鼠标位置添加或减去0.1f刻度。
到目前为止,我已经成功实现了平移和缩放 - 但只有当缩放锁定在窗口/小部件的中心时才可以。如果我尝试在鼠标位置缩放,则视图似乎会“跳动”,并且在缩放级别增加后,我缩放的物品不再位于鼠标光标下方。
我的相机类如下 - 代码量很大,但很抱歉我无法使它更小!
在每个帧的开始处调用
Apply()
,当场景被平移时调用SetX/YPos
,最后在鼠标滚轮滚动时使用以前的比例+/- 0.1f
调用SetScale
与鼠标位置。
camera.h
class Camera
{
public:
Camera();
void Apply();
void SetXPos(float xpos);
void SetYPos(float ypos);
void SetScale(float scaleFactor, float mx, float my);
float XPos() const { return m_XPos; }
float YPos() const { return m_YPos; }
float Scale() const { return m_ScaleFactor; }
void SetWindowSize(int w, int h);
void DrawTestItems();
private:
void init_matrix();
float m_XPos;
float m_YPos;
float m_ScaleFactor;
float m_Width;
float m_Height;
float m_ZoomX;
float m_ZoomY;
};
camera.cpp
Camera::Camera()
: m_XPos(0.0f),
m_YPos(0.0f),
m_ScaleFactor(1.0f),
m_ZoomX(0.0f),
m_ZoomY(0.0f),
m_Width(0.0f),
m_Height(0.0f)
{
}
// Called when window is created and when window is resized
void Camera::SetWindowSize(int w, int h)
{
m_Width = (float)w;
m_Height = (float)h;
}
void Camera::init_matrix()
{
glViewport(0, 0, m_Width, m_Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float new_W = m_Width * m_ScaleFactor;
float new_H = m_Height * m_ScaleFactor;
// Point to zoom on
float new_x = m_ZoomX;
float new_y = m_ZoomY;
glOrtho( -new_W/2+new_x,
new_W/2+new_x,
new_H/2+new_y,
-new_H/2+new_y,
-1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Camera::Apply()
{
// Zoom
init_matrix();
// Pan
glTranslatef( m_XPos, m_YPos, 1.0f );
DrawTestItems();
}
void Camera::SetXPos(float xpos)
{
m_XPos = xpos;
}
void Camera::SetYPos(float ypos)
{
m_YPos = ypos;
}
// mx,my = window coords of mouse pos when wheel was scrolled
// scale factor goes up or down by 0.1f
void Camera::SetScale(float scaleFactor, float mx, float my)
{
m_ZoomX = (float)mx;
m_ZoomY = (float)my;
m_ScaleFactor = scaleFactor;
}
void Camera::DrawTestItems()
{
}
更新:我似乎已经注意到了两个问题:
- 在SetScale中,鼠标位置不正确-我不知道原因。
- 无论我尝试什么方法,glOrtho都会导致屏幕中心成为缩放点,我通过手动设置/硬编码确认了这一点。在Google地图中,屏幕不会像这样“粘”在中心。
我还使用Qt,如果这有任何区别的话,我只是有一个基本的QGLWidget,我使用鼠标滚轮事件来进行缩放,我获取滚轮事件的delta,然后根据鼠标位置添加或减去0.1f刻度。