6
$\begingroup$

new to geometry nodes. I generated instances so they're all clumped together to form one large object, and I want to scatter more instances to make smaller clumps over the surface of this large object. I know this is because the instances are all their own volumes and so scatter points on faces will naturally do that even in the parts overlapping. Is there a workaround? Thanks

picture 1) I made cube instances on the points on the faces on the cluster of cylinder instances

picture 2) however I would like to be selective on where the cubes/points are generated so that they are only on the outer surface of the cylinder cluster, and exclude the parts of it inside that are overlapped/hidden. if possible I would like for the 'scatter points on surface' to be on the outer surface of the whole cluster itself, and not all the faces of each individual cylinder (most which have sides that are hidden), the way it is in this photo when I hide the cylinder cluster

I made cube instances on the points on the faces on the cluster of cylinder instances

 however I would like to be selective on where the cubes/points are generated so that they are only on the outer surface of the cylinder cluster, and exclude the parts of it inside that are overlapped/hidden. if possible I would like for the 'scatter points on surface' to be on the outer surface of the whole cluster itself, and not all the faces of each individual cylinder (most which have sides that are hidden), the way it is in this photo when I hide the cylinder cluster

enter image description here

Newest pic to show examples of points that I would like to not have there.

Tried with a mesh boolean node and with only primitives just to make sure that they are manifold objects I'm working with. Unfortunately I can still see that the instances are being made inside where the objects' volumes have intersected. I hid the outer cube for visibility, but inside the points are still made inside.

enter image description here

$\endgroup$
5
  • 1
    $\begingroup$ If nobody comes up with a better idea, the only way I would know is realizing the instances. Then put a Remesh modifier on the object after the Geometry Nodes modifier and adjust the settings to get a more or less close to the original hull of the object. Then add another Geometry Nodes modifier and create a new nodetree where you instance objects on the remeshed geometry. But I would suspect there has to be a better way. $\endgroup$ Commented Aug 30, 2023 at 7:55
  • 2
    $\begingroup$ Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. $\endgroup$
    – Community Bot
    Commented Aug 30, 2023 at 9:35
  • 1
    $\begingroup$ Could you please illustrate exactly what you mean with a simple example?.. this post is a little hard to interpret unambiguously. $\endgroup$
    – Robin Betts
    Commented Aug 30, 2023 at 10:16
  • $\begingroup$ Hi @RobinBetts , sorry for the confusion. I updated the question with screenshots and descriptions. I hope this helps make my issue more clear $\endgroup$
    – Yeti
    Commented Aug 31, 2023 at 2:10
  • $\begingroup$ Hi @GordonBrinkmann unfortunately I would like to preserve the geometry if possible. This was still helpful though so thank you, if I don't find a solution I may just do this. $\endgroup$
    – Yeti
    Commented Aug 31, 2023 at 2:14

3 Answers 3

4
$\begingroup$

You have a bunch of instances generated in a different modifier. These instances intersect each other. You would like to distribute some other instances on the surface of these objects, with a new GN modifier, but not where they intersect each other. Is that correct?

enter image description here

We start with a "realize instances" node so we can do further work on the instanced meshes. Then we can use a "mesh boolean" node with self-intersection enabled to create a single surface from the union of all of our instances (assuming those instances are manifold meshes; otherwise, the notion of "outer" is ambiguous.) Then we'll distribute instances only on the surface of this union.

