From 56e9fa537b1ddbde6275330817bc91cf70b509da Mon Sep 17 00:00:00 2001 From: milek7 Date: Wed, 24 Oct 2018 18:25:29 +0200 Subject: [PATCH] restore depth based world mouse position --- gl/framebuffer.cpp | 40 +++++--- gl/framebuffer.h | 6 +- gl/pbo.cpp | 10 +- gl/pbo.h | 4 +- map.cpp | 2 +- renderer.cpp | 175 ++++++++++++++++++++++++++++----- renderer.h | 9 +- shaders/gles_depthpointer.frag | 11 +++ 8 files changed, 205 insertions(+), 52 deletions(-) create mode 100644 shaders/gles_depthpointer.frag diff --git a/gl/framebuffer.cpp b/gl/framebuffer.cpp index 4748ae5d..6c347ab9 100644 --- a/gl/framebuffer.cpp +++ b/gl/framebuffer.cpp @@ -55,26 +55,34 @@ void gl::framebuffer::clear(GLbitfield mask) glClear(mask); } -void gl::framebuffer::blit_to(framebuffer &other, int w, int h, GLbitfield mask, GLenum attachment) +void gl::framebuffer::blit_to(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, *this); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, other); - - int attachment_n = attachment - GL_COLOR_ATTACHMENT0; - - GLenum outputs[8] = { GL_NONE }; - outputs[attachment_n] = attachment; - - glReadBuffer(attachment); - glDrawBuffers(attachment_n + 1, outputs); - - glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST); - unbind(); + blit(this, other, 0, 0, w, h, mask, attachment); } -void gl::framebuffer::blit_from(framebuffer &other, int w, int h, GLbitfield mask, GLenum attachment) +void gl::framebuffer::blit_from(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment) { - other.blit_to(*this, w, h, mask, attachment); + blit(other, this, 0, 0, w, h, mask, attachment); +} + +void gl::framebuffer::blit(framebuffer *src, framebuffer *dst, int sx, int sy, int w, int h, GLbitfield mask, GLenum attachment) +{ + glBindFramebuffer(GL_READ_FRAMEBUFFER, src ? *src : 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst ? *dst : 0); + + if (mask & GL_COLOR_BUFFER_BIT) + { + int attachment_n = attachment - GL_COLOR_ATTACHMENT0; + + GLenum outputs[8] = { GL_NONE }; + outputs[attachment_n] = attachment; + + glReadBuffer(attachment); + glDrawBuffers(attachment_n + 1, outputs); + } + + glBlitFramebuffer(sx, sy, sx + w, sy + h, 0, 0, w, h, mask, GL_NEAREST); + unbind(); } void gl::framebuffer::setup_drawing(int attachments) diff --git a/gl/framebuffer.h b/gl/framebuffer.h index 77869727..37bdefc2 100644 --- a/gl/framebuffer.h +++ b/gl/framebuffer.h @@ -22,8 +22,10 @@ namespace gl void clear(GLbitfield mask); bool is_complete(); - void blit_to(framebuffer &other, int w, int h, GLbitfield mask, GLenum attachment); - void blit_from(framebuffer &other, int w, int h, GLbitfield mask, GLenum attachment); + void blit_to(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment); + void blit_from(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment); + + static void blit(framebuffer *src, framebuffer *dst, int sx, int sy, int w, int h, GLbitfield mask, GLenum attachment); using bindable::bind; static void bind(GLuint id); diff --git a/gl/pbo.cpp b/gl/pbo.cpp index ae6a7f4e..18c2f8b3 100644 --- a/gl/pbo.cpp +++ b/gl/pbo.cpp @@ -1,8 +1,8 @@ #include "pbo.h" -void gl::pbo::request_read(int x, int y, int lx, int ly) +void gl::pbo::request_read(int x, int y, int lx, int ly, int pixsize, GLenum format, GLenum type) { - int s = lx * ly * 4; + int s = lx * ly * pixsize; if (s != size) allocate(PIXEL_PACK_BUFFER, s, GL_STREAM_DRAW); size = s; @@ -11,20 +11,20 @@ void gl::pbo::request_read(int x, int y, int lx, int ly) sync.reset(); bind(PIXEL_PACK_BUFFER); - glReadPixels(x, y, lx, ly, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glReadPixels(x, y, lx, ly, format, type, 0); unbind(PIXEL_PACK_BUFFER); sync.emplace(); } -bool gl::pbo::read_data(int lx, int ly, uint8_t *data) +bool gl::pbo::read_data(int lx, int ly, void *data, int pixsize) { is_busy(); if (!data_ready) return false; - int s = lx * ly * 4; + int s = lx * ly * pixsize; if (s != size) return false; diff --git a/gl/pbo.h b/gl/pbo.h index 5a58b5b3..be7bf9bf 100644 --- a/gl/pbo.h +++ b/gl/pbo.h @@ -10,8 +10,8 @@ namespace gl { bool data_ready; public: - void request_read(int x, int y, int lx, int ly); - bool read_data(int lx, int ly, uint8_t *data); + void request_read(int x, int y, int lx, int ly, int pixsize = 4, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE); + bool read_data(int lx, int ly, void *data, int pixsize = 4); bool is_busy(); }; } diff --git a/map.cpp b/map.cpp index debf145d..102f0603 100644 --- a/map.cpp +++ b/map.cpp @@ -166,7 +166,7 @@ void map::render(scene::basic_region *Region) GfxRenderer.Draw_Geometry(m_section_handles.begin(), m_section_handles.end()); if (Global.iMultisampling) - m_fb->blit_from(*m_msaa_fb, size.x, size.y, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0); + m_fb->blit_from(m_msaa_fb.get(), size.x, size.y, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0); gl::framebuffer::unbind(); m_shader->unbind(); diff --git a/renderer.cpp b/renderer.cpp index b71e67bc..3c84bb7b 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -161,6 +161,8 @@ bool opengl_renderer::Init(GLFWwindow *Window) m_pick_shader = make_shader("vertexonly.vert", "pick.frag"); m_billboard_shader = make_shader("simpleuv.vert", "billboard.frag"); m_celestial_shader = make_shader("celestial.vert", "celestial.frag"); + if (Global.gfx_usegles) + m_depth_pointer_shader = make_shader("quad.vert", "gles_depthpointer.frag"); m_invalid_material = Fetch_Material("invalid"); } catch (gl::shader_exception const &e) @@ -296,7 +298,59 @@ bool opengl_renderer::Init(GLFWwindow *Window) m_picking_pbo = std::make_unique(); m_picking_node_pbo = std::make_unique(); - WriteLog("picking pbos created"); + + m_depth_pointer_pbo = std::make_unique(); + if (!Global.gfx_usegles && Global.iMultisampling) + { + m_depth_pointer_rb = std::make_unique(); + m_depth_pointer_rb->alloc(Global.gfx_format_depth, 1, 1); + + m_depth_pointer_fb = std::make_unique(); + m_depth_pointer_fb->attach(*m_depth_pointer_rb, GL_DEPTH_ATTACHMENT); + + if (!m_depth_pointer_fb->is_complete()) + return false; + } + else if (Global.gfx_usegles) + { + m_depth_pointer_tex = std::make_unique(); + + GLenum format = Global.gfx_format_depth; + if (Global.gfx_skippipeline) + { + gl::framebuffer::unbind(); + GLint bits, type; + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, &bits); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH, GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE, &type); + if (type == GL_FLOAT && bits == 32) + format = GL_DEPTH_COMPONENT32F; + else if (bits == 16) + format = GL_DEPTH_COMPONENT16; + else if (bits == 24) + format = GL_DEPTH_COMPONENT24; + else if (bits == 32) + format = GL_DEPTH_COMPONENT32; + } + + m_depth_pointer_tex->alloc_rendertarget(format, GL_DEPTH_COMPONENT, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height); + + m_depth_pointer_rb = std::make_unique(); + m_depth_pointer_rb->alloc(GL_R16UI, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height); + + m_depth_pointer_fb = std::make_unique(); + m_depth_pointer_fb->attach(*m_depth_pointer_tex, GL_DEPTH_ATTACHMENT); + + m_depth_pointer_fb2 = std::make_unique(); + m_depth_pointer_fb2->attach(*m_depth_pointer_rb, GL_COLOR_ATTACHMENT0); + + if (!m_depth_pointer_fb->is_complete()) + return false; + + if (!m_depth_pointer_fb2->is_complete()) + return false; + } + + WriteLog("picking objects created"); WriteLog("renderer initialization finished!"); @@ -555,8 +609,8 @@ void opengl_renderer::Render_pass(rendermode const Mode) if (Global.gfx_postfx_motionblur_enabled) { m_main_fb->clear(GL_COLOR_BUFFER_BIT); - m_msaa_fb->blit_to(*m_main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0); - m_msaa_fb->blit_to(*m_main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT1); + m_msaa_fb->blit_to(m_main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0); + m_msaa_fb->blit_to(m_main_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT1); model_ubs.param[0].x = m_framerate / (1.0 / Global.gfx_postfx_motionblur_shutter); model_ubo->update(model_ubs); @@ -565,7 +619,7 @@ void opengl_renderer::Render_pass(rendermode const Mode) else { m_main2_fb->clear(GL_COLOR_BUFFER_BIT); - m_msaa_fb->blit_to(*m_main2_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0); + m_msaa_fb->blit_to(m_main2_fb.get(), Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_COLOR_BUFFER_BIT, GL_COLOR_ATTACHMENT0); } if (!Global.gfx_usegles && !Global.gfx_shadergamma) @@ -1587,7 +1641,7 @@ void opengl_renderer::Render(scene::basic_region *Region) { // when editor mode is active calculate world position of the cursor // at this stage the z-buffer is filled with only ground geometry - Update_Mouse_Position(); + get_mouse_depth(); } Render(std::begin(m_cellqueue), std::end(m_cellqueue)); break; @@ -3411,7 +3465,7 @@ void opengl_renderer::Update_Pick_Node() m_node_pick_requests.clear(); } - if (!m_picking_node_pbo->is_busy()) + if (!m_node_pick_requests.empty()) { // determine point to examine glm::dvec2 mousepos = Application.get_cursor_pos(); @@ -3439,29 +3493,100 @@ void opengl_renderer::pick_node(std::function callbac m_node_pick_requests.push_back(callback); } -glm::dvec3 opengl_renderer::Update_Mouse_Position() +glm::dvec3 opengl_renderer::get_mouse_depth() { - // m7t: we need to blit multisampled framebuffer into regular one - // and better to use PBO and wait frame or two to improve performance - /* - glm::dvec2 mousepos; - glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y ); - mousepos = glm::ivec2{mousepos.x * Global.render_width / std::max(1, Global.iWindowWidth), mousepos.y * Global.render_height / std::max(1, Global.iWindowHeight)}; - GLfloat pointdepth; - ::glReadPixels( mousepos.x, mousepos.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pointdepth ); + if (!m_depth_pointer_pbo->is_busy()) + { + // determine point to examine + glm::dvec2 mousepos = Application.get_cursor_pos(); + mousepos.y = Global.iWindowHeight - mousepos.y; // cursor coordinates are flipped compared to opengl - if( pointdepth < 1.0 ) { - m_worldmousecoordinates = - glm::unProject( - glm::vec3{ mousepos, pointdepth }, - glm::mat4{ glm::mat3{ m_colorpass.camera.modelview() } }, - m_colorpass.camera.projection(), - glm::vec4{ 0, 0, Global.render_width, Global.render_height } ); + glm::ivec2 bufferpos; + bufferpos = glm::ivec2{mousepos.x * Global.gfx_framebuffer_width / std::max(1, Global.iWindowWidth), + mousepos.y * Global.gfx_framebuffer_height / std::max(1, Global.iWindowHeight)}; + 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::max(); + + if (!Global.gfx_usegles) + { + m_depth_pointer_pbo->read_data(1, 1, &pointdepth, 4); + + if (!Global.iMultisampling) + { + m_depth_pointer_pbo->request_read(bufferpos.x, bufferpos.y, 1, 1, 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); + + m_depth_pointer_fb->bind(); + m_depth_pointer_pbo->request_read(0, 0, 1, 1, 4, GL_DEPTH_COMPONENT, GL_FLOAT); + m_depth_pointer_fb->unbind(); + } + else + { + gl::framebuffer::blit(m_msaa_fb.get(), m_depth_pointer_fb.get(), bufferpos.x, bufferpos.y, 1, 1, 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_msaa_fb->bind(); + } + } + else + { + unsigned int data[4]; + if (m_depth_pointer_pbo->read_data(1, 1, data, 16)) + pointdepth = (double)data[0] / 65535.0; + + if (Global.gfx_skippipeline) + { + gl::framebuffer::blit(nullptr, m_depth_pointer_fb.get(), 0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_DEPTH_BUFFER_BIT, 0); + + m_empty_vao->bind(); + m_depth_pointer_tex->bind(0); + m_depth_pointer_shader->bind(); + m_depth_pointer_fb2->bind(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_depth_pointer_pbo->request_read(bufferpos.x, bufferpos.y, 1, 1, 16, GL_RGBA_INTEGER, GL_UNSIGNED_INT); + m_depth_pointer_shader->unbind(); + m_empty_vao->unbind(); + m_depth_pointer_fb2->unbind(); + } + else + { + gl::framebuffer::blit(m_msaa_fb.get(), m_depth_pointer_fb.get(), 0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height, GL_DEPTH_BUFFER_BIT, 0); + + m_empty_vao->bind(); + m_depth_pointer_tex->bind(0); + m_depth_pointer_shader->bind(); + m_depth_pointer_fb2->bind(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_depth_pointer_pbo->request_read(bufferpos.x, bufferpos.y, 1, 1, 16, GL_RGBA_INTEGER, GL_UNSIGNED_INT); + m_depth_pointer_shader->unbind(); + m_empty_vao->unbind(); + m_msaa_fb->bind(); + } } - return m_colorpass.camera.position() + glm::dvec3{ m_worldmousecoordinates }; - */ - return glm::dvec3(); + if (pointdepth != std::numeric_limits::max()) + { + if (GLAD_GL_ARB_clip_control || GLAD_GL_EXT_clip_control) + m_worldmousecoordinates = glm::unProjectZO( + glm::vec3(bufferpos, pointdepth), + glm::mat4(glm::mat3(m_colorpass.camera.modelview())), + m_colorpass.camera.projection(), + glm::vec4(0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height)); + else + m_worldmousecoordinates = glm::unProjectNO( + glm::vec3(bufferpos, pointdepth), + glm::mat4(glm::mat3(m_colorpass.camera.modelview())), + m_colorpass.camera.projection(), + glm::vec4(0, 0, Global.gfx_framebuffer_width, Global.gfx_framebuffer_height)); + } + } + + return m_colorpass.camera.position() + glm::dvec3{ m_worldmousecoordinates }; } void opengl_renderer::Update(double const Deltatime) diff --git a/renderer.h b/renderer.h index f924c167..05a8554c 100644 --- a/renderer.h +++ b/renderer.h @@ -182,7 +182,7 @@ class opengl_renderer void Update(double const Deltatime); void Update_Pick_Control(); void Update_Pick_Node(); - glm::dvec3 Update_Mouse_Position(); + glm::dvec3 get_mouse_depth(); // debug methods std::string const &info_times() const; std::string const &info_stats() const; @@ -399,6 +399,13 @@ class opengl_renderer std::unique_ptr m_picking_pbo; std::unique_ptr m_picking_node_pbo; + std::unique_ptr m_depth_pointer_pbo; + std::unique_ptr m_depth_pointer_fb; + std::unique_ptr m_depth_pointer_fb2; + std::unique_ptr m_depth_pointer_rb; + std::unique_ptr m_depth_pointer_tex; + std::unique_ptr m_depth_pointer_shader; + material_handle m_invalid_material; bool m_blendingenabled; diff --git a/shaders/gles_depthpointer.frag b/shaders/gles_depthpointer.frag new file mode 100644 index 00000000..42b9cb60 --- /dev/null +++ b/shaders/gles_depthpointer.frag @@ -0,0 +1,11 @@ +in vec2 f_coords; + +#texture (tex1, 0, R) +uniform sampler2D tex1; + +layout(location = 0) out uvec4 out_color; + +void main() +{ + out_color = uvec4(uint(texture(tex1, f_coords).r * 65535.0), 0, 0, 0xFFFF); +}