Sampling Nearby Points

I'm grateful for the Raycasting example file demonstrating how to 'stick' objects onto other objects. However its limitation becomes apparent when one object is larger than the frequency perturbations of the underlying object (see attached image). Ideally one would sample at a higher rate to gather multiple point data (in this case Normals) and filter (average, for example) to better represent the interface between the surfaces.

Getting closest points seems better suited to Getting neighboring points in that there is control of search radius, which can be adjusted to best represent the surface perturbation frequency. I've included an image of an ICETree, which is the most basic approach - but despite its simplicity is not at all straightforward to recreate in Canvas. I have looked through the docs and it is not obvious or intuitive how to manipulate arrays on a per-point basis.

Beside a demonstration of an equivalent Canvas solution it would be great if there were also an explanation of the Canvas approach - why it is handled in the way that it is.

And my apologies if this has been addressed elsewhere - I will continue to hunt among the forum & tutorials while awaiting a reply.


Many thanks,
Edward

Best Answer

Answers

  • Roy NieterauRoy Nieterau Posts: 258 ✭✭✭
    edited September 2016

    Not entirely sure what you're looking for since I'm not an ICE user so I'm not completely sure about the expected output of that graph.

    Attached is a graph where I have a cylinder shooting raycasts to a wavy plane to find hits in the Y-axis direction.
    This example raycasts from all point positions of the cylinder.
    From all these hits it retrieves the valid geometry locations from which it takes the normals and point positions.

    The average of these normals is used as up vector for the cylinder orientation to allow us to smooth out the overall orientation.
    The average Y value of the hit positions is used for the translate Y of the cylinder to have it move up and down with the wavy motion.

    Note that this is just a quick example graph showing how (like your ice graph) you could perform raycasts, get the normals and set a direction from it.


    Note that you could also do the smoothing the other way around. Where you'd instead create a new Attribute on the wavy water mesh, like a normalsSmoothed where the normals are blurred/average across the surface. As such sampling a single hit point would then already result in a smoothed normal.

    Have fun playing around with different possibilities! :)

  • QuirkEdQuirkEd Posts: 5

    I appreciate the quick response, however I don't think I articulated the issue clearly enough since your example arrives at a single solution, whereas I'm interested in evaluating over an array (in this particular case, as shown in the previous image, nine points/objects). Imagine particles raining down onto an uneven surface, each represented as a cylinder (like a coin, perhaps).

    Given an array of raycast hits, an array of locations is returned & for each of these another array is then generated (a subarray of normals per-point, I suppose) which is filtered (averaged) to return an array of solutions for each initial raycast hit.

    In an ICETree, the GetClosestPoint node I understand to operate within a per-point context. I'm unsure how to set this up in Canvas, whether it makes sense to create a 'block' for a single solution & use that block within a loop, iterating over each of the locations? Or ?

    Perhaps, as you suggested, creating a 'smoothed' attribute for the surface would be the simplest approach, although this certainly would be inefficient since I only want to evaluate a small range of those points, not the entire surface. I'm thinking I'll take a closer look at the 'ShrinkWrap' example file too.

    Thanks again

  • Roy NieterauRoy Nieterau Posts: 258 ✭✭✭
    edited September 2016

    Ah, that explains it better.

    In this case you'd indeed want to "nest loops". The way to do that visually is to use blocks.

    With this scenario you have an array of point positions, and for each of these positions you want to generate an "average normal" by shooting a grid of rays from around the point.

    In a form of pseudocode it boils down to something like::

    • For each point in point positions
    • Generate a grid of sample points at point
    • For each sample point in sample points -> raycast -> get normals -> average

    Attached is a sample graph of translating roughly that into something visually.

  • borjaborja Administrator, Fabric Employee Posts: 480 admin

    Nice sample Roy!

    Borja Morales
    Technical Product Manager
    Fabric Software Inc.

  • QuirkEdQuirkEd Posts: 5

    Cool - seems like it should work as requested. Thanks very much for taking the time to create your example.

    I've not had a chance to scrutinize in greater detail, but I'm curious why you've chosen to 'shoot a grid of rays' for each point rather than using either getting points within a given radius or simply grabbing neighboring point information (as in the ICETree)?

    Is it computationally less expensive to shoot a grid of rays, or more efficient timewise? Easier to transfer array data? What are the advantages or disadvantages to this method over getting closest points? There's always a million ways to skin a cat, as they say, and I'm just as interested in understanding & mastering Canvas's 'best practices' as I am of the solution to which you arrived.

  • Roy NieterauRoy Nieterau Posts: 258 ✭✭✭

    I'm curious why you've chosen to 'shoot a grid of rays' for each point rather than using either getting points within a given radius or simply grabbing neighboring point information (as in the ICETree)?

    To be honest this was just to quickly get an example graph out.

    Within radius

    You could use the SpatialQuery.GetElementsInBSphere to get the points and then retrieve the attributes.

    I tried that quickly (see attached cylinder_on_wavy_water_v05_bsphere) but was unable to get the correct positions. Not sure what's wrong, hopefully just me being fuzzy in the morning. Let me know if you figure it out. :smile:

    Getting neighbours

    For this you could use: GetPointSurroundingPoints, see attached cylinder_on_wavy_water_v06_neighbors.

    This means that for each closest point you'll have to take a nearby point index and then from there on out take the point's neighbours.


    There's always a million ways to skin a cat, as they say, and I'm just as interested in understanding & mastering Canvas's 'best practices' as I am of the solution to which you arrived.

    I think this covers it mostly.

    Deciding what's the best way to go about it of course heavily depends on the exact use case. The grid raycasting is rather consistent across the grid for a wavy plane like this and as such gives a fluent motion. This is different for the other two options, because those are "taking the nearest point index" which could jump from frame to frame to a different point index, as such instantly differ quite a lot instead of interpolating between the points. Of course this could be solved again by having a weighted average (further away points have less influence). That way as they come "in-sight" they gradually become stronger influencers.

    Also the way I've built the graphs is purely with the intent to demo the possible workflows. I believe there are definitely ways to have this done more optimally. Or even ways that one could call a better Canvas best practice, but I wouldn't really know. :wink:

  • Roy NieterauRoy Nieterau Posts: 258 ✭✭✭

    I tried that quickly (see attached cylinder_on_wavy_water_v05_bsphere) but was unable to get the correct positions. Not sure what's wrong, hopefully just me being fuzzy in the morning. Let me know if you figure it out.

    To get back on to this issue I believe the GetElementsInBSphere matches against the polygons instead of the points on a PolygonMesh. As such when you use those elements to as a "point index" it'll have unexpected results.

    Attached is a graph that shows a possible workaround for the workflow, but maybe the FE team can point out how to do this without making an intermediate Points instance.

Sign In or Register to comment.