LiangliangNan / Easy3D

A lightweight, easy-to-use, and efficient C++ library for processing and rendering 3D data
GNU General Public License v3.0
1.37k stars 246 forks source link

updating model in real time #19

Closed alior101 closed 5 years ago

alior101 commented 5 years ago

Hi, Is there a way to

  1. receive timer interrupt similar to key press events ?
  2. update the model in RT and update the GPU to enable simple animations ?

Thanks

LiangliangNan commented 5 years ago

receive timer interrupt similar to key press events ?

you can schedule functions calls using the "Timer" class implemented in "easy3d/util/timer.h". Check the examples here: https://github.com/LiangliangNan/Timer

update the model in RT and update the GPU to enable simple animations ?

For animation, you can call drawable->update_vertex_buffer(...); every time when your geometry changes, followed by the viewer's update(). For the speed, use the timer functions to schedule the frequency for updating the GPU.

alior101 commented 5 years ago

Hi! I followed your advice and set up a timer callback which works fine. I tried to change the color of a simple point cloud (that I created in the main function before calling viewer.run() ) inside that callback. Unfortunatly, as soon as I call update_color_buffer, all points turns green .. Any idea what I'm doing wrong ? (sorry for the lack of code markdown - I replied mistakenly by email...) Thanks

` bool ViewerImGui::callback_event_timer() { printf("booya!\n"); easy3d::Model* model = this->current_model(); if (model) { auto drawable = model->points_drawable("lior"); drawable->set_point_size(25.0f);

easy3d::PointCloud cloud = dynamic_cast<PointCloud>(model);

PointCloud::VertexProperty colors = cloud->get_vertex_property( "v:color");

for (auto v : cloud->vertices()) // iterate over all vertices { colors[v] = random_color(); // assign a random color to point 'v' } drawable->update_color_buffer(colors.vector());

update(); } return true; } `

LiangliangNan commented 5 years ago

call drawable->set_per_vertex_color(true); // vertices have different colors before update();

also, all OpenGL/GPU related code must be called after the creation of the viewer (otherwise OpenGL context doesn't exist).

alior101 commented 5 years ago

I Added the drawable->set_per_vertex_color(true); before update() but got the sample all points turning green results. I'm using tutorial_302_viewer_imgui as a basis and the viewer is created and init the first two lines of main() before all opengl/gpu code.. Any other suggestion ?

LiangliangNan commented 5 years ago

can you post your code here?

alior101 commented 5 years ago

vec3 random_color() {
    float r = rand() % 255 / 255.0f;    // in the range [0, 1]
    float g = rand() % 255 / 255.0f;    // in the range [0, 1]
    float b = rand() % 255 / 255.0f;    // in the range [0, 1]
    return vec3(r, g, b);
}

int main(int argc, char** argv) {
    try {

        ViewerImGui viewer("Easy3D ImGui Viewer", 80, 3, 2);

        viewer.resize(800, 600);

        Timer t; 

        #if 1
            PointCloud* cloud = new PointCloud;

            for (float i=-5; i<5; ++i) {
                for (float j = -5; j < 5; ++j) 
                {
                    cloud->add_vertex(vec3(i, j, 0));// z = 0: all points are on XY plane
                    cloud->add_vertex(vec3(i, j, 4));// z = 0: all points are on XY plane
                }           
            }

            auto vertices = cloud->get_vertex_property<vec3>("v:point");
            // All the XYZ coordinates
            auto colors = cloud->add_vertex_property<vec3>("v:color");

            const auto& points = vertices.vector();

            for (auto v : cloud->vertices())    // iterate over all vertices
                colors[v] = random_color();     // assign a random color to point 'v'

            PointsDrawable* points_drawable =  cloud->add_points_drawable("lior"); // cloud->points_drawable("vertices");
            points_drawable->set_point_size(6.0f);

            points_drawable->update_vertex_buffer(points);
            points_drawable->update_color_buffer(colors.vector());
            points_drawable->set_per_vertex_color(true);
            points_drawable->set_visible(true);

        #endif

        // add the model to the viewer
        viewer.add_model(cloud);

        viewer.run();

    } catch (const std::runtime_error &e) {
        std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
        std::cerr << error_msg << std::endl;
        return EXIT_FAILURE;
    }

and


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

        if (!context_) {
            // Setup ImGui binding
            IMGUI_CHECKVERSION();

            context_ = ImGui::CreateContext();

            const char* glsl_version = "#version 150";
            ImGui_ImplGlfw_InitForOpenGL(window_, false);
            ImGui_ImplOpenGL3_Init(glsl_version);
            ImGuiIO& io = ImGui::GetIO();
            io.WantCaptureKeyboard = true;
            io.WantTextInput = true;
            io.IniFilename = nullptr;
            ImGui::StyleColorsDark();
            ImGuiStyle& style = ImGui::GetStyle();
            style.FrameRounding = 5.0f;

            // load font
            reload_font();
            t.set_interval(1000, &ViewerImGui::callback_event_timer, this);
        }
    }

bool ViewerImGui::callback_event_timer() {
        printf("booya!\n");

        easy3d::Model* model = this->current_model();
        if (model)
        {
            auto drawable = model->points_drawable("lior");

            drawable->set_point_size(25.0f);
            //rawable->set_default_color(random_color());

            easy3d::PointCloud* cloud = dynamic_cast<PointCloud*>(model); 

            PointCloud::VertexProperty<vec3> colors = cloud->get_vertex_property<vec3>("v:color");
            //std::vector<unsigned int> indices;

            for (auto v : cloud->vertices())    // iterate over all vertices
            {
                colors[v] = random_color();     // assign a random color to point 'v'
            }

            drawable->update_color_buffer(colors.vector());
            drawable->set_per_vertex_color(true);

            update();

            std::cout << "point cloud has " << cloud->n_vertices() << " points" << std::endl;
        }
        return true;
    }

all other code is unmodified

return EXIT_SUCCESS;

}

