Adaptive Pavilion is an old school script that used to be taught in many workshops of the early days of Grasshopper (2010-2011). It consists of a Pavilion based on two free-form NURBS curves that delineate pavilion borders connected by arcs defining the pavilion surface. David Rutten, the creator of Grasshopper, has his version of this script from 2013, in which he teaches Grasshopper basics using this example. Back in those days, everyone had a version of this script. Some versions used triangulated panels, others used grid shell, and others voronoi…a lot of them used Voronoi.
In this tutorial, we explore a version that I used to teach in Grasshopper workshops. However, this version has a special Blender flavour. Instead of using a NURBS curve, we draw the curve using the power of Blender’s Grease Pencil, which allows us to make and animate 2D sketches in 3D Blender Environment. It is a powerful tool to be explored by architects and designers. This example is just a simple exploration of how this tool can be used.
First, we create a Blank
Grease Pencil
object on Blender Viewport (Shift+a -> Grease Pencil -> Blank
).
Then, we turn on Auto Keying
to automatically save keyframes in the Blender timeline. This step is necessary because Grease Pencil
will use it to register drawings in the keyframes in the different drawing canvas. It is a feature of 2D animation, and the draws just can be saved in keyframes.
We draw the curve using the Grease Pencil
tool. On Blender Viewport, we digit 7
from NumPad to change the view from Perspective to
Top View. Then, change Blender Mode from
Object Modeto
Drawand draw a freehand curve following the
Y` axis.
The next step is to pass this curve to Sverchok. We use Object_ID Selector+
(BPY Data -> Object_ID Selector
) for data
parameter we use grease_pencils
, for name
-> GPencil
, which will be this name by default it is the first object draw, for layer
-> GP_layer
, it follows the same logic of the name
parameter, but for the layer’s name. Finally, we click on the active frame
option to select active keyframes.
Then, we use Path Length
(Analyzers -> Path Length
) to measure the curve length.
Object
output from Object_ID Selector
node goes in Vertices
input from Path Length
, or in a short notation form:
(Object_ID Selector[Object ->]) -> (Path Length[Vertices <-])
I will use these notations from now to make less verbose input/output descriptions.
We connect a Multiply
(Number -> Scalar Math
) as a factor, because later we will divide this curve into vertices and use this factor to define the number of vertices.
(Path Length[TotalLength ->]) -> (Multiply[x <-])
Then, we connect the Multiply
node in a Float to Int
(Number -> Float to Int
) node.
(Multiply [Out ->]) -> (Float to Int [float <-)
We use a Number Range
(Number -> Number Range
) connected to the Float to Int
:
(Float to Int[int]) -> (Number Range[step <-])
To create an interval of numbers from 0
to 1
, using the method Float
, Count
, with start
as 0
, end
as 1
, or:
Number Range {Float; Count; start:0; end:1}
Then we connect the Number Range
and Object_ID Selector
to a Vector Interpolation
(Vector -> Vector Interpolation
). Also, we can use a Viewer Draw
(Viz -> Viewer Draw
) to visualise the vertices on the curve.
Vector Interpolation {Linear}
(Number Range[Range ->]) -> (Vector Interpolation[Interval <-])
(Object_ID Selector[Object ->]) -> (Vector Interpolation[Vertices <-])
(Vector Interpolation[Vertices ->]) -> (Viewer Draw[vertices <-])
We make a group with the curve nodes Crtl+j
.
We create a connection between the vertices using UV Connection
(Modifiers-> Modifiers Make -> UV Connection
). We use a Viewer Draw (1)
to visualise.
UV Connection {Direct:U; Make:Edges}
(Vector Interpolation[Vertices ->]) -> (UV Connection[vertices <-])
(UV Connection[vertices ->]) -> (Viewer Draw (1)[vertices <-])
(UV Connection[data ->]) -> (Viewer Draw (1)[edges <-])
Now, we need to mirror the vertices to create other pavilion borders using Mirror MK2
(Transformations -> Mirror
). Here is a tip, if you click T
in the Sverchok canvas, you can access a menu with Sverchok components divided into categories. Through a search bar from this menu is possible to check in which category a specific node fits.
The parameters from the Mirror MK2
node will vary according to the curve drawn with the Grease Pencil
.
In my case the values used were:
Mirror MK2 {Vertex; x:1.05; y:1.2; z:0}
The UV Connection
node connects to Mirror MK2
.
(UV Connection[vertices ->]) -> (Mirror MK2[vertices <-])
The next step is to connect the list of vertices of both curves. We use UV Connection (1)
connecting Mirror MK2
and the previous UV Connection
. Also, we can use the shortcut Alt + Space
to search for nodes.
UV Connection (1) {Direction: V; Make: Edges}
(UV Connection[vertices ->]) -> (UV Connection (1)[vertices 1 <-])
(Mirror [Vertices ->]) -> (UV Connection (1)[vertices 1.1 <-])
But the second list of vertices is reversed. It makes the connection between vertices be reversed as well. We need to reverse the second list to make this connection work right. We use a List Reverse
(List -> List Struct -> List Reverse
) node between the Mirror MK2
and `UV Connection (1).
List Reverse {Level: 2}
(Mirror MK2 [vertices ->]) -> (List Reverse[data <-])
(List Reverse[data -> ]) -> (UV Connection[vertices 1.1 <-])
Now, we create vertices in the middle of each line created. This vertices will be used later to define the pavilion top. We use Subdivide Lite
(Beta Nodes -> Subdivide Lite
) connecting UV Connection (1)
. Also, we use a Viewer Draw (2)
to visualise the geometry.
Subdivide Lite {Show Options; Show New}
(UV Connection (1)[vertices ->]) -> (Subdivide Lite[vertices <-])
(UV Connection (1)[data ->]) -> (Subdivide Lite[edg_pol <-])
(Subdivide Lite[New Vertices ->]) -> (Viewer Draw (2)[Vertices <-])
We will create a cosine curve to control the pavilion top vertices. First, we use a List Length
(List -> List Main -> List Length
) to track how many vertices we have, connecting it to Subdivide Lite
with New Vertices
output.
{List Length {Level : 1}}
(Subdivide Lite[New Vertices ->]) -> (List Length[Data <-])
Then, we use a Number Range (1)
to control cosine frequency, a Scalar Math (Multiply)
(Number -> Scalar Math
) node to amplify the cosine frequency, and a Scalar Math (Cosine)
.
Number Range (1) {Float: Step}
(List Length[Length ->]) -> (Number Range[Count <-])
(Number Range (1)[Range ->]) -> (Scalar Math (Multiply)[x <-])
(Scalar Math (Multiply)[Out ->]) -> (Scalar Math (Cosine)[x <-]))
Now we use a Scalar Math (Add)
to control the position on the Z
axis of the cosine curve, then a Vector In
(Vector -> Vector In
) connecting the Z
input.
(Scalar Math (Cosine)[Out ->]) -> (Scalar Math (Add)[x <-])
(Scalar Math (Add)[Out ->]) -> (Vector In[Z <-])
Now everything is ready to generate the cosine curve. We use a Move
(Transforms -> Move
) node to move the vertices to the pavilion top. We connect it to Vector In
and UV Connection (1)
. Then, we use a Viewer Draw (3)
to visualise the output and change the values of Scalar Math (Add)(Multiply)
to modify the pavilion top vertices.
(UV Connection (1)[New Vertices ->]) -> (Move[Vertices <-])
(Vector In[Vertices ->]) -> (Move[Movement Vertices <-])
(Move[Vertices ->]) -> (Viewer Draw (3)[Vertices <-])
Now is the time to create a shell for the pavilion. We use UV Connection (2)
connecting following this sequence: the first vertices list Vector Interpolation
output, the cosine vertices Move
output, and the second vertices list Reverse List
output. We use a Viewer Draw (4)
to visualise the shell.
UV Connection (2) {Direction: U; Make: Pols}
(Vector Interpolation[vertices ->]) -> (UV Connection (2)[vertices 1 <-])
(Move[Vertices ->]) -> (UV Connection (2)[vertices 1.1 <-])
(Reverse List[data ->]) -> (UV Connection (2) [vertices 2.1 <-])
(UV Connection (2) [Vertices ->]) -> (Viewer Draw (4)[Vertices <-])
(UV Connection (2) [data ->]) -> (Viewer Draw (4) [Poligons <-])
Now we can make this pavilion less “sharp”, using a Subdivide
(Modifiers -> Modifiers Make -> Subdivide
) node, connecting UV Connection (2)
(vertices and polygon) and UV Connection (1)
(edges). Then, a Viewer Draw (5)
to visualise the geometry. We can control how smooth the shape will be by changing the value of the Smooth
parameter.
Subdivide {Show Options; Falloff: Smooth; Grid Fill}
(UV Connection (2)[vertices ->]) -> (Subdivide[Vertices <-])
(UV Connection (1)[data ->]) -> (Subdivide[Edges <-])
(UV Connection (2)[data ->]) -> (Subdivide[Faces <-])
(Subdivide[Vertices ->]) -> (Viewer Draw (5)[Vertices <-])
(Subdivide[Edges ->]) -> (Viewer Draw (5)[Edges <-])
(Subdivide[Polygons ->]) -> (Viewer Draw (5)[Polygons <-])
Then make a group with pavilion nodes Ctrl +j
.
The final step is to adapt the panels with an external form. In this example, we use a Torus geometry. We use a Adaptive Polygons
(Modifiers -> Modifiers Make -> Adaptive Polygons
) and a Torus
(Generator -> Torus
). We have to connect Vertices and Polygons from a “recipient” Subdivide
output and vertices, edges, and polygons from a “donor” Torus
output. We can use a Viewer Draw (6)
to visualise the final result.
(Subdivide[Vertices ->]) -> (Adaptive Polygons[Vertices Recipient <-])
(Subdivide[Polygons ->]) -> (Adaptive Polygons[Polygons Recipient <-])
(Torus [Vertices ->]) -> (Adaptive Polygons[Vertices Donor <-])
(Torus [Edges ->]) -> (Adaptive Polygons[Edges Donor <-])
(Torus [Polygons ->]) -> (Adaptive Polygons[Polygons Donor <-])
(Adaptive Polygons[Vertices ->]) -> (Viewer Draw (6)[Vertices <-)
(Adaptive Polygons[Edges ->]) -> (Viewer Draw (6)[Edges <-)
(Adaptive Polygons[Polygons ->]) -> (Viewer Draw (6)[Polygons <-)
Then make a group of adaptive nodes Ctrl+j
.
Then you can play with the parameters.
…or change the Grease Pencil draw.
You can download the blender file here
Have fun.