$\endgroup$
8
  • $\begingroup$ That was actually what I was going for, but maybe I had too many instances because as soon as I plugged the geometry into the Mesh Boolean node, my Blender froze and even outside of the program everything stuck and reacted quite slowly and randomly. So I gave up trying to give it as an answer because I feared it would perform to badly or not at all, since when I wrote my comment there were no screenshots to see how many instances there might be. 😆 $\endgroup$ Commented Aug 31, 2023 at 19:28
  • $\begingroup$ @GordonBrinkmann It does perform poorly :) Exactly how poor depends on the meshes. But, it's usable. Some stuff is just expensive, and everything is expensive when you throw enough polys around. $\endgroup$
    – Nathan
    Commented Aug 31, 2023 at 20:11
  • $\begingroup$ @Nathan Hi, yes correct I basically want to only spawn points that are outside of where they intersect. I just tried this, but upon closer examination I've seen points still spawn inside. Could there be something I'm doing wrong? I'll update with a screenshot. $\endgroup$
    – Yeti
    Commented Sep 3, 2023 at 8:14
  • $\begingroup$ @Buoy Likely, it depends on the specific instances-- as I mentioned, if they're not manifold, then a mesh boolean won't really work on them. Could tell you better with a file than with an image. $\endgroup$
    – Nathan
    Commented Sep 3, 2023 at 15:12
  • $\begingroup$ @Nathan I tried it out using only primitives (cubes and cylinders), hoping that this ensures they are all manifold objects I'm working with. There seems to be an issue on my end, am I doing something wrong? When you look inside the volumes of your cylinders, are the small cubes not there like mine are? Also sorry for editing your answer, I didn't even realize that it was possible. $\endgroup$
    – Yeti
    Commented Sep 4, 2023 at 7:02
7
+500
$\begingroup$

*This method needs manifold geometry (closed and with outward normals)*

With the Raycast node and a few chained raycasts, you can get a good result:

  • Red: Inside Points
  • Yellow: Unsure Points
  • Black: Outside Points

four iterations animated image

But for a lot of instances intersecting the number of iterations needed grows:

I have some other ideas for optimizing for very clumped instances, I may test them and update the answer later.

11 iterations progression


The idea is simple, first for a point raycast to the source surface using the source normal, if the raycast hits and the hit normal points away from the source normal, then the point is inside a mesh.

To know if the hit normal points away or towards the point normal we can use the Dot Product operation, it receives two vectors and outputs the cosine of the angle between them if they are normalized, so if the result is greater than $0$ the hit comes from inside, else it comes from outside.

A single raycast will work if there's a maximum of one intersection per mesh, but, if there isn't, more raycasts starting from the previous raycast hit position will be needed, and the result will depend on the number of times a ray enter and exit a mesh, if it exits more times than it enters, it is inside some geometry.

For a point, first store an integer to be used as a depth counter, then raycast to the source surface, if there's no hit, it's outside; if the hit normal is opposite to the point normal, subtract $1$ from depth, else add $1$. As soon as depth becomes 1, you know the ray started [and still is] inside some geometry, but while it doesn't hit, repeat the raycast process, accumulating depth until it reaches $1$ or does not hit.

A way to reduce the number of iterations needed for some points is also raycasting backwards, storing another integer for the backwards depth, but this one starts at $-1$, since the ray will have exit the source mesh, adding an extra $1$ to the total.


In Geometry nodes, first we prepare our variables:

variables declaration by Named Attribute Prepare Raycast node group

  • direction: the point normal, used as the raycast direction.
  • hit_pos: the position hit by the last forward raycast, initialized as the point position.
  • hit_depth: the depth of the forward raycast, starting at 0.
  • inv_hit_pos: the position hit by the last backward raycast, initialized as the point position.
  • inv_depth: the depth of the backward raycast, starting at -1, since the back of the source mesh will eventually be hit, adding an extra $1$ to the value.

Now we need a node group that does the raycasting and can be chained:

Raycast Step node group Raycast Step node group tree

Something important to do is offset the raycast source in the raycast direction by a very small amount, if that's not done, the raycast can hit the place where the point was distributed. The offset value in the blend file I provided is $0.001$, but can be made smaller inside the node group if your meshes are of smaller scale, I tested until $0.00005$.

At the end of the chain, we can remove the named attributes used for calculation:

Here there's switches that output no geometry if the source is empty, the only purpose of that is to stop the 'named attribute not found' warning. I also added an option to join unsure points to the resulting points (which contains the outside points).

Blender 3.6.1


In blender 4.0, with repeat zones, you won't need to duplicate the chain nodes anymore, the number of iterations can be chosen in the node:

using repeat zones Single Node raycast iterator