LiangliangNan commented 5 years ago

It seems your random number generator is not initialized. See here for an example: http://www.cplusplus.com/reference/cstdlib/rand/ http://www.cplusplus.com/reference/cstdlib/rand/ -- Liangliang

On Tue, Jun 11, 2019 at 2:51 PM Lior Assouline notifications@github.com wrote:

vec3 random_color() { float r = rand() % 255 / 255.0f; // in the range [0, 1] float g = rand() % 255 / 255.0f; // in the range [0, 1] float b = rand() % 255 / 255.0f; // in the range [0, 1] return vec3(r, g, b); }

int main(int argc, char** argv) { try {

    ViewerImGui viewer("Easy3D ImGui Viewer", 80, 3, 2);

    viewer.resize(800, 600);

    Timer t;

    #if 1
        PointCloud* cloud = new PointCloud;

        for (float i=-5; i<5; ++i) {
            for (float j = -5; j < 5; ++j)
            {
                cloud->add_vertex(vec3(i, j, 0));// z = 0: all points are on XY plane
                cloud->add_vertex(vec3(i, j, 4));// z = 0: all points are on XY plane
            }
        }

        auto vertices = cloud->get_vertex_property<vec3>("v:point");
        // All the XYZ coordinates
        auto colors = cloud->add_vertex_property<vec3>("v:color");

        const auto& points = vertices.vector();

        for (auto v : cloud->vertices())  // iterate over all vertices
            colors[v] = random_color();       // assign a random color to point 'v'

        PointsDrawable* points_drawable =  cloud->add_points_drawable("lior"); // cloud->points_drawable("vertices");
        points_drawable->set_point_size(6.0f);

        points_drawable->update_vertex_buffer(points);
        points_drawable->update_color_buffer(colors.vector());
        points_drawable->set_per_vertex_color(true);
        points_drawable->set_visible(true);

    #endif

    // add the model to the viewer
    viewer.add_model(cloud);

    viewer.run();

} catch (const std::runtime_error &e) {
    std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
  std::cerr << error_msg << std::endl;
    return EXIT_FAILURE;
}

and

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

  if (!context_) {
      // Setup ImGui binding
      IMGUI_CHECKVERSION();

      context_ = ImGui::CreateContext();

      const char* glsl_version = "#version 150";
      ImGui_ImplGlfw_InitForOpenGL(window_, false);
      ImGui_ImplOpenGL3_Init(glsl_version);
      ImGuiIO& io = ImGui::GetIO();
        io.WantCaptureKeyboard = true;
        io.WantTextInput = true;
        io.IniFilename = nullptr;
      ImGui::StyleColorsDark();
      ImGuiStyle& style = ImGui::GetStyle();
      style.FrameRounding = 5.0f;

      // load font
      reload_font();
        t.set_interval(1000, &ViewerImGui::callback_event_timer, this);
  }

}

bool ViewerImGui::callback_event_timer() { printf("booya!\n");

    easy3d::Model* model = this->current_model();
    if (model)
    {
        auto drawable = model->points_drawable("lior");

        drawable->set_point_size(25.0f);
        //rawable->set_default_color(random_color());

        easy3d::PointCloud* cloud = dynamic_cast<PointCloud*>(model);

        PointCloud::VertexProperty<vec3> colors = cloud->get_vertex_property<vec3>("v:color");
        //std::vector<unsigned int> indices;

        for (auto v : cloud->vertices())  // iterate over all vertices
        {
            colors[v] = random_color();       // assign a random color to point 'v'
        }

        drawable->update_color_buffer(colors.vector());
        drawable->set_per_vertex_color(true);

        update();

        std::cout << "point cloud has " << cloud->n_vertices() << " points" << std::endl;
    }
    return true;
}

all other code is unmodified

return EXIT_SUCCESS;

}

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/LiangliangNan/Easy3D/issues/19?email_source=notifications&email_token=ADWOVCA3X26YNJU64UKCRNDPZ6NW3A5CNFSM4HVZR3SKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXNAHHQ#issuecomment-500827038, or mute the thread https://github.com/notifications/unsubscribe-auth/ADWOVCBYB4EULYIKVZN542TPZ6NW3ANCNFSM4HVZR3SA .

