nortikin / sverchok

Sverchok
http://nortikin.github.io/sverchok/
GNU General Public License v3.0
2.23k stars 232 forks source link

Create an Intersect Meshes node #4594

Open ArpegorPSGH opened 2 years ago

ArpegorPSGH commented 2 years ago

There is a node to find self intersections of a wireframe (Intersect Edges), but none to find intersections between two meshes or self intersections. By intersection I mean it in the sense of the Intersect (knife) of Blender, i. e. to find all edge/face intersections, and return it as a list of points. Additionally, there could be the possibility to actually merge the two meshes or self-merge the mesh.

Durman commented 2 years ago

CSG Boolean 2 node is not what you are looking for?

ArpegorPSGH commented 2 years ago

Well, it could be used to find intersection points by comparing the output vertices with the input vertices and retaining only the new ones, but it would be heavy calculations for something quite simple. Furthermore, it has a lot of limitations and is slow (according to documentation), and do not allow to merge meshes like Intersect (knife) does. So I really don't think it would be a good idea to use CSG Boolean 2. The node I am talking about would only need to find intersection points between each edge and all the polygons of the mesh(es), and optionally split edges and faces accordingly. I created a node tree to find intersection points, and it works fine, but it is quite slow as I used over 20 nodes as well as for each loops.

zeffii commented 2 years ago

mesh.ops has intersect_boolean , not a bmesh.ops unfortunately.

image

https://docs.blender.org/api/current/bpy.ops.mesh.html?highlight=mesh%20ops#bpy.ops.mesh.intersect_boolean

zeffii commented 2 years ago

unfortunately the mesh.ops doesn't return the matching topology indices that overlap between multiple objects., it just performs the intersection+union..

ArpegorPSGH commented 2 years ago

bpy.ops.mesh.intersect is what I was referring to. It is not difficult to code I believe, it is just that there is no way to do this efficiently currently. That's basically just edge/polygon intersections, or raycasting vertices along edges on mesh(es), limiting distance to edges lengths.

zeffii commented 2 years ago

image

here's with appropriate hiding..

"""
>in iverts v
>in ifaces s
out overts v
out ofaces s
"""

shell_object_name = "bifida"

docstring = """
[ ] create shell object + mesh 
[ ] select all geometry
[ ] set to edit mode
[ ] execute mesh.ops
[ ] set to object mode
[ ] get new mesh data
[ ] delete shell object
"""

for idx, (verts, faces) in enumerate(zip(iverts, ifaces)):

    # for now skip all additional mesh input, to prove a point.
    if idx > 0: continue

    if shell_object_name in bpy.data.meshes:
        data = bpy.data.meshes[shell_object_name]
        data.clear_geometry()
        obj = bpy.data.objects.get(shell_object_name)
    else:
        data = bpy.data.meshes.new(name=shell_object_name)
        obj = bpy.data.objects.new(shell_object_name, data)
        bpy.context.scene.collection.objects.link(obj)

    obj.hide_viewport = False
    obj.hide_render = False
    bpy.ops.object.mode_set(mode='OBJECT')
    data.from_pydata(verts, [], faces)
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.intersect_boolean(operation='UNION', solver='EXACT',
        use_swap=False, use_self=True, threshold=-.00006)
    bpy.ops.object.mode_set(mode='OBJECT')
    overts.append([v.co[:] for v in data.vertices])
    ofaces.append([f.vertices[:] for f in data.polygons])
    obj.hide_viewport = True
    obj.hide_render = True
ArpegorPSGH commented 2 years ago

Well, what I am most interested in is getting intersection points, so using boolean is not best, I think knife is better. Furthermore, when sverchok get multi-threaded, using bpy.ops won't be possible whithin loops or multi-branch trees, that is why I try to limit any scripts using them to intial or final treatments of the trees.

zeffii commented 2 years ago

you might want to look at the bvh nodes, and consider cobbling together a prototype script.

bvh docs (Blender) bvh_overlap_polys.py

unfortunately the bvh seems to work only on verts+faces, so while it would speed up the scenario where you look for intersections of two polygon based meshes, we don't have a massively efficient way to do proximity based lookups on verts+edge combinations ( it's a bit of an iterative process comparing all edges,

