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 245 forks source link

3D lines progressively become thiner and ultimately disappear upon rotating the 3D object. #108

Closed Davar1990 closed 2 years ago

Davar1990 commented 2 years ago

Hello again.

I used "Tutorial_301_Drawables" to learn how to draw lines. I can successfully draw the lines, but the lines gradually disappear as I rotate my 3D object, and as the view is changed. The pictures below demonstrate the issue.

frontal visible side 1 side 2

Even in frontal view, the lines are not fully visible. I have used the following code to create them.

auto drawable = new easy3d::LinesDrawable("lines");

drawable->update_vertex_buffer(verts);

vector<uint32_t> lineIndices;
lineIndices.reserve(vk.size() * 2);
for (int i = 0; i < vk.size(); i++) {
    lineIndices.push_back(i);
    lineIndices.push_back(i);
}
lineIndices.erase(lineIndices.begin());
lineIndices.pop_back();

drawable->update_element_buffer(lineIndices);

drawable->set_uniform_coloring(easy3d::vec4(0, 0.8, 0.0, 1));
drawable->set_line_width(lineWidth);
viewer.add_drawable(drawable);

viewer.fit_screen();
viewer.run();

I would appreciate your help on this issue.

LiangliangNan commented 2 years ago

Hi, Glad to peek at your results :-)

OpenGL draws line segmentation in the view space, so they are actually 2D quad and thus the weird behavior you currently have. What you need is to draw 3D lines as cylinders, which can be simply achieved by drawable>set_impostor_type(LinesDrawable::CYLINDER);.

BTW, the way generating the 'line indices' could be simplified (but the current one is also fine).

Good luck and looking forward to seeing your exciting progresss.

Davar1990 commented 2 years ago

Hi, Thank you very much for your comments and kind support as always :)

I tried drawable>set_impostor_type(LinesDrawable::CYLINDER); and it made a big difference. However, the lines are still not 100% visible when the connecting vertices are far apart. If the vertices are tightly close together, the lines appear fine as follows.

But if the vertices are far apart, the lines grow thin or disappear at some places.

Additionally, I would appreciate it if you could share the correct and simplified way of assigning the line indices.

LiangliangNan commented 2 years ago

If the vertices are far apart, you will need to subdivide the line segment. This is due to the non-planar nature of the surface. Think about a line segment whose two endpoints are on a sphere: the interior part of the segment always stays in the interior of the sphere and will never be visible from the outside (we assume a 0-radius line). To make it visible, you can subdivide the line segment in a way such that the distance between any point in the line segment is smaller than the radius of the cylinder. In your case, you can use a kd-tree to query the nearest vertex in the mesh to approximate the distance.

Below the code for obtaining the vertex indices of the lines (I assume you have a polyline, i.e., each vertex is shared by two consecutive segments except the first and last vertcies):

    for (int i=1; i<num; ++i) { // NOTE: starts from 1
        std::cout << "source index: " << i-1 << std::endl;
        std::cout << "target index: " << i << std::endl;
    }
Davar1990 commented 2 years ago

Thanks for the explanation. It makes perfect sense. I will look into the kd-tree structure to solve this. Also, the simplified index assignment is exactly what I need :) Thank you!