mariuszhermansdorfer / SandWorm

Augmented Reality Sandbox for Grasshopper & Rhino
MIT License
20 stars 11 forks source link

Draw contour lines #15

Closed mariuszhermansdorfer closed 2 years ago

mariuszhermansdorfer commented 4 years ago

Drawing actual curves to display contour lines is computationally expensive. Let's try adding these in the shader instead. Simply change the vertex color value to black at a given interval in the Z direction.

philipbelesky commented 4 years ago

Some quick notes/research:

mariuszhermansdorfer commented 4 years ago

Ad 1. I have just uploaded a branch where I doodled a bit with displaying contour lines as part of the vertex shader. It is fast, but visually quite disappointing... https://youtu.be/kjxylCEvV5M

We're probably better off looking into drawing actual polylines...

mariuszhermansdorfer commented 4 years ago

And btw. we need some better-looking gradients soon! My eyes hurt each time I see these ultra-saturated rainbow on the screen :)

mariuszhermansdorfer commented 4 years ago

From the middle of this video one can see the difference, proper curves make. It's worlds apart. Obviously, we'd need to internalize the logic. Having it run through an external component is way too slow.

BarusXXX commented 3 years ago

We can cut the time to 40% using mesh¦plane intersection instead of the Mesh.CreateContourCurves() image 22k faces image 30k faces image 57k faces It seems to compute at 38-40% of the time.

mariuszhermansdorfer commented 3 years ago

Awesome @BarusXXX ! We should definitely use this as an immediate improvement.

Mid-term I'd like us to have a more interactive logic, though. I've found this post with a nice description of how the algorithm works. To answer your questions, @BarusXXX, instead of creating isocurves from the mesh, we use the elevation array from the sensor and work directly on its values.

For every pixel, we check the elevation delta to each neighbor and mark it with a dot. The placement of these dots is linearly interpolated -> difference between elevation values for neighboring pixels is '5', we place 4 dots at the corresponding edge and space them by edgeLength/5
image

Then it's just a matter of connecting the right dots (corresponding to the contour interval setting).

mariuszhermansdorfer commented 2 years ago

OK, I took a stab at implementing the logic from the above post. Preliminary results are not too sexy yet, but I'll try to optimize it for one more day to see how feasible this approach is.

image

mariuszhermansdorfer commented 2 years ago

I like the fact, that we can decide on the density of the sampling grid for contour lines separately to the mesh. Here, I added a slider to define how coarse we want the analysis to be:

image

I haven't figured out a proper way of connecting these lines yet and didn't optimize the code at all, but already now it is the fastest we've ever had.

@philipbelesky, @BarusXXX do you have an idea on how to connect the lines?

Right now, it's just a bunch of loose lines, and ideally we'd have one polyline per contour line.

mariuszhermansdorfer commented 2 years ago

Fixed some bugs in the contour lines logic - it looks like we can use this for fast & coarse interactive contour display, and let users generate more detailed contours once the mesh is baked. image image

Still some work to be done on this front but looks potentially promising. The biggest issue right now, is that relatively small elevation differences between points are not identified at all. Color ramp vs. contour lines comparison visualizes this quite well: image

mariuszhermansdorfer commented 2 years ago

Getting there: image image image

mariuszhermansdorfer commented 2 years ago

@philipbelesky, @BarusXXX, I think we've got it! Displaying all contour lines through the display pipeline (DrawViewportWires) rather than outputting them through the component speeds things up tremendously! Now, we really have an interactive model which is super fun to work with!

image image

mariuszhermansdorfer commented 2 years ago

There might be value in having a dedicated contour lines output, though. Therefore, I added the following hybrid logic:

I'm using the same trick for water surface rendering - the moment something is connected to the corresponding output, its display is turned off in the main component. We can't really use the typical GH approach of disabling the preview of the entire component, since it would force us to output contours as geometry as well and slow things down significantly.

When nothing is connected to the water surface output, we get the typical GH preview: image

After connecting the Custom Previewcomponent, we only see the downstream geometry: image

mariuszhermansdorfer commented 2 years ago

Code ported to work with Kinect for Windows as well. It is super smooth and a joy to work with: image

mariuszhermansdorfer commented 2 years ago

Made contour lines adapt to Rhino's drawing units.

philipbelesky commented 2 years ago

As you mentioned, this is a joy to use! The lack of overhead in the component-preview mode is also great to see.

Regarding the geometric output, I assume the latency is coming from the sheer amount of Line objects that are being output? In which case it might be worth trying to use GH_Line rather than Line to see if type conversions can be avoided. The other trick is that changing the output parameter to be Generic rather than Curve can often route around conversion issues.

Another option might be to test if the overhead of joining the lines together might be similar/less to the overhead of outputting so many lines individually. As a bonus, it could open up some nice opportunities in the component to bridge some of the transient 'gaps' between lines as well as making downstream operations (e.g. further smoothing or contour 'matching') easier.

I've slightly run out of time today just reading/testing the new code but would be happy to have a go at some of the above options.

mariuszhermansdorfer commented 2 years ago

Definitely, way too many lines to output for Grasshopper to remain interactive. I took a stab at creating Polyline object rather than lines using two linked Dictionary<Point3d, Polyline>. One for start points, the other for end points. I got to a point, that roughly half of the lines were connected, couldn't figure out how to solve the issue, got annoyed and deleted the code :)

Would be great if you could test the proposed solutions, I might also revisit my idea another day with a fresh brain.

mariuszhermansdorfer commented 2 years ago

Did some testing today:

  1. pManager.AddCurveParameter + Rhino.Geometry.Line: image

  2. pManager.AddGenericParameter + Rhino.Geometry.Line: image

  3. pManager.AddGenericParameter + Grasshopper.Kernel.Types.GH_Line: image

  4. pManager.AddCurveParameter + Grasshopper.Kernel.Types.GH_Line: image

Generic parameters force a cast in downstream components, which we can do faster internally. Decided to go with 4 as it's the fastest and cleanest overall.

Drawing fewer contours yields acceptable results in terms of time: image

philipbelesky commented 2 years ago

Ah, thanks for trying that out. Should we close this issue and could come back to joining/linking as a separate issue?