Video summary
In this tutorial, Andy Pixel demonstrates a procedural workflow in Houdini for automatically generating bridges and roads based on terrain curves. The process begins with creating a detailed landscape using height fields, noise nodes, and clipping techniques to define water levels and plateaus. Once the terrain is established, the artist sets up a user-defined curve that acts as the path for both the road and potential bridges. By snapping this curve to the terrain volume and adjusting its resolution, the setup ensures the path accurately follows the ground geometry while allowing for elevation changes where necessary.
The core logic of the bridge generation relies on calculating the slope along the curve to identify areas requiring structural support. The artist computes the slope in degrees by comparing the curve's normal vector to a flat plane, then maps these values to determine which sections need to be elevated. By blurring this slope data, the workflow creates smooth transitions that lift the curve above the terrain only where steep gradients exist, effectively identifying bridge locations while leaving flatter areas as standard roads. This approach ensures that bridges are generated precisely where needed without unnecessary construction in flat zones.
Finally, the procedural setup separates the elevated sections from the ground-level paths to create distinct bridge and road geometries. The workflow uses color-coded attributes to distinguish between bridge segments and road surfaces, then splits the geometry into individual primitives for further processing. Each segment is assigned a unique ID to facilitate different modeling strategies based on length and type, such as varying bridge designs or retaining walls. The video concludes by showing how these procedural curves are swept into final 3D models, complete with guardrails, foliage, and foam, resulting in a cohesive environment that updates dynamically as the underlying terrain curve is modified.
Read the full video transcript
hi
guys andy pixel here and in this video
we are going to take a look
specifically at how we produce bridges
all right so we've kind of covered roads
a little bit
uh most notably the uh guard rails with
the curvature
video this time what we're going to do
is we're going to look at how to produce
the proper curves to produce bridges
here all procedurally so if i were to go
and move
this curve around you can see that my
entire environment here is actually
updating so all the
card rails are updating but the bridge
is also updating as i move the curve
around
to accommodate the terrain at that level
so what we're going to do is learn how
to produce
the proper data to produce a bridge
from curves all right so let's get
started okay so
let's get started by building our
terrain and bridges here so we're going
to start with the
grain but i'm just going to put this all
inside of one geo
container here so i'm going to drop down
a height field
and i'm going to change the size here to
200 by 200 just make it small we don't
need a large train for this
and then i'm going to go and drop down a
height field noise
node like so and i'm going to pick a
noise
that i like so i went with something
around
600 for the amplitude and about 129
for the element size and i can play
around with the roughness a little bit
really depends on what you're looking
for
that's going to be good and then let's
go and create a height field clip node
and for this one i want to kind of set
where the bottom of the terrain is and
so i'm just going to use a min clip for
this
so this allows me to actually clip the
terrain off so this is basically
going to be where all the water is for
this particular landscape and then i
want to do another clip and we need to
make sure that we get the height field
clip node
there we go and i want to clip off the
tops here
so you can also hit the compute range
and then just kind of move your way down
from there i really just want to create
these kind of plateaus
like so and then what i like to do is go
back to the noise here and actually pick
a
location for this guy i used negative 77
and negative 89 for the location
of the noise which gives me a nice place
to put a bridge it's really what i was
looking for there
and we could bring this down even more i
really want kind of a flat top
something like that it looks pretty good
uh you can also play around with these
clip strengths here
and the soft clip strength maybe get a
deeper channel going there looks pretty
good
all right and then i'm going to do a
mask clear i don't need that mask
anymore
and then i want to go and do a height
field distort so let's get a distort
node
distort by noise there we go and i just
want to
go and just kind of rough it up a little
bit make it look more interesting more
terrain like
looks pretty good all right and then i'm
going to do a visualize and i'm not
going to get all fancy with the
visualization in this particular video
here just want to get something so i'm
just going to do a compute range
and i'm going to get rid of all these
color knots here just by clicking and
dragging them
and i'm going to make this more of like
a darker mud
type color and then we're just going to
come over here and do kind of a
nice terrine green and i'm going to go
and clamp these guys here so get a
harsher transition
looks pretty good all right so i'm going
to select all these guys hold down a on
the keyboard and then left click and
drag upwards to organize those guys
i'm going to drop down a new grid and
this grid now needs to match the size
of this particular guy so i'm just going
to copy this parameter go down to the
grid here paste that into
the size option here so now we have a
grid that's the same size
and this is going to act as my water
plane so i'm just going to drop down a
color node and we're going to go and
give it
a nice water type color and then let's
just merge the two guys together here
by selecting both hold down alt left
click and drag off of the
knot there for the output see that one
more time there we go and now i've got
a pretty nice setup there for a terrain
that we can use
and the color here doesn't seem to be
coming through
all that great it's picking up a little
bit of the terrain colors there uh let's
just go and drop down a attribute create
node
and what i'm gonna do is uh call this
alpha i'm gonna give the water a little
bit of uh transparency i'm gonna put it
at uh 0.5
there we go that will work for our
terrain
so i'm gonna go and drop down a null
node we'll call this out
terrain all right so with that done
let's put a net box around this
stuff here so i'm just gonna select all
the nodes do a shift o
and we're gonna call this step one
call this create terrain and give a
color by hitting c on the keyboard and
selecting the
black swatch there or whatever color you
want now we are ready to
go and create our bridges one thing we
can do is make this a little higher res
so let's go up to our height field node
up here
and in the grid spacing let's do
something like 0.75 there we go so now
we've got much higher res
terrain there all right so let's take a
look at calculating the bridges from
a single user curve so let's drop down a
curve node here
and this guy is going to be our user
curve
so if you're building an hda this will
be exposed to the actual hda so it can
be edited in like the houdini engine
or outside of this particular geo node
and then i'm going to go down and hold
down
my alt control and left click and that
will template this
and then i can draw on top of my terrain
so if i hit spacebar 2 and hit enter on
the keyboard in the scene view here
and we'll just draw some sort of like
road like thing yeah
something like that looks pretty cool
all right i want my curve here to
actually sit on top of the terrain so i
can cast right down and
snap this to the train and so to do that
i like to go and drop down a transform
node just in case the user curve comes
in with values that are
in y and i just put the scale to zero in
y and that flattens it out and then we
can use a match
size node so let's drop down a much size
node and let's feed in
an object for the second input here so
i'm going to drop down an object merge
node and this is going to be called get
turing and i'm just gonna feed in
my terrain here so let's just drop this
guy down here like so
and um yeah let's uh pipe this guy into
here very cool
you can see the batch size node will
actually take into account the
second input's geometry bounding box
size so we can then use the justify
and set this to max so that the curve is
sitting right on top of the terrain
there all right so at this point i'm
going to resample the curve
and i'm going to start out with a high
value so i'm going to do something like
a 4
for this and then i want to make sure i
turn on my subdivision curves you can
see
here if i turn on my point display we
have a good resampling for this
particular road
here i'm going to start with larger
values just because we're going to work
our way down to smaller values as we get
more detail going here all right so then
we want to go and snap this to
the terrain so i'm going to call this
guy snap to terrain
and for the second input here i'm going
to feed it the
terrain there and for this i'm going to
utilize the volume sampling
trick that i showed you guys in a video
a little bit ago and so this is the code
right here so you can copy that i just
saved it as a preset
so that way i don't have to type it over
and over and over again
all right so now we're snapped to the
terrain perfectly you can see that it
missed the water
because this particular technique here
is only looking for volumes and our
height fields are volumes what we need
to do now is we need to go and
figure out how we get the curve to be
above the terrain here
right and so to do that we're going to
be doing some blurring and so i need to
go and
drop down a group by range node here and
just group the ends
you can also do it with backs as well
but i'm going to do it with a group by
range node this time
let's uh go to points and we'll set our
start end to one and one and we'll
invert it and that will
go and group just the end points there
which is perfect for us
all right so at this point i need to go
and drop down a polyframe node
and this time i'm going to type in n a
capital n for the tangent you can also
save a preset for that so
you can see i have a couple here all
right and that will create for us our
flow normal and then finally we want to
go
and get our slope here so i'm going to
call this
get slope because what i want to do is i
want to find the areas that have really
high slopes
in here and what that will allow us to
do is it'll allow us then to blur those
areas which will actually lift this
portion of the curve up
these areas over here don't have a high
slope and so they won't generate any
sort of bridges or anything like that so
let's do this
in order to do this if you haven't seen
the path slow production video i highly
recommend
watching it i'm going to call this a new
vector flat norm it's going to be equal
to the
current normal which is our flow normal
and then for that flat norm i'm going to
set its
y component to zero and then we're going
to normalize it just so we have a unit
length
of one so we're going to say normalize
and we're going to say
flat norm and then to get the actual
slope
in degrees i'm going to create a new
attribute called slope by
typing an f at attribute stands for a
float type of attribute and we're going
to say degrees
and we're going to get the arc cosine of
the dot product of the current normal
and
our flat norm that will give us our
slope in
degrees there and i need to type in dot
for this guy
i missed one there we go beautiful all
right so now we have our slope now one
way you can actually visualize this is
you can utilize the visualizers here
you've probably seen that i've used the
visualize node over here by just
creating a node or
you can also select node and hit x on
the keyboard alright or you can come
over here and you can right click on
this little guy
and you can say i want to create a new
visualizer by hitting this plus button
right here and i want to create a new
marker
and for this i want to go and look at
that slope value so i set the class to
points because it's on the point
class and i just want to set it as a
marker so now we have really quick
access to our visualizer
so you can see that we have all of our
slope values here and you can see the
area where there should be a bridge
we have some pretty high slopes so it's
a pretty good way to
find all this stuff now if you want to
turn off the visualizer just right click
this and just turn off the little check
mark so a little bit faster than using
the
visualize node all right so now we've
got the slope going there um i want to
go and find
the maximum slope that we have so let's
go and do an attribute promote so i'm
just going to go and type
this in here we're going to do max slope
and we want to go from point because
currently our
slope attribute is on the point class
let's go from point to detail we want to
take the slope
and we want to get the maximum value
let's change that new name let's call
this max slope
and let's make sure not to delete the
original there all right so with that
done let's go and drop down an attribute
remap node and this remap node is going
to
remap our slope into a value of zero and
one
all right so let's go and select the
remap node there and our original is
going to be slope
our destination our new name is going to
be slope as well so we're just going to
overwrite it and then what i want to do
is i want to get the maximum value from
this attribute promote so to do that
we're going to type in detail
0 for the first input and the remap node
only has one input so that'll work
and we want to get the max slope and we
want to
get the first index of that because it's
just a single flow value so now we've
got that maximum value and if i were to
go and look at the slope now
so let's turn on our marker that we made
you can see that we have a value that
goes from 0 to 1
depending on our max slope values all
right so we can use that now
let's go and blur this and let's
actually let me show you really quickly
let's untemplate our terrain here let's
go back to our marker by right clicking
on it and then we can go and edit the
marker now by hitting the little pencil
icon right here let's actually change it
to a color
and let's close this guy out and turn
off our point displays
so now you can see where our slope is
the most intense which is
right around where the bridge should be
which is great so we're going to then
blur that value so i'm going to say
blur slope and we are then going to
type in slope for the attribute to blur
we're going to turn off pin
border points and you can see now as i
move this guy that the visualizer will
update so you can see it's kind of hard
to see but there you go so i'm going to
set this up to something like oh i don't
know 200.
actually let's do 50. 200 is probably
going to be a bit much so i'm going to
set the step size to 1. so that just
gives us a really nice gradient
all right very cool what we can do with
that value is we can drop down another
attribute blur node
and we can then blur the position
so i'm going to use that slope value as
a weight attribute
so let's type that into the weight
attribute so what's going to happen in
the blur node is it's going to use that
0 to 1 value our slope value and it's
going to blur it more intensely
where our slope is more intense all
right so
let's go and do that so i'm going to set
this one up to about 200 and we are
going to turn off our pin border points
and we also want to make sure you can
see that when i move this slider it's
actually moving our endpoint so i want
to say
not ends up here or exclamation mark
ends and that will pin our endpoints to
where they were originally located
so now i'm just going to set this to
something like 200. all right so if
you can see now if i were to template my
original curve
you can see that the greatest changes in
the curve appear right around where the
bridge should be and these other guys
would be tunnels basically
based off of some sort of height
threshold all right so cool now we've
got our
curve that we want to use so i'm going
to drop down our wrangle node
and this one is going to be to set the y
pause i really am just interested in the
y position of this curve
and i want the x and z positions of this
curve all right so that's what we're
going to do here so to do that we're
just going to create a new vector called
other pause
and we're going to make that equal to a
point expression or
point function that is looking at the
second input
it's going to get its p attribute and
we're going to look it up by its point
number
and because both these curves are the
exact same point numbers that'll work
all right so at this point let's
resample this now let's go down to a
lower sampling rate this time i'm going
to do something like 1 this will just
give us more detail to work with
and let's also make sure we turn on our
subdivision curves
uh the other thing i forgot to do let's
actually set the
p dot y up here to our other pause dot y
there we go so now you can see we retain
the x and z
position but use the y position from
this curve that was
that has been blurred out so now we need
to go and find out
the height from the terrain that a
certain part of the curve is at
all right so to do that i'm going to go
and grab my terrain i'm going to drop
down
a another object merge node you could
always come up here and just copy this
guy and drag it down here so do an alt
left click drag so now i have my terrain
over here let's uh template it by
holding down control
and left clicking the template flag
we'll take a look at our curve here all
right so i need to go and sample the
terrain and figure out the heights from
each point
to our particular curve there all right
so to do this i always turn
to my trusty effects all right so we're
going to say find
height and for this just like what we
did up here
for the snapping to the terrain we're
going to do a volume sample because you
can see that we're returning the height
so we basically want to just copy
this same set of code here for the vex
and we want to paste it
into there but this time i don't want to
actually set
the height to the curve i want to keep
this particular portion of the curve
this time what i want to do is i want to
say f at disk to create a new distance
attribute that lives on each point and i
want to then go and subtract the current
points position from our height that we
just sampled
and i need to make sure this is a period
there we're going to negate that
and then finally i'm going to colorize
this just so we can visualize this
particular
distance value so i'm going to say at
dist so if at this
is less than negative 1 let's just start
there
so 3 feet then we want to basically give
it a color of
red so let's do one zero zero for red
else we want to just color it green
that'll just be
a road area so i'm just going to go and
pump that in there
we go and voila we now know if i were to
template my terrain again
turn off my point display you can see
everywhere where a bridge will be
considered right so you might have a
little tiny bridge there
you might have a little tiny bridge
there you can always get rid of those
guys and only take the really long ones
all right so now we know where all that
stuff is all right so we know a bridge
is going to go right here and this has a
potential for being a bridge
at this point then what we need to do
now is break off these sections of the
curves
from the green area so we want to get
just the curve that are all red
and just the curves that are all green
all the green curves will be the
roads and all the red curves will be the
bridges so to do that i'm going to use a
convert
line and we're going to convert all of
these
into individual segments or primitives
here perfect so i don't need to keep the
wrestling so i just turn that off
and i'm going to then go and promote my
color value
so i'm going to do attribute promote
we're going to promote this
from points to our primitive because we
now have individual primitives per
segment
you can see it creates a nice clean
value but it it is actually producing
like a yellow value so i do want to go
and get just the first match
so now we have a very clear cut between
those two guys
so at this point i'm just going to drop
down a split node and we're going to use
a little expression we're going to say
at cd
dot r is greater than zero and that'll
leave us with just the bridge curves
just for good measure let's set this to
primitives and now what we can do
is drop down a null node and we can say
out
bridge curves and then left click and
drag with alt held down and say out
road curves like so i'm just going to
drag these guys down because we're not
done yet remember all these
particular curves here are still broken
up in individual segments so i don't
want that
and so all we need to do is just drop
down a fuse node and a
polypath node and that will turn them
back into single primitives per
curve there and then finally we're going
to need a value for these
so we can loop through each one of these
guys and currently we have this prim
number that identifies each
bridge segment by itself but i need to
actually create a
id value for this so primitive all i'm
going to do is just go and
write a little tiny backs here i'm going
to say i at id
is equal to at premnum this will help us
when we
drop down a couple for each loop nodes
and
start working on the individual segments
so different bridges here because you
could
end up having different types of bridges
for the overall distance that it's
actually traveling like this one would
be a really big bridge
and this one would be a really small
bridge because remember it's based off
of its distance
value all right and let's just do the
same thing for the roads
and there we go so now we've got our
bridge curves and we've got our road
curves
last step here is just uh select all the
nodes do a shift o
and we will then go and call this step
two find
bridge curves and then give it a little
color
i tend to go for the black very nice all
right so now we've got all that data
you're pretty much good to go all we
need to do is drop down a couple sweep
nodes and then build our bridges
and we'll have some roads and bridges
and so after a couple of hours
uh this is what i came up with so i
literally just started with these
bits of data and the terrain so i did
just a couple of things
you know for the terrain for the water
um in order to get this nice cut out i
just used a boolean
so i just took the original drain and an
extruded version of the
water and then just bullied it out and
then just remeshed it to get a nice
mesh out of that and then moving on
um this was the final terrain right here
so nothing awesome to look at there
it's just really basic and then for the
road so in this case i took both curves
the
road curve and the bridge curve i also
made sure to put an attribute blur onto
the actual bridge so that way it's nice
and flat um i also went
up here and removed all the small
bridges so to do that
you would just drop down a measure node
and find the perimeter and then go and
delete
all the small bridges and then you could
do something else with them after that
maybe they're just like a retaining wall
type of structure so yeah then i ended
up with the roads
and then we got my final bridges which i
didn't really spend a ton of time on
this it's just really basic uh version
of the bridge added some foliage
just like so all just using a scatter
node nothing nothing really complex or
anything like that um i can walk through
the nodes here so i brought in the train
just added some point normals created a
really basic mask used a
mask from geometry node to mask out
where the path was
and then scattered it on using that mask
value as my density
for the scatter points and then just
copied some stuff to it some really
basic little poly models
and then i created the foam so for the
foam i use the ab seam so if you come
over to the
boolean node over here um i output the a
b seams
and then that allows me then to go and
um extract those particular curves with
the edge group to curve node so you get
those guys and then i just peeked it out
and then uh
created two more lines there and then
just did a sweep with a random
p scale on it and gave me something nice
and stylized there which i was going for
then finally the guard rails which we
saw
a couple videos ago in the procedure
modeling tips video series and then that
is that i ended up with this guy it
turned out pretty cool
i like it and then i also went and set
up a
basic uh karma render here for this
nothing crazy either
all the materials are all just principle
shaders there we go so
this file is available to all the
patrons on the any pixel patreon page if
you're interested definitely go check it
out
and uh so yeah that is how we do bridges
there's at least one way to do bridges
um you know what they're doing there's
a hundred different ways thousands of
different ways to do things so hopefully
you guys like that technique
and thanks much