[英]OpenGL: Move 2D Orthographic Camera with Mouse
我正在使用 C++ 中的 OpenGL 为我的游戏制作关卡编辑器。 我正在尝试像在 Unity Engine 2D 场景相机中一样制作编辑器相机,但是当我尝试为相机实现鼠标移动(相机平移)时遇到问题。 我正在将鼠标 position 从屏幕转换为世界空间。
ScreenToWorldSpace 方法:
Vector3 Application::ScreenToWorldSpace(int mousex, int mousey)
{
double x = 2.0 * mousex / viewportWidth - 1;
double y = 2.0 * mousey / viewportHeight - 1;
Vector4 screenPos = Vector4(x, -y, -1.0f, 1.0f);
Matrix4 ProjectionViewMatrix = camera1->GetProjectionMatrix() * camera1->GetViewMatrix();
Matrix4 InverseProjectionViewMatrix = glm::inverse(ProjectionViewMatrix);
Vector4 worldPos = InverseProjectionViewMatrix * screenPos;
return Vector3(worldPos);
}
上述方法可以正常工作。
但我使用 ScreenToWorldSpace 坐标来更新相机 position。
渲染方法:
void Application::Render(float deltaTime)
{
Vector3 pos = ScreenToWorldSpace(mousePosition.x, mousePosition.y);
// This is the position of a tile not the camera
position = Vector3(0, 0, 0);
Vector3 rotation = Vector3(0, 0, 0);
Vector3 scale = Vector3(1);
Matrix4 translationMatrix = glm::translate(Matrix4(1.0f), position);
Matrix4 rotationMatrix = glm::eulerAngleYXZ(rotation.y, rotation.x, rotation.z);
Matrix4 scaleMatrix = glm::scale(Matrix4(1.0f), scale);
modelMatrix = translationMatrix * rotationMatrix * scaleMatrix;
if (mouseButtonDown)
{
Console << pos.x << ", " << pos.y << Endl;
camera1->position = Vector3(pos.x, pos.y, -10);
}
{
glScissor(0, 0, 900, 600);
glEnable(GL_SCISSOR_TEST);
glClearColor(236 / 255.0f, 64 / 255.0f, 122 / 255.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, 900, 600);
basicShader->Use();
dirt_grass_tex->Use();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
camera1->SetZoom(zoomFactor);
camera1->Update();
Matrix4 mvp = camera1->GetProjectionMatrix() * camera1->GetViewMatrix() * modelMatrix;
basicShader->SetUniformMat4("MVP", mvp);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glDisable(GL_SCISSOR_TEST);
}
}
相机 Class:
#include "camera.h"
Camera::Camera(int width, int height)
{
swidth = width;
sheight = height;
position = Vector3(0, 0, -10);
rotation = Vector3(0, 0, 0);
m_direction = Vector3(0, 0, -5);
m_up = Vector3(0, 1, 0);
m_right = Vector3(1, 0, 0);
m_offset = Vector3(-swidth / 2 * m_zoom, -sheight / 2 * m_zoom, 0);
m_projection = glm::ortho(0.0f * m_zoom, (float)swidth * m_zoom, 0.0f * m_zoom, (float)sheight * m_zoom, -1000.0f, 0.0f);
}
Camera::~Camera()
{
}
void Camera::Update()
{
Vector3 finalPos = position + m_offset;
m_up = glm::cross(m_right, m_direction);
m_viewMatrix = glm::lookAt(finalPos, finalPos + m_direction, m_up);
m_viewMatrix = glm::scale(m_viewMatrix, Vector3(100));
}
void Camera::SetZoom(float zoom)
{
m_zoom = zoom;
m_offset = Vector3(-swidth / 2 * m_zoom, -sheight / 2 * m_zoom, 0);
m_projection = glm::ortho(0.0f * m_zoom, (float)swidth * m_zoom, 0.0f * m_zoom, (float)sheight * m_zoom, -1000.0f, 0.0f);
}
以下是当我尝试使用从屏幕转换为世界空间的鼠标 position 移动相机时得到的 output:
if (mouseButtonDown)
{
Console << pos.x << ", " << pos.y << Endl;
position = Vector3(pos.x, pos.y, 0);
}
但是,如果我使用鼠标 position 使用ScreenToWorldSpace方法从屏幕转换到世界空间,则 object 会完美移动。 看看下面的 gif:
所以我正在尝试制作游戏引擎编辑器,因为我想实现像统一/虚幻引擎场景相机一样的编辑器场景相机。 以下是我目前正在使用的编辑器:
我试图寻找不同的资源,但我一无所知。 帮助我了解如何用鼠标移动相机。
我认为正在发生的事情:由于我正在使用相机的 projectionView 矩阵将鼠标 position 从屏幕转换为世界空间,并使用这些世界坐标移动相机 position 导致了问题,因为当相机移动时,projectionView 会更新,从而改变鼠标position 递归地相对于 viewMatrix。
我会很感激一些帮助。
通常,您不希望将鼠标 position 直接写入相机位置(因为这在实践中用途有限 - 每当您点击屏幕时,相机就会跳跃)。
您可能想要按照以下方式做一些事情:
Vector3 g_lastPosition;
void onMousePressed(int x, int y) {
// record starting position!
g_lastPosition = ScreenToWorldSpace(x, y);
}
void onMouseMove(int x, int y) {
// find the difference between new position, and last, in world space
Vector3 new_pos = ScreenToWorldSpace(x, y);
Vector3 offset = new_pos - g_lastPosition;
g_lastPosition = new_pos;
// now move camera by offset
camera->position += offset
}
如果您处于正交视图中,那么您实际上根本不需要担心投影矩阵。
int g_lastX;
int g_lastY;
void onMousePressed(int x, int y) {
// store mouse pos
g_lastX = x;
g_lastY = y;
}
void onMouseMove(int x, int y) {
// find the difference between new position, and last, in pixels
int offsetX = x - g_lastX;
int offsetY = y - g_lastY;
// update mouse pos
g_lastX = x;
g_lastY = y;
// get as ratio +/- 1
float dx = ((float) offsetX) / swidth;
float dy = ((float) offsetY) / sheight;
// now move camera by offset (might need to multiply by 2 here?)
camera->position.x += camera->m_offset.x * dx;
camera->position.y += camera->m_offset.y * dy;
}
但总的来说,对于任何基于鼠标的移动,您总是希望考虑添加偏移量,而不是设置精确的 position。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.