鼠标拾取的目标时服务于引擎编辑器,根据鼠标点击位置,确定用户点中了场景中的哪个实体(Entity)。
鼠标拾取的实现思路:
鼠标拾取功能的实现与帧缓冲区有关。在一个帧缓冲区中,在原有的一层颜色附件上,再加上一层颜色附件,只不过此前保存的是三元组形式的RGB8,而这一层则保存一个整数格式的RED_INTEGER。
一个帧缓存区就像PS中的图层,每一个颜色附件就是一层。比如,这一层颜色附件保存的是RGB8,则表示每一个像素存储的都是RGB8,即反映到屏幕上的颜色。如果这一层颜色附件保存了RED_INTEGER,则保存的是一个ID,而这个ID则就是我们想要的Entity ID,获取到这个ID后,就可以知道我们当前点击的是哪个Entity。
当鼠标点击时,读取鼠标所在像素的帧缓冲区的颜色附件的值,就知道用户点中了哪个实体。
将整个场景光栅化,而不是写出每个像素的颜色值。
Entity ID -> ID 渲染区 -> 附加到帧缓冲区,从而不添加额外的渲染通道
将Entity ID写入帧缓冲区的过程:
在渲染实体时,将 Entity 的 ID 传入 shader,然后写入帧缓冲区的整数颜色附件(比如 RED_INTEGER 格式)中。
读取帧缓存区的ID颜色附件中每个像素的Entity ID的过程:
将鼠标坐标转换为像素坐标,然后读取该像素的值:
int OpenGLFramebuffer::ReadPixel(uint32_t attachmentIndex, int x, int y)
{
glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentIndex);
int pixelData;
glReadPixels(x, y, 1, 1, GL_RED_INTEGER, GL_INT, &pixelData);
return pixelData;
}
在EditorLayer的函数OnUpdate()中,如果鼠标在视窗内,则读取像素位置:
auto [mx, my] = ImGui::GetMousePos();
mx -= m_ViewportBounds[0].x;
my -= m_ViewportBounds[0].y;
glm::vec2 viewportSize = m_ViewportBounds[1] - m_ViewportBounds[0];
my = viewportSize.y - my;
int mouseX = (int)mx;
int mouseY = (int)my;
// 当鼠标在窗口内时,读取鼠标所在的像素以分辨Entity
if (mouseX >= 0 && mouseY >= 0 && mouseX < (int)viewportSize.x && mouseY < (int)viewportSize.y)
{
int pixelData = m_Framebuffer->ReadPixel(1, mouseX, mouseY);
HZ_CORE_WARN("Pixel data = {0}", pixelData);
}

Leave a comment