Skip to content

Commit

Permalink
LinesDrawable2D for drawing lines in the screen space
Browse files Browse the repository at this point in the history
  • Loading branch information
LiangliangNan committed Dec 31, 2024
1 parent 1602371 commit 10424da
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 144 deletions.
2 changes: 1 addition & 1 deletion applications/FigureMaker/viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ namespace easy3d {

bool FigureMaker::key_press_event(int key, int modifiers) {
if (key == KEY_D)
set_division_visible(!division_visible_);
set_division_visible(!division_visible());
else if (key == KEY_L) {
for (const auto model : models_) {
const auto& tri_drawables = model->renderer()->triangles_drawables();
Expand Down
2 changes: 2 additions & 0 deletions easy3d/renderer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(${module}_headers
constraint.h
drawable.h
drawable_lines.h
drawable_lines_2D.h
drawable_points.h
drawable_triangles.h
dual_depth_peeling.h
Expand Down Expand Up @@ -51,6 +52,7 @@ set(${module}_sources
constraint.cpp
drawable.cpp
drawable_lines.cpp
drawable_lines_2D.cpp
drawable_points.cpp
drawable_triangles.cpp
dual_depth_peeling.cpp
Expand Down
2 changes: 1 addition & 1 deletion easy3d/renderer/drawable_lines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ namespace easy3d {
}


void LinesDrawable::draw(const Camera *camera /* = false */) const {
void LinesDrawable::draw(const Camera *camera) const {
if (update_needed_ || vertex_buffer_ == 0) {
const_cast<LinesDrawable *>(this)->update_buffers_internal();
const_cast<LinesDrawable *>(this)->update_needed_ = false;
Expand Down
98 changes: 98 additions & 0 deletions easy3d/renderer/drawable_lines_2D.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/********************************************************************
* Copyright (C) 2015 Liangliang Nan <[email protected]>
* https://3d.bk.tudelft.nl/liangliang/
*
* This file is part of Easy3D. If it is useful in your research/work,
* I would be grateful if you show your appreciation by citing it:
* ------------------------------------------------------------------
* Liangliang Nan.
* Easy3D: a lightweight, easy-to-use, and efficient C++ library
* for processing and rendering 3D data.
* Journal of Open Source Software, 6(64), 3255, 2021.
* ------------------------------------------------------------------
*
* Easy3D is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 3
* as published by the Free Software Foundation.
*
* Easy3D is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
********************************************************************/

#include <easy3d/renderer/drawable_lines_2D.h>
#include <easy3d/renderer/vertex_array_object.h>
#include <easy3d/renderer/shader_program.h>
#include <easy3d/renderer/shader_manager.h>
#include <easy3d/renderer/opengl_error.h>


namespace easy3d {


LinesDrawable2D::LinesDrawable2D(const std::string &name)
: Drawable(name, nullptr)
{
set_uniform_coloring(vec4(0.0f, 0.0f, 1.0f, 1.0f));
}


Drawable::Type LinesDrawable2D::type() const {
return DT_LINES;
}


void LinesDrawable2D::update_vertex_buffer(const std::vector<vec2> &vertices, int width, int height, bool dynamic) {
assert(vao_);

// convert from screen coordinates to Normalized Device Coordinates (NDC)
std::vector<vec2> points(vertices.size());
for (std::size_t i = 0; i < vertices.size(); ++i) {
const vec2 &p = vertices[i];
const float x = 2.0f * p.x / static_cast<float>(width) - 1.0f;
const float y = 1.0f - 2.0f * p.y / static_cast<float>(height);
points[i] = vec2(x, y);
}
bool success = vao_->create_array_buffer(vertex_buffer_, ShaderProgram::POSITION, points.data(),
points.size() * sizeof(vec2), 2, dynamic);
LOG_IF(!success, ERROR) << "failed creating vertex buffer";
num_vertices_ = success ? points.size() : 0;
}


void LinesDrawable2D::draw(const Camera *camera) const {
if (update_needed_ || vertex_buffer_ == 0) {
const_cast<LinesDrawable2D *>(this)->update_buffers_internal();
const_cast<LinesDrawable2D *>(this)->update_needed_ = false;
}

// create the shader program for visualizing the dividing lines
const std::string name = "screen_space/screen_space_color";
ShaderProgram *program = ShaderManager::get_program(name);
if (!program) {
std::vector<ShaderProgram::Attribute> attributes = {
ShaderProgram::Attribute(ShaderProgram::POSITION, "ndc_position")
};
program = ShaderManager::create_program_from_files(name, attributes);
}
if (!program) {
LOG(ERROR) << "shader doesn't exist: " << name;
return;
}

const float depth = -1.0f; // on top of everything
program->bind();
program->set_uniform("screen_color", color_);
program->set_uniform("depth", depth);
vao_->bind();
glDrawArrays(GL_LINES, 0, static_cast<int>(num_vertices_));
vao_->release();
program->release();
easy3d_debug_log_gl_error
}

}
69 changes: 69 additions & 0 deletions easy3d/renderer/drawable_lines_2D.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/********************************************************************
* Copyright (C) 2015 Liangliang Nan <[email protected]>
* https://3d.bk.tudelft.nl/liangliang/
*
* This file is part of Easy3D. If it is useful in your research/work,
* I would be grateful if you show your appreciation by citing it:
* ------------------------------------------------------------------
* Liangliang Nan.
* Easy3D: a lightweight, easy-to-use, and efficient C++ library
* for processing and rendering 3D data.
* Journal of Open Source Software, 6(64), 3255, 2021.
* ------------------------------------------------------------------
*
* Easy3D is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 3
* as published by the Free Software Foundation.
*
* Easy3D is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
********************************************************************/

#ifndef EASY3D_RENDERER_DRAWABLE_LINES_2D_H
#define EASY3D_RENDERER_DRAWABLE_LINES_2D_H

#include <easy3d/renderer/drawable.h>


namespace easy3d {

/**
* \brief The drawable for rendering a set of line segments in the screen space.
* \details This drawable is used to render a set of line segments in the screen space, e.g., the pivot mark.
* Line width, imposter, texturing, per-element color, and scalar attributes are not implemented given
* the limited usage cases.
* \class LinesDrawable2D easy3d/renderer/drawable_lines_2D.h
* \see LinesDrawable the 3D version of lines drawables.
*/
class LinesDrawable2D : public Drawable {
public:
explicit LinesDrawable2D(const std::string& name = "");

Type type() const override;

// Rendering.
void draw(const Camera* camera) const override;

/**
* \brief Creates/Updates the vertex buffer.
* \param vertices The vertices of the line segments, represented in screen coordinates.
* \param width The width of the screen/viewport.
* \param height The height of the screen/viewport.
* \param dynamic If true, the buffer is dynamic and can be updated.
* \attention In the current implementation, each pair of consecutive vertices represent a line. Thus for
* polylines or polygons, the shared vertices has to be duplicated in the vertex buffer. This is not
* optimal in terms of memory usage, but it is easier to implement and use.
* For a more memory efficient implementation, an element buffer should be used.
*/
void update_vertex_buffer(const std::vector<vec2> &vertices, int width, int height, bool dynamic = false);
};

}


#endif // EASY3D_RENDERER_DRAWABLE_LINES_2D_H
2 changes: 1 addition & 1 deletion easy3d/renderer/drawable_points.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace easy3d {
}


void PointsDrawable::draw(const Camera *camera /* = false */) const {
void PointsDrawable::draw(const Camera *camera) const {
if (update_needed_ || vertex_buffer_ == 0) {
const_cast<PointsDrawable *>(this)->update_buffers_internal();
const_cast<PointsDrawable *>(this)->update_needed_ = false;
Expand Down
2 changes: 1 addition & 1 deletion easy3d/util/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace easy3d {
#define EASY3D_VERSION_NR 1020504

/// Easy3D release date, in the format YYYYMMDD.
#define EASY3D_RELEASE_DATE 20241230
#define EASY3D_RELEASE_DATE 20241231


#endif // EASY3D_UTIL_VERSION_H
92 changes: 29 additions & 63 deletions easy3d/viewer/multi_viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,12 @@
#include <easy3d/viewer/multi_viewer.h>
#include <easy3d/core/model.h>
#include <easy3d/renderer/opengl.h>
#include <easy3d/renderer/opengl_error.h>
#include <easy3d/renderer/vertex_array_object.h>
#include <easy3d/renderer/drawable_lines.h>
#include <easy3d/renderer/drawable_lines_2D.h>
#include <easy3d/renderer/drawable_points.h>
#include <easy3d/renderer/drawable_triangles.h>
#include <easy3d/renderer/shader_program.h>
#include <easy3d/renderer/shader_manager.h>
#include <easy3d/renderer/renderer.h>
#include <easy3d/renderer/camera.h>
#include <easy3d/renderer/manipulated_camera_frame.h>
#include <easy3d/renderer/framebuffer_object.h>
#include <easy3d/renderer/clipping_plane.h>
#include <easy3d/util/file_system.h>
Expand All @@ -48,17 +44,14 @@ namespace easy3d {

MultiViewer::MultiViewer(int rows, int cols, const std::string &title)
: Viewer(title)
, lines_program_(nullptr)
, division_vertex_buffer_(0)
, division_visible_(true)
{

set_layout(rows, cols);
}


MultiViewer::~MultiViewer() {
VertexArrayObject::release_buffer(division_vertex_buffer_);
division_vao_.reset();
drawable_division_.reset();
// Not needed: it will be called in the destructor of the base class
// Viewer::cleanup();
}
Expand Down Expand Up @@ -160,25 +153,24 @@ namespace easy3d {
}


void MultiViewer::set_division_visible(bool b) {
if (drawable_division_)
drawable_division_->set_visible(b);
}


bool MultiViewer::division_visible() const {
if (drawable_division_)
return drawable_division_->is_visible();
return false;
}


void MultiViewer::init() {
Viewer::init();

// compute the division
update_division();

// create the shader program for visualizing the dividing lines
const std::string name = "screen_space/screen_space_color";
lines_program_ = ShaderManager::get_program(name);
if (!lines_program_) {
std::vector<ShaderProgram::Attribute> attributes = {
ShaderProgram::Attribute(ShaderProgram::POSITION, "ndc_position")
};
lines_program_ = ShaderManager::create_program_from_files(name, attributes);
}
if (!lines_program_) {
LOG(ERROR) << "shader doesn't exist: " << name;
return;
}
}


Expand Down Expand Up @@ -241,25 +233,8 @@ namespace easy3d {
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);

// draw the division of views
if (division_visible_)
draw_division();
}


void MultiViewer::draw_division() const {
if (!lines_program_)
return;

const float depth = -1.0f;
lines_program_->bind();
lines_program_->set_uniform("screen_color", vec4(0, 0, 0, 1.0f));
lines_program_->set_uniform("depth", depth);
division_vao_->bind();
const unsigned int vertex_count = (num_rows_ - 1) * 2 + (num_cols_ - 1) * 2;
glDrawArrays(GL_LINES, 0, static_cast<int>(vertex_count));
division_vao_->release();
lines_program_->release();
easy3d_debug_log_gl_error
if (drawable_division_->is_visible())
drawable_division_->draw(camera());
}


Expand All @@ -272,8 +247,8 @@ namespace easy3d {
if (views_.empty() || views_[0].empty())
return;

if (!division_vao_)
division_vao_ = std::unique_ptr<VertexArrayObject>(new VertexArrayObject);
if (!drawable_division_)
drawable_division_ = std::unique_ptr<LinesDrawable2D>(new LinesDrawable2D("division"));

view_width_ = static_cast<int>(static_cast<float>(width()) / static_cast<float>(num_cols_));
view_height_ = static_cast<int>(static_cast<float>(height()) / static_cast<float>(num_rows_));
Expand All @@ -296,21 +271,20 @@ namespace easy3d {

// ------------------------------------------------------------

// Note: we need NDC
// Update the vertex buffer for the division drawable.
// Each pair of consecutive points (screen coordinates) represent a line.
std::vector<vec2> points;
for (std::size_t i = 1; i < num_rows_; ++i) {
const float y = 2.0f * static_cast<float>(i * view_height_) / static_cast<float>(height()) - 1.0f;
points.emplace_back(vec2(-1.0f, y));
points.emplace_back(vec2(1.0f, y));
const float y = i * view_height_;
points.emplace_back(vec2(0, y));
points.emplace_back(vec2(width(), y));
}
for (std::size_t i = 1; i < num_cols_; ++i) {
const float x = 2.0f * static_cast<float>(i * view_width_) / static_cast<float>(width()) - 1.0f;
points.emplace_back(vec2(x, -1.0f));
points.emplace_back(vec2(x, 1.0f));
const float x = i * view_width_;
points.emplace_back(vec2(x, 0));
points.emplace_back(vec2(x, height()));
}
division_vao_->create_array_buffer(division_vertex_buffer_, ShaderProgram::POSITION, points.data(),
points.size() * sizeof(vec2), 2, true);
easy3d_debug_log_gl_error
drawable_division_->update_vertex_buffer(points, width(), height(), true);
}


Expand Down Expand Up @@ -341,14 +315,6 @@ namespace easy3d {
}


bool MultiViewer::mouse_press_event(int x, int y, int button, int modifiers) {
// This re-implementation does nothing extra but just hides the pivot point.
bool result = Viewer::mouse_press_event(x, y, button, modifiers);
show_pivot_point_ = false;
return result;
}


bool MultiViewer::mouse_release_event(int x, int y, int button, int modifiers) {
// make the mouse position relative to the current view
x %= view_width_;
Expand Down
Loading

0 comments on commit 10424da

Please sign in to comment.