$\endgroup$
7
  • 1
    $\begingroup$ "If depth is 1, the point is inside" - maybe could be rephrased to something like "as soon as depth becomes 1, you know the ray started [and still is] inside some geometry", not sure if this isn't a pedantic nitpick, but I spent some time thinking to make sure I understand the GIF correctly (which shows very nicely the two upper rays never go outside the screen, because the test finishes early, as soon as the value becomes $1$). $\endgroup$ Commented Sep 5, 2023 at 10:17
  • 1
    $\begingroup$ "A way to reduce the number of iterations needed for some points is also raycasting backwards" - This reduces the number of iterations, but possibly increases the number of raycasts? A statistic could actually be measured on some real geometry… BTW, this answer is a nice example of a limitation of the "Repeat Zone" - there's no "while" functionality, so you can't know how many times to raycast. However, what you can do is put a switch inside the repeated group checking if there are still some unevaluated points, doing nothing otherwise, and set the "Iterations" to a huge number (num of faces) $\endgroup$ Commented Sep 5, 2023 at 10:19
  • 1
    $\begingroup$ … And since that switch would be very inexpensive for a no-op, it would only be significant (in the very likely scenario) if it was run millions or billions of times unnecessarily, but you can wrap one repeat zone in another, let's say outer_max = ceil(len(faces)/1000); Then have an inner loop of 1000 iterations, outer loop of outer_max` iterations, you're now running using two switches, but for a million faces you just have at most 2000 unnecessary switch checks. $\endgroup$ Commented Sep 5, 2023 at 10:36
  • 1
    $\begingroup$ Sorry for spamming, one more thing: "This method needs manifold geometry and outward normals" - I think the latter is the part of the manifold definition. $\endgroup$ Commented Sep 5, 2023 at 12:08
  • 1
    $\begingroup$ @MarkusvonBroady About reducing the number of iterations, I wasn't thinking about speed, just the number of times you would need to copy the step node, but now i'm curious about speed statistics. $\endgroup$
    – Hulifier
    Commented Sep 5, 2023 at 17:00
4
$\begingroup$

Well, this is how it could be done:

enter image description here

Just create a volume from the objects, without increasing the Band Width, and with a high Voxel Amount. Then convert the volume into a mesh. This will give you a closed mesh that combines all objects into one, similar to Mesh Boolean.

Then distribute your points on the original objects and send a raycast to the previously created mesh in the direction of the normals of the points. Finally, delete the points if their normals point in the opposite direction, which you can solve with Compare and the Dot Product.


(Blender 3.6+)

PS: I love simple solutions...

$\endgroup$
5
  • 1
    $\begingroup$ It's a nice solution, and I also love simple solutions, however simple solutions are sometimes slow and unreliable :P Dealing with edge cases make them no-longer-simple solutions. Remeshing is more reliable than boolean, and I think it's a good fit for random distribution most of the time, however I imagine one possible problem is that some geometry, that would be never visible on the inside in Hulifier's solution, here will be (it's hidden by the fact those are points and so even properly spawned points will be visible on the inside, not bringing attention to the incorrect points) $\endgroup$ Commented Sep 5, 2023 at 12:03
  • $\begingroup$ A bigger problem is finding out good voxel resolution of the volume, which will never be perfect and that can cause issues in two ways: 1) when working with topology and wanting to snap the closest point to the intersection - where even the slightest inaccuracies can cause huge problems, 2) as the volume scales you need to readjust the settings or you will get errors visible with the naked eye: i.imgur.com/fu4mX1t.png $\endgroup$ Commented Sep 5, 2023 at 12:06
  • 1
    $\begingroup$ Still, this is a good answer (albeit with your current settings, annoyingly slow, as remesh/boolean solutions usually are). $\endgroup$ Commented Sep 5, 2023 at 12:07
  • $\begingroup$ @MarkusvonBroady That's right. The solution has its weaknesses, but only eight nodes ;-) $\endgroup$
    – quellenform
    Commented Sep 5, 2023 at 12:11
  • 1
    $\begingroup$ I also have to admit, while I thought of this solution the previous time a similar question has been asked (I answered it poorly, can't find it) I didn't even test it, being sure it would be MUCH slower or much less accurate. The volume implementation had some improvements along the way though. $\endgroup$ Commented Sep 5, 2023 at 13:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .