
In the previous attractor examples, the focus was on creating 2D patterns with a linear distance falloff. Attractors can also be used to adjust geometry in 3D space, and the distance domain can be modified based on various functions to create more interesting and dynamic geometry. In this example, we will be using attractor logic to modify a 2D plane in the Z axis to create a 3D topographic surface with landforms controlled by various modifiable attractor points. We will also be adjusting the distances within a defined radius to create landforms with an adjustable section profile by using the Graph Mapper component to change the linear domain into a non-linear one. The focus here is on point attractors, but curve attractors can be used as well, which will be the focus of the next example so stay tuned!
Step One – Setup Initial Surface and Attractor Points

For this particular example, we will start by drawing a rectangular plane in Rhino and referencing this with a Surface parameter into Grasshopper. Here I am using a 100 x 100 unit square plane, which you can use as well if you want results similar to mine. I then use the Divide Surface component to create a grid of points on my surface, with U and V values set at 25. I can increase this later to refine my final surface output, but this should do for now.
I have also drawn four points within the surface in Rhino. Two of the points are very close together (towards the bottom, center region), which will give me a higher landform in the end in this area. We will try different point variations in the end, but we want to stay simple for now. I then reference these four points into Grasshopper using a Point parameter. Note that the initial suface division points have a ‘flattened‘ data structure, and the referenced data points are ‘grafted.’
Step Two – Calculate Inverted Distances from Attractor Points within a Defined Radius

We now start setting up our attractor by calculating the distances with the Distance component measuring between each one of our initial surface division points (Input A) and each of our referenced attractor points (Input B). Make sure you remembered to ‘graft‘ the referenced points in the previous step to ensure the distance measurement is between each of the referenced points and each of the surface division points!
Since we want a stronger attractor effect the closer we get to the attractor points, I am ‘inverting’ the distance outputs by subtracting these from a modifiable constant, which we will see later governs the radius of the attractor effect. I create an adjustable slider (set to 15.5 here) and use the Subtract component with the Radius parameter going into Input A and with the calculated distances going into Input B. I then use a Maximum component to reset all negative values to a constant of ‘0’.
Step 3: Remap Distances and Modify with a Graph Mapper

If I were to use the distances as currently configured to move points vertically, my final output would be limited to cone-like geometry, which is not the effect that we want. Fortunately, we can use the Graph Mapper component to modify a set of numbers based on one of many different graph types. Graph Mapper will only modify a range of numbers between 0 and 1 though, so our first task is to use the Remap Domain component to remap our distances – in this case numbers between 0 and 15.5 – to numbers between 0 and 1. To do this, I input the current set of distances into the V (Value) input of Remap Domain, I use a Bounds component attached to my distances to measure this domain, with the output of this feeding into S (Source Domain) input, and with a panel with the value ‘0 to 1’ input into the T (Target Domain) input. I could also use a Construct Domain component here with values of ‘0’ and ‘1’ but the panel is a bit simpler and cleaner.
The outputs of the Remap Domain are then fed into a Graph Mapper. There are various options here, but the one I am using now is the Bezier curve graph. Right click the Graph Mapper component, select ‘Graph Types > Bezier’ to get this. There are adjustable control points you can drag to get the curve into the desired position. This in effect will be the section profile between the edge of our radius of effect and the referenced attractor points.
Step 4: Move Points Vertically Based on Scaled and Modified Distances

Before I move my control points vertically, I want to Multiply the outputs of the Graph Mapper by an adjustable parameter which will control the maximum vertical displacement per control point. This means if I have a single attractor point in a region, this will be the maximum height, but if I have two control points very close together, the landform height could be double this and so on. I then use the Flip Matrix component to reorganize my data structure into sub-lists associated with each of my initial division points. The sublists will have a number of values equal to the number of grafted reference attractor points from step 1. I then use a Mass Addition component to sum the sub-lists together, with the results of Mass Addition then flattened to make these compatible with the number of division points.
I am now ready to use a Move component to move my surface division points vertically. These points go into the G (Geometry) input on move, and the results of Mass Addition are fed into a Unit Z vector component and into the T (Motion Vector) input of Move.
Step 5: Recreate Surface Based on Moved Points and Cut Contour Lines

I am now ready to create a new surface based on the position of the modified points. For this I am using the Surface from Points (SrfGrid) component. The points themselves naturally go into the P input. For the U (U Count) input I need to use the initial value for the U division +1. This is a common error for SrfGrid, as our SDivide actually gave us an extra column of points! Here I used the Expression component to do the math. You could also use an addition component or a formula override directly at the U input parameter.
To help with the visualization, I’ve chose to cut contours using one of the Contour components. There are actually actually a few different components named ‘Contour.’ Make sure the one you are using has an ‘S’ for the first input. This is found under the Intersect>Mathematical tab in Grasshopper.
The surface itself is fed into the S input. You can modify the other parameters if you would like or use the default values.
Variations

Once this is up and working, you can try playing with some of the parameters or the graph itself to modify your surface. In the Variation 1 above, I am using a lower value for the maximum height parameter and a larger value for the distance effect radius. In Variation 2 I’ve used a different graph in graph mapper, in this case a Sine curve, which in effect gives me donut-like landforms around my attractor points. In Variation 3 I’ve returned to the Bezier graph and added more reference points in Rhino. Play around with this a bit to see what you get!
