Would anyone know how to make something similar to this using grasshopper? I tried manually modelling but it just isn’t working out how I would like it. I’m new to GH and I found a similar thread on creating a ripple effect.
I’m not inclined to revisit this topic in depth but a quick scan of some of the code I referred to tells me you’ll be better off skipping the earlier work that depends on Graph Mapper and start with this post that uses an alternative way of generating a damped sine wave from David Rutten:
This post (below) and others that follow it don’t use Graph Mapper so offer the potential of more flexible control but I confess, they aren’t easy to understand:
Beginning in ripples_2019Jun06a.gh and ripples_2019Jun06b.gh, a switch between “Config” (cyan group) and “Scale” (yellow group) is offered with a ten second (!)Data Dam that delays putting into effect any parameter changes. That can be confusing.
Some of the later posts in that thread (June 7 and after) mention extremely long elapsed times for high resolution models, which is probably the reason for the Data Dam.
The thread gets into the weeds offering a “Ripple Preview” feature and ripple patterns that span multiple panels, along with other refinements. I’d have to dig in deep to understand it myself at this point.
Here a small “simulator” using points as droplets.
Droplet fall speed is equal to wave propagation speed, so when a droplet is below Z=0 it is projected to XY plane and its Z value used as radius of the wave.
Waves keeps a constant volume (conservation of energy… ? maybe not…)
Used a c# script for most of the work, used Parallel.For for increased speed using multithreading.
Managing big lists of values is slow on grasshopper, doing everything inside a c# script let the simulation works realtime even with big meshes and high droplets count.
Added comments inside the c# script so anyone could reverse engineer it and maybe learn how to do stuff…
Cya boyz!
code:
using System.Threading;
using System.Threading.Tasks;
private void RunScript(Mesh M, List<Point3d> P, double Wp, double Wh, ref object A)
{
double pi = Math.PI;
// Finding droplets that are below Z=0 and putting them into a new list. Projecting them into XY plane.
// Saving the Z values into a separate list. Point depth is used as time factor (the further down, the earlier the droplet did hit the water surface).
List<Rhino.Geometry.Point3f> pts = new List<Rhino.Geometry.Point3f>();
List<double> t = new List<double>();
foreach(Rhino.Geometry.Point3d p in P){
if(p.Z < 0){
pts.Add(new Rhino.Geometry.Point3f((float) p.X, (float) p.Y, 0));
t.Add(-p.Z);
}
}
// The next 2 lines do the same thing: iterate through M.Vertices list.
Parallel.For(0, M.Vertices.Count, i => { // This is the parallel, multithreaded method. Faster.
// for(int i = 0;i < M.Vertices.Count;i++){ // This is the normal for loop method. Slower.
// Current vertex is M.Vertices[i] .
// This value will become later the Z movement of current vertex.
double m = 0;
// Now iterating to each Z<0 droplets; finding distance to current vertex and applying function to increment m.
for(int j = 0;j < pts.Count;j++){
double d = M.Vertices[i].DistanceTo(pts[j]); // distance
// Wave speed is same as droplet, so wave radius is equal to droplet value below Z=0;
if(!(d < t[j] - Wp / 2 || d > (t[j] + Wp / 2))){ // Applying function only to areas around the wave radius +/- half Wave pitch (Wp).
m += Wh * (1 - Math.Cos(pi + pi * (d - t[j]) / (0.5 * Wp))) / (d + 1);
}
}
// Moving vertex.
M.Vertices[i] = M.Vertices[i] + new Rhino.Geometry.Vector3f(0, 0, (float) m);
}); // End of parallel method.
// } // End of for loop method.
M.RebuildNormals();
A = M;
}
That’s brilliant, thanks for sharing.
It looks like each drop sends one ring / wave out from the point that it hits the surface.
In reality, each drop would send a decaying oscillation outwards from each point. Is there an easy tweak to the script to do this?
if(!(d < t[j] - Wp / 2 || d > (t[j] + Wp / 2))){ // Applying function only to areas around the wave radius +/- half Wave pitch (Wp).
m += Wh * (1 - Math.Cos(pi + pi * (d - t[j]) / (0.5 * Wp))) / (d + 1);
}
That part is when the distance (d, from vertex to droplet) is begin used. t[j] is the “time” since droplet hit.
You can edit that formula.
Keep the "m += " part, and put whatever. (it’s needed to sum the effects of every droplets)
I can do it for you but i don’t know a function . I’ve found some but i didn’t like them.
Anyway, if you find a formula using d and t[j] i can fix that…
Wave equations tends to be complex and… opinion-dependent.
Maybe i’m wrong.
This is from a @DavidRutten example from years ago (can’t find the link)
I use this for nice static wave interference from point sources. ripplesDR.gh (13.7 KB)
Yes, this looks like a reversion to the models I posted in June, 2019.
Of the additional parameters you mentioned, I think time elapsed is the most important. I imagine it to be a kind of damped oscillation at the center point, in addition to the “half-life” damping factor at a distance in @DavidRutten’s equation from 2016:
Beyond me though.
P.S. It’s not as simple as this but maybe something similar?
I said I wasn’t inclined to revisit this topic… But visualizing ripples have been a fascination of mine for more than 40 years(!), going back to using character sets to represent “pixel” density.
Looking again at ripples_2019Jun07b.gh from June, 2019, I’m really impressed with some of the features in this model, especially “caliper” (purple blob group) and “Ripple Preview” (yellow group):
I added the “EXPERIMENTAL” ‘time’ slider (blue group), which is nonsense but interesting? No other changes. Resolution (white group) is low for better response time but can be increased.