alior101 commented 5 years ago

Hi Liangliang When I'm running random_color() in the main, it is working (Im seeing random colored point cloud). In addition, when I'm running under debugger I see the colors[v] = random_color(); line in the timer event assigning really random numbers into colors vector (I saw random values for r,g,b). I even checked

        int status = vao_->create_array_buffer(color_buffer_, ShaderProgram::COLOR, colors, count * sizeof(float) * dim, GL_FLOAT, dim);

in drawable.cpp is returning 0 (no error) but still I get green dots ..

alior101 commented 5 years ago

It seems that the color buffer update is causing the green vertex to show regardless of what is inside the color buffer (I put constants in that buffer and it didn't change a thing ..)

LiangliangNan commented 5 years ago

Please do a quick test: load the bunny.bin (in $easy3d_root$/data/ directory) model and let me know if it has per point color or has a uniform color? -- Liangliang

On Tue, Jun 11, 2019 at 3:18 PM Lior Assouline notifications@github.com wrote:

It seems that the color buffer update is causing the green vertex to show regardless of what is inside the color buffer (I put constants in that buffer and it didn't change a thing ..)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/LiangliangNan/Easy3D/issues/19?email_source=notifications&email_token=ADWOVCELD5I3X4IE5WMLB6DPZ6QZVA5CNFSM4HVZR3SKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXNCTLA#issuecomment-500836780, or mute the thread https://github.com/notifications/unsubscribe-auth/ADWOVCCF4HMPXVHWPIRESMTPZ6QZVANCNFSM4HVZR3SA .

alior101 commented 5 years ago

yes, it has per point color.. But in my example also it had a per point color when I initially assigned colors to the points... It's only when updating the color that the color went away ..

alior101 commented 5 years ago

Hi Liangliang, Here is a quick way to recreate the issue I'm seeing: Please take tutorial 304_realcamera and add the below lines in main.cpp

   RealCamera viewer("Tutorial_305_RealCamera",
                      bundler_file,
                      cloud_file);

    viewer.resize(960, 800);
    // issue recreation code area
    easy3d::Model* model = viewer.current_model();
    if (model)
    {
        easy3d::PointCloud* cloud = dynamic_cast<easy3d::PointCloud*>(model); 
        if (cloud)
        {
            easy3d::PointCloud::VertexProperty<easy3d::vec3> colors = cloud->get_vertex_property<easy3d::vec3>("v:color");
            for (auto v : cloud->vertices())    // iterate over all vertices
            {
                colors[v] = easy3d::vec3(1, 0, 0);      // assign a fix color to point 'v'
            }
            viewer.update();
        }
    }   
  /// end of issue recreation code area 

    // Run the viewer
    viewer.run();

I would expect to see the fountain in red only - but the color is unchanged ... Am I missing something ?

LiangliangNan commented 5 years ago

in the RealCamera example, you need to add easy3d::PointsDrawable* drawable = cloud->points_drawable("vertices"); drawable->update_color_buffer(colors.vector()); drawable->set_per_vertex_color(true); before viewer.update(); -- Liangliang

On Tue, Jun 11, 2019 at 5:11 PM Lior Assouline notifications@github.com wrote:

Hi Liangliang, Here is a quick way to recreate the issue I'm seeing: Please take tutorial 304_realcamera and add the below lines in main.cpp

RealCamera viewer("Tutorial_305_RealCamera", bundler_file, cloud_file);

viewer.resize(960, 800);
// issue recreation code area
easy3d::Model* model = viewer.current_model();
if (model)
{
    easy3d::PointCloud* cloud = dynamic_cast<easy3d::PointCloud*>(model);
    if (cloud)
    {
        easy3d::PointCloud::VertexProperty<easy3d::vec3> colors = cloud->get_vertex_property<easy3d::vec3>("v:color");
        for (auto v : cloud->vertices())  // iterate over all vertices
        {
            colors[v] = easy3d::vec3(1, 0, 0);        // assign a fix color to point 'v'
        }
        viewer.update();
    }
}

/// end of issue recreation code area

// Run the viewer
viewer.run();

I would expect to see the fountain in red only - but the color is unchanged ... Am I missing something ?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/LiangliangNan/Easy3D/issues/19?email_source=notifications&email_token=ADWOVCE6ASR2NQYXASMPU5DPZ66CFA5CNFSM4HVZR3SKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXNOXVA#issuecomment-500886484, or mute the thread https://github.com/notifications/unsubscribe-auth/ADWOVCGV5T2GKO75C2TGSRTPZ66CFANCNFSM4HVZR3SA .

LiangliangNan commented 5 years ago

I just updated my post.

alior101 commented 5 years ago

well, it works with the RealCamera example! but not with viewer_imgui and the difference is that in real camera example the initial point cloud is taken from a file with all properties whereas in my code I just init vertices and colors ... Could this be the reason ? I used your code above in the timer event but still no success - Any chance you can use my modified totorial 302 and recreate the issue on your side ? It's viewer_imgui.h (for adding the timer declaration) viewer_imgui.cpp (for the callback actual code - just changing the colors of the cloud point) main.cpp (for initializing a simple cloud point not from a file - just from a simple loop)

Again, thanks for the effort you're putting to help me - it's greatly appreciated :) Thanks Lior Tutorial_302_Viewer_imgui.zip

LiangliangNan commented 5 years ago

Got the issue and had a solution.

The issue: calling the OpenGL functions in another thread (Timer is implemented this way) is not supported by GLFW. More info here: http://discourse.glfw.org/t/multithreading-glfw/573

A workaround: the callback function notifies the main thread (here the viewer thread) to update the GPU data. Here is the modified code in which the point cloud changes color every second. Tutorial_302_Viewer_imgui.zip

alior101 commented 5 years ago

Thanks! works perfect!