also definitely look at the code behind the intersect edges node , especially the imported functions. (https://github.com/nortikin/sverchok/blob/master/utils/geom_2d/intersections.py ,,etc)

ArpegorPSGH commented 2 years ago

I think it should be doable with raycasting, by taking each edge and raycasting one of its vertices along the edge direction, finding hit point on mesh, taking that as new start point, project again along edge direction, and so on until the opposite edge vertex is reached, then collect all hit points and return them. The process is also parallelizable on the edge level. However, I do not have much time to implement it as of now, and I am not confident in my ability to produce efficient code, so if anyone is willing to do it, great, otherwise, I have already a node tree performing that, although quite slowly, so I won't work on it anytime soon.

zeffii commented 2 years ago

make a mockup nodetree, and show what the input looks like ( viewer draw ) and show what the desired node socket configuration is of the IntersectionNode, and show the output of that node ( stethoscopes + viewer draws.. ) that way there is no ambiguity about the behaviour. Use simplest input mesh. No guarantees, but the edges intersection node is something i added to sverchok back in 2014, and it has had many upgrades.

portnov commented 2 years ago

You may be interested in this node: https://github.com/nortikin/sverchok/blob/master/docs/nodes/modifier_make/cut_object_by_surface.rst It is very limited, but in some cases it can help.

ArpegorPSGH commented 2 years ago

It is quite close from what I am looking for, however the limitation make it unusable for me, and I am looking for intersections both ways, not only from one mesh with another.

portnov commented 2 years ago

You're welcome to enhance it :)

ArpegorPSGH commented 2 years ago

I'll look into that when I have some time.

Durman commented 2 years ago

Merge Mesh 2D?

image

ArpegorPSGH commented 2 years ago

I need only the new vertices, and in a 3D context, so I think solving the limitation of Cut Object by Surface, and adding a socket containing the intersections found is the best way to go.

ArpegorPSGH commented 2 years ago

After reading the code, in fact there is no need for a new socket, just to solve the limitation. I already know how to find all the intersection points by modifying the code slightly, but generating cut faces and cut parts, especially the parts will be very complicated. If it is fine, I can modify only the part about finding the intersections in such a way that it works the same as now, and reduce the implementation limitation case to only when attempting to generate cut faces or cut parts. I found a strange part in the code, stating that : "Since raycast's ray is single-directioned, we have to check for intersections twice : from V1 to V2 and from V2 to V1." I dont' understand what is the point : if there is no intersection from vertex V2 to vertex V1, there cannot be an intersection from vertex V1 to vertex V2, right? I think I can also add an all triangle option, since raycast is used internally. Since it will be my first time contributing to sverchok and to a GitHub project in general, could you tell me how to go about working on the node, debugging it, testing it, and submitting it for merge?

portnov commented 2 years ago

If it is fine, I can modify only the part about finding the intersections in such a way that it works the same as now, and reduce the implementation limitation case to only when attempting to generate cut faces or cut parts.

Ok, you just have to maintain backwards compatibility. If your new code will give different results on existing setups, you have to make an option to switch new functionality off. Or maybe create an mk2 version of the node.

I dont' understand what is the point :

Correct, if there is an intersection from V1 to V2, then there cannot be an intersection from V2 to V1. But, if there is no intersection from V1 to V2, we still have to check for intersection from V2 to V1.

portnov commented 2 years ago

Since it will be my first time contributing to sverchok and to a GitHub project in general, could you tell me how to go about working on the node, debugging it, testing it, and submitting it for merge?

Refer to http://nortikin.github.io/sverchok/docs/contributing/contributing_to_sverchok.html :)

If you decide to make an mk2 version of the node:

ArpegorPSGH commented 2 years ago

You mean raycasting is influenced by front-side/back-side of face, it does not look only for a face, whatever its normal?

portnov commented 2 years ago

I do not remember exactly right now, but judging by code and comment - if you try to send a ray from "back" side of a face, you will not see intersection. But you're welcome to try, maybe I was wrong.

ArpegorPSGH commented 2 years ago

When I use the raycaster node, I can project onto back faces fine, so it seems strange. Well, it does not decrease node efficiency by much, just adds more volume to the code.

ArpegorPSGH commented 2 years ago

@portnov Okay, I finally found some time to work on this issue, and I tried to download the development version with the code there, but I got this error : git@github.com: Permission denied (publickey). Note that it is my first time using Git, I installed it specifically for contributing to Sverchok, so it may be a dumb error. I suspect that it has something to do with me skipping your instruction to "clone this repo on github", as I didn't understand it. Am I supposed to clone the repository directly on github? If yes, how? If no, does that mean I have to download it on my computer? But in that case, it wouldn't be consistent anymore with the code for installing the development version.

portnov commented 2 years ago

First you have to create a fork of this repo on github (see button at the top of this page), then you work with your repo,then you create a pull request, asking us to pull changes from your repo to ours. I suggest you to google for "Github Pull Request Howto", there ought to be plenty of them.

ArpegorPSGH commented 2 years ago

I forked only the master branch, is it alright?

portnov commented 2 years ago

Yes, you will create a pull request towards the master.

ArpegorPSGH commented 2 years ago

I forked, cloned to my machine, and checked out to create a new branch. Then I ran mkdir -p ~/.config/blender/3.2/scripts/addons/ while in my branch, then ln -s "C:/Program Files/Blender Foundation/sverchok" ~/.config/blender/3.2/scripts/addons/, and everything went without error or warnings. However, when I went to Blender, nothing changed from the regular version, and when I modify the code of my local repo and reload the scripts, nothing changes on the node I'm working on. However, I skipped "go to Blender preferences, locate Sverchok addon and enable it as usual.", as I don't really understand what it means : I have sverchok already enabled.

What worked however, was to modify code directly inside Blender with Node Edit Source Internally button, but it isn't really a proper way to work, I guess?

portnov commented 2 years ago

Probably in your installation (this may be windows-specific), your usual Sverchok installation is located in some another directory, not in ~/.config/blender/3.2/scripts/addons/. You can probably check this out when you do "edit source internally" — where is the file located? The idea is to replace your "standard" Sverchok installation directory with the directory which you cloned from github.

ArpegorPSGH commented 2 years ago

Yeah, the file is located in another place, that is why it didn't work.