mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 17:26:22 +01:00
Merge pull request #240 from miloszunio/fix/gl46-editor-cursor-depth
fix(gl46): editor cursor depth read in the biased depth pass (port of 7078edf)
This commit is contained in:
@@ -407,7 +407,7 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
|
||||
if (Global.iMultisampling)
|
||||
{
|
||||
m_depth_pointer_rb = std::make_unique<gl::renderbuffer>();
|
||||
m_depth_pointer_rb->alloc(depth_pointer_format, 1, 1);
|
||||
m_depth_pointer_rb->alloc(depth_pointer_format, 3, 3); // the pixel under the cursor and the ones around it
|
||||
|
||||
m_depth_pointer_fb = std::make_unique<gl::framebuffer>();
|
||||
m_depth_pointer_fb->attach(*m_depth_pointer_rb, GL_DEPTH_ATTACHMENT);
|
||||
@@ -5497,53 +5497,100 @@ void opengl46_renderer::Pick_Node_Callback(std::function<void(scene::basic_node
|
||||
m_node_pick_requests.push_back(callback);
|
||||
}
|
||||
|
||||
// the position of the cursor of the editor in the scene: the depth around it read back from an earlier frame, worked out in
|
||||
// the view that frame was drawn in (the cursor and the camera may have moved since), and kept in world space
|
||||
glm::dvec3 opengl46_renderer::Update_Mouse_Position()
|
||||
{
|
||||
if (!m_depth_pointer_pbo->is_busy())
|
||||
{
|
||||
// determine point to examine
|
||||
glm::vec2 mousepos = Global.cursor_pos;
|
||||
mousepos.y = Global.window_size.y - mousepos.y; // cursor coordinates are flipped compared to opengl
|
||||
// the depths asked for before, around where the cursor was then
|
||||
auto const count{m_cursorblocksize.x * m_cursorblocksize.y};
|
||||
std::array<float, 9> depths{};
|
||||
if ((count > 0) && (count <= static_cast<int>(depths.size())) && m_depth_pointer_pbo->read_data(m_cursorblocksize.x, m_cursorblocksize.y, depths.data(), 4))
|
||||
{
|
||||
auto const centre{m_cursorposition - m_cursorblockcorner};
|
||||
auto const depth_at = [&](glm::ivec2 const Pixel) {
|
||||
if ((Pixel.x < 0) || (Pixel.y < 0) || (Pixel.x >= m_cursorblocksize.x) || (Pixel.y >= m_cursorblocksize.y))
|
||||
{
|
||||
return 0.f;
|
||||
}
|
||||
return depths[static_cast<std::size_t>(Pixel.y * m_cursorblocksize.x + Pixel.x)];
|
||||
};
|
||||
float pointdepth{depth_at(centre)};
|
||||
if (m_cursorbiased && (pointdepth > 0.f))
|
||||
{
|
||||
// read in the depth pass of the scene (Render_Scene_Depth()), which draws everything a little farther than it lies
|
||||
// (glPolygonOffset(-1, -1)), so the colour pass passes on the same surface. the slope of the depth grows towards the
|
||||
// horizon, and the ground seen at a grazing angle came out a pixel's worth of ground farther than it lies, metres off
|
||||
// some way from the camera. the slope is taken back as in the vulkan renderer: the pixels next to it on the same triangle
|
||||
// are moved by the same bias, so their difference is the slope; of the two sides the smaller, which is less likely
|
||||
// to lie on another surface, and the larger of the two axes, the one implementations use for m. then the unit, r
|
||||
auto const slope = [&](glm::ivec2 const Step) {
|
||||
auto result{-1.f};
|
||||
for (auto const side : {-1, 1})
|
||||
{
|
||||
auto const other{depth_at(centre + Step * side)};
|
||||
if (other > 0.f)
|
||||
{
|
||||
auto const difference{std::abs(other - pointdepth)};
|
||||
result = (result < 0.f ? difference : std::min(result, difference));
|
||||
}
|
||||
}
|
||||
return std::max(result, 0.f);
|
||||
};
|
||||
pointdepth += std::max(slope({1, 0}), slope({0, 1})) + std::ldexp(1.f, std::ilogb(pointdepth) - 23);
|
||||
}
|
||||
m_mousehit = pointdepth > 0.0f;
|
||||
if (m_mousehit)
|
||||
{
|
||||
auto const offset{glm::unProjectZO(glm::vec3(m_cursorposition, pointdepth), m_cursorview, m_cursorprojection, m_cursorviewport)};
|
||||
m_worldmouseposition = m_cursorcamera + glm::dvec3{offset};
|
||||
m_mouseknown = true;
|
||||
}
|
||||
}
|
||||
|
||||
glm::ivec2 bufferpos;
|
||||
bufferpos = glm::ivec2(mousepos * glm::vec2(Global.gfx_framebuffer_width, Global.gfx_framebuffer_height) / glm::vec2(Global.window_size));
|
||||
bufferpos = glm::clamp(bufferpos, glm::ivec2(0, 0), glm::ivec2(Global.gfx_framebuffer_width - 1, Global.gfx_framebuffer_height - 1));
|
||||
|
||||
float pointdepth = std::numeric_limits<float>::max();
|
||||
|
||||
m_depth_pointer_pbo->read_data(1, 1, &pointdepth, 4);
|
||||
// ask for the depths around where the cursor is now
|
||||
glm::vec2 mousepos = Global.cursor_pos;
|
||||
mousepos.y = Global.window_size.y - mousepos.y; // cursor coordinates are flipped compared to opengl
|
||||
glm::ivec2 const extent{Global.gfx_framebuffer_width, Global.gfx_framebuffer_height};
|
||||
auto bufferpos{glm::ivec2(mousepos * glm::vec2(extent) / glm::max(glm::vec2(Global.window_size), glm::vec2(1.f)))};
|
||||
bufferpos = glm::clamp(bufferpos, glm::ivec2(0, 0), extent - 1);
|
||||
// the pixels around the one under the cursor too, for the slope of the depth there
|
||||
auto const blocksize{glm::clamp(extent, glm::ivec2(1), glm::ivec2(3))};
|
||||
auto const blockcorner{glm::clamp(bufferpos - 1, glm::ivec2(0), extent - blocksize)};
|
||||
|
||||
if (!Global.iMultisampling)
|
||||
{
|
||||
m_depth_pointer_pbo->request_read(bufferpos.x, bufferpos.y, 1, 1, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
m_depth_pointer_pbo->request_read(blockcorner.x, blockcorner.y, blocksize.x, blocksize.y, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
}
|
||||
else if (Global.gfx_skippipeline)
|
||||
{
|
||||
gl::framebuffer::blit(nullptr, m_depth_pointer_fb.get(), bufferpos.x, bufferpos.y, 1, 1, GL_DEPTH_BUFFER_BIT, 0);
|
||||
gl::framebuffer::blit(nullptr, m_depth_pointer_fb.get(), blockcorner.x, blockcorner.y, blocksize.x, blocksize.y, GL_DEPTH_BUFFER_BIT, 0);
|
||||
|
||||
m_depth_pointer_fb->bind();
|
||||
m_depth_pointer_pbo->request_read(0, 0, 1, 1, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
m_depth_pointer_pbo->request_read(0, 0, blocksize.x, blocksize.y, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
m_depth_pointer_fb->unbind();
|
||||
}
|
||||
else
|
||||
{
|
||||
gl::framebuffer::blit(m_viewports.front()->msaa_fb.get(), m_depth_pointer_fb.get(), bufferpos.x, bufferpos.y, 1, 1, GL_DEPTH_BUFFER_BIT, 0);
|
||||
gl::framebuffer::blit(m_viewports.front()->msaa_fb.get(), m_depth_pointer_fb.get(), blockcorner.x, blockcorner.y, blocksize.x, blocksize.y, GL_DEPTH_BUFFER_BIT, 0);
|
||||
|
||||
m_depth_pointer_fb->bind();
|
||||
m_depth_pointer_pbo->request_read(0, 0, 1, 1, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
m_depth_pointer_pbo->request_read(0, 0, blocksize.x, blocksize.y, 4, GL_DEPTH_COMPONENT, GL_FLOAT);
|
||||
m_viewports.front()->msaa_fb->bind();
|
||||
}
|
||||
|
||||
if (pointdepth != std::numeric_limits<float>::max())
|
||||
{
|
||||
m_mousehit = pointdepth > 0.0f;
|
||||
if (pointdepth > 0.0f)
|
||||
m_worldmousecoordinates = glm::unProjectZO(glm::vec3(bufferpos, pointdepth), glm::mat4(glm::mat3(m_colorpass.pass_camera.modelview())), m_colorpass.pass_camera.projection(),
|
||||
glm::vec4(0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height));
|
||||
}
|
||||
// and the view it's drawn in, for when the depths come back
|
||||
m_cursorposition = bufferpos;
|
||||
m_cursorblockcorner = blockcorner;
|
||||
m_cursorblocksize = blocksize;
|
||||
m_cursorbiased = m_scenedepthpass;
|
||||
m_cursorview = glm::mat4(glm::mat3(m_colorpass.pass_camera.modelview()));
|
||||
m_cursorprojection = m_colorpass.pass_camera.projection();
|
||||
m_cursorcamera = m_colorpass.pass_camera.position();
|
||||
m_cursorviewport = glm::vec4(0, 0, extent.x, extent.y);
|
||||
}
|
||||
|
||||
return m_colorpass.pass_camera.position() + glm::dvec3{m_worldmousecoordinates};
|
||||
return m_colorpass.pass_camera.position() + Mouse_Position();
|
||||
}
|
||||
|
||||
void opengl46_renderer::Update(double const Deltatime)
|
||||
|
||||
@@ -150,7 +150,7 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
|
||||
void
|
||||
Forget_Node( scene::basic_node const *Node ) override;
|
||||
glm::dvec3
|
||||
Mouse_Position() const override { return m_worldmousecoordinates; }
|
||||
Mouse_Position() const override { return m_mouseknown ? m_worldmouseposition - m_colorpass.pass_camera.position() : glm::dvec3 { 0.0 }; }
|
||||
bool
|
||||
Mouse_Hit() const override { return m_mousehit; }
|
||||
glm::mat4
|
||||
@@ -748,8 +748,20 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
|
||||
std::array<renderpass_config, 3> m_shadowpass; // parametrs of most recent shadowmap pass for each of csm stages
|
||||
TSubModel const *m_pickcontrolitem{nullptr};
|
||||
scene::basic_node *m_picksceneryitem{nullptr};
|
||||
glm::vec3 m_worldmousecoordinates { 0.f };
|
||||
// the point of the scene under the cursor of the editor, in world space (Update_Mouse_Position())
|
||||
glm::dvec3 m_worldmouseposition { 0.0 };
|
||||
bool m_mouseknown { false }; // whether the cursor hit anything yet
|
||||
bool m_mousehit { false };
|
||||
// the depths around the cursor asked of the gpu: where they lie in the image, whether they come from the depth pass of the
|
||||
// scene (drawn a little farther than it lies), and the view they were drawn in
|
||||
glm::ivec2 m_cursorposition { 0 };
|
||||
glm::ivec2 m_cursorblockcorner { 0 };
|
||||
glm::ivec2 m_cursorblocksize { 0 };
|
||||
bool m_cursorbiased { false };
|
||||
glm::mat4 m_cursorview { 1.f };
|
||||
glm::mat4 m_cursorprojection { 1.f };
|
||||
glm::dvec3 m_cursorcamera { 0.0 };
|
||||
glm::vec4 m_cursorviewport { 0.f };
|
||||
#ifdef EU07_USE_DEBUG_CAMERA
|
||||
renderpass_config m_worldcamera; // debug item
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user