How I built a realistic grass shader in UE5! Shader driven bend, clump, tilt, wind and more!
Summary
TLDRIn this comprehensive video, the creator shares an in-depth guide on crafting realistic animated grass using Blender and Unreal Engine. The tutorial builds upon a previous video that introduced a 2D wind system and grass animation techniques. Here, the focus shifts to advanced methods for achieving a natural and fluffy appearance in animated grass. The artist is inspired by the grass rendering in 'Ghost of Tsushima' and explores the potential of world position offset for creating dynamic grass features. The video delves into intricate details, such as reconstructing world positions, applying instance scaling, and utilizing vertex normals for random 2D directions. It also covers the creation of a clump map for added realism and the application of various shaders and techniques to manipulate the grass's appearance based on environmental factors like wind and landscape. The summary also touches on the challenges and solutions related to normal mapping and the importance of managing vertex count and LODs for performance optimization. The creator concludes by teasing upcoming content on foliage asset creation in Blender and the development of a related Blender addon.
Takeaways
- 🌱 The video is a tutorial on creating realistic animated grass using Blender and Unreal Engine, focusing on techniques for natural and fluffy animations.
- 🎨 The creator used Niagara to build a 2D wind system and dynamically generate a tiling wind texture, as well as animating grass and achieving a spherical projection trick.
- 📐 The grass mesh is non-traditional, with flat cards oriented towards the positive x-axis, and utilizes UV mapping for texturing and baking pivots, height, and random values for variation.
- 🌿 World Position Offset (WPO) is central to achieving the grass features, with the idea of controlling features and their randomization for a more natural look.
- 🤔 The video explores the Ghost of Tsushima game's grass rendering as inspiration, despite not having the same level of UI and rendering pipeline knowledge.
- 💡 A key technique involves reconstructing world position from scratch and converting it to an offset, which simplifies vertex manipulation for the grass.
- 🔄 The use of a 3x3 matrix to rotate each grass card randomly around the z-axis allows for more control and leads to more natural-looking grass.
- 🌬️ Wind effects are integrated into the grass animation, with the wind direction influencing how much the grass cards tilt, simulating a 'sail' effect.
- 🌄 A clump map is created to define areas where grass clumps together, adding to the natural and chaotic look of the grass field.
- 🎭 The grass shader includes features for controlling the scale, bend, and orientation of the grass, with texture maps used to randomize these features.
- 📉 The video discusses the importance of managing the vertex count and level of detail (LOD) to maintain performance, especially when using complex shaders and effects.
Q & A
What is the main focus of the video series?
-The video series focuses on explaining how to create realistic-looking grass using Blender and Unreal Engine, with a particular emphasis on techniques for animating and rendering the grass.
What was covered in the first video of the series?
-The first video covered the use of Niagara to build a 2D wind system, dynamically generating a tiling wind texture, and a simple way to animate grass using the texture. It also demonstrated a spherical normal projection trick.
What are some of the cool tricks showcased in the second video?
-The second video showcases various tricks to create natural and fluffy looking animated grass, including using World Position Offset for grass mesh features, orientation, and control over these features' randomization.
How does the grass mesh used in the video differ from typical grass meshes?
-The grass mesh used in the video has flat cards that are purposely undeformed and oriented towards the positive x-axis, which is not typical for grass meshes. This unique design allows for more control over the grass's appearance and behavior.
What is the purpose of using a 3x3 Matrix for rotating cards?
-The 3x3 Matrix is used to rotate each card around three axes, allowing for more complex and natural-looking rotations. This method also enables the creation of cool effects, such as random rotations and aligning cards with the landscape normal.
How does the video approach wind animation for the grass?
-The video uses a combination of wind direction from a texture and the direction each card is facing to modulate how much wind is applied. This creates a more natural response to wind, with grass blades acting somewhat like sails.
What is the significance of using a Clump Map in the grass shader?
-The Clump Map is used to create clusters of grass, adding more randomness and a natural look to the grass field. It influences the position and tilt of the grass cards, contributing to the overall visual complexity and realism.
How does the video address the issue of perceived grass density?
-The video discusses the use of Billboards or camera-facing cards to maximize pixel coverage and improve perceived grass density. It also explores techniques like pixel depth offsetting to give the illusion of depth in the grass.
What is the role of the landscape layer capture tool mentioned in the video?
-The landscape layer capture tool is used to bake the painted landscape grass layer into a texture, which can then be projected in world space in the grass shader. This helps to create a smooth transition between grass and other layers like dirt.
How does the video handle the challenge of normal reconstruction for the grass?
-The video describes a process of rebuilding a world space normal from scratch due to the complexities introduced by vertex offsetting and encoding a random direction in normals. It uses various techniques, including a Lerp function and a cheat method of luring the normal towards the tilt direction.
What are some performance considerations mentioned in the video for rendering grass?
-The video emphasizes the importance of keeping the vertex count under control, being aggressive with LODs (Level of Detail), and minimizing quad overdraw to maintain decent performance with a large amount of grass instances.
Outlines
🎨 Creating Realistic Animated Grass with Blender and Unreal Engine
This paragraph introduces the video as the second part of a three-part series. The creator discusses using Blender and Unreal Engine to make realistic animated grass. They recap the first video, where they used Niagara to create a 2D wind system and animate grass, and mention the Ghost of Tsushima game as an inspiration. The focus is on using world position offset to control grass features and orientation for a more natural look.
🌟 Advanced Techniques for Rendering Grass
The creator references an earlier video on industry-grade techniques for rendering grass and suggests viewers watch it for context. They then delve into the specifics of their grass mesh, which is atypical with flat cards oriented towards the positive x-axis. They discuss using UV mapping for textures, baking pivots and height into UVs, and random values for variation. The paragraph concludes with the idea of using world position offset tricks to achieve a natural grass appearance.
🤔 Exploring World Position Offset for Grass Features
The paragraph details the process of using world position offset to manipulate the grass mesh. It covers reconstructing world position, applying local position, and using baked pivots to center cards. The creator also discusses scaling, rotating, and offsetting the cards using various techniques. They touch on using instance position in world space and interpolating between positions to control card spread. The paragraph concludes with the challenge of rotating cards while maintaining their natural appearance.
🎲 Utilizing 3x3 Matrix for Card Rotation and Clumping
The creator explains using a 3x3 matrix to rotate each grass card randomly around the z-axis. They discuss generating a random 2D direction and using vertex normals to store this information. The paragraph also covers using action scripts and geometry scripting for processing the grass cards and ensuring consistent random directions across all LODs. The focus then shifts to creating clumps in the grass, using a custom tool in Unreal Engine to generate a clump map that adds to the grass's final appearance.
🌬️ Grass Clumping and Wind Interaction
This paragraph focuses on how the grass clumps are influenced by the wind and the landscape. The creator discusses using a lerp to control the grass's tilt according to the landscape normal and a texture to randomize the clump effect. They also explain how the wind texture's airflow vector can be used to modulate the wind effect on the grass, making it act like a sail. The paragraph concludes with the idea of using mathematical approaches to achieve a resting pose for the grass cards.
🌱 Maximizing Pixel Coverage with Camera-Facing Techniques
The creator discusses methods to maximize pixel coverage of the grass, such as using billboards or camera-facing cards. They explore different techniques to achieve a natural look while maintaining performance, including using view space and camera space for shadow passes. The paragraph also covers the use of a shadow pass switch node for creative effects and the importance of managing vertex processing to avoid unnecessary costs.
🎨 Final Touches and Normal Reconstruction for Realistic Grass
The paragraph details the final steps in creating the grass shader, including handling normals for both stylized and realistic rendering. The creator discusses the challenges of reconstructing world space normals from scratch and the decision to use a forward normal with a slight shift toward Z. They also cover the use of mip maps for opacity control, the application of a normal map in world space, and the importance of managing the vertex count and LODs for performance.
🛠️ Shader Optimization and Future Workflow
The creator summarizes the shader's components, including base color, roughness, specular, and opacity mask. They discuss configuring the two-sided foliage shader and the importance of keeping the vertex count low for performance. The paragraph concludes with the creator's reflections on the project, their decision not to use nanite or virtual shadow maps, and a teaser for the upcoming third video on creating foliage assets in Blender.
Mindmap
Keywords
💡World Position Offset
💡Niagara
💡Vertex Normals
💡3x3 Matrix
💡Clump Map
💡Billboards and Camera-Facing Cards
💡Subsurface Scattering
💡Mipmaps
💡Vertex Shader and Pixel Shader
💡LOD (Level of Detail)
💡Shadow Pass
Highlights
The video is a part of a three-part series focusing on creating realistic animated grass using Blender and Unreal Engine.
The presenter used Niagara to build a 2D wind system and dynamically generate a tiling wind texture in the first video of the series.
A simple method to animate grass using a texture and achieve spherical projection trick is showcased.
The video dives into advanced techniques to create natural and fluffy looking animated grass.
The Ghost of Tsushima game's grass rendering inspired the presenter to experiment with world position offset.
A custom grass mesh with flat cards oriented towards the positive x-axis was used for the tutorial.
The presenter used a UV map for grass textures and baked pivots, height, and random values into the UV space for more control.
World position offset tricks are employed to control grass mesh features such as band orientation.
A per-instance fade amount node is used to frame cards at a distance and smooth instance distance fading.
Instance scale is controlled using the Z component of a vector transformed from local to world space.
A 3x3 matrix is used to rotate each grass card randomly around the Z-axis using vertex normals for a random 2D direction.
The landscape normal is used to orient instances, allowing grass to match the landscape orientation.
A clump map is created to influence the tilt and position of grass cards, adding to the natural look.
The wind direction is used to modulate how much wind affects each grass card, creating a more dynamic animation.
A mathematical approach is taken to bend the grass cards into a resting pose, using sine and cosine functions.
Billboards or camera-facing cards are discussed as a method to maximize pixel coverage and perceived grass density.
Desert LODs are used for a smoother level of detail transition at a distance, despite the extra cost.
The presenter discusses the use of shadow pass switch nodes for creative shadow effects and performance optimization.
The video concludes with a discussion on the trade-offs between using world position offsets and the potential performance costs.
Transcripts
hey what's up YouTube this is the second
video of this three-part Series where I
explain how I created this realistic
looking Rass using blender and under
engine in the first video I explained
how I use Niagra to build a 2d wind
system and dynamically generate a tiling
wind texture I also showed a very simple
way to animate grass using the texture
and Achieve spherical repr projection
trick in today's video I'm going to dive
much much deeper I'm going to Showcase a
whole bunch of very very cool tricks I
use to create that natural and very
fluffy looking animated grass now a
couple of months ago I released a video
explaining a crap ton of Industry grade
techniques when it comes to rendering
grass some of which I will be rusing in
today's video so you might want to give
that video a watch first if you haven't
already all right let's get
started
now I've had an idea that has been
bugging me for a while now you see this
ghost of tsushima torque was very
inspiring to me I like a lot what they
did with their grass now I'd love to be
more knowledgeable when it comes to UI
and its rendering pipeline to be able to
try similar things using geometry
shaders and whatnot but for now I'm not
and I can't but there's still a lot you
can do with that good old world position
offset so I wanted to see how far I
could go with it hence why the grass
mesh I'll be using in today's video
looks like this now this will be the
subject of a dedicated video so I'll be
brief here but yes it's quite bizarre
looking not the typical grass mesh you
tend to use I have this flat cards right
they are straight purposely undeformed
and they are all oriented towards the
positive x-axis I use the first UV map
to well map my grass textures nothing
fancy I also used my data Baker blender
addon to bake this cards pivots in UVS
it's quite a common technique and I made
a video on the subject so feel free to
check it out I also baked the normalized
height in UV in the vertical axis and a
random value per card in the horizontal
axis very useful so that's the mesh I
exported to you and the idea was to try
and see if it was possible to build most
of the grass mesh features band
orientation and all using nothing but
World position ofet tricks and do that
in the hope that I could reach a much
more natural look by having a complete
control over these features and their
randomization so let's have a
look as as usual my favorite wall
position of the trick of all times is to
reconstruct a wall position from scratch
and convert it to an offset so let's do
that Zer subtracted by World position
that collapses all vertices to the world
origin because all vertices are now at 0
0 0 as simple as that so let's add the
vertices local position then subtract
the baked pavots in local space to
Center cards on zerin at that point
scale and rotation can be applied to
well scale and rotate cards around their
p points so I'm first going to use a
perir instance fade amount node this 0
to1 value is based on the instance start
and anle distance settings that's going
to frame cards at a distance and smooth
out otherwise very harsh instance
distance gning next let's apply the
instance scale here I'm going to assume
instances are uniformly scaled and that
the scale Z component is used to control
that uniform scale so let's create an
Vector transform it from local to World
space then get that vector's length and
that the instant scale along the
z-axis and maybe add an extra parameter
to have further control over that scale
cool it's working next let's offset
cards so they recover their original
World position that's just a matter of
adding the big pivots transform from
local to World space and here's another
neat trick instead of offsetting cards
using their pivots in World space I can
use instance position in worldspace
cards are going to be centered on that
single instance position not very
interesting but then I can lure between
these two positions and control how much
cards are spread apart right keep in
mind that may mess with occlusion
cutting so you might want to increase
the mesh bounds a bit depending on the
amount of offset applied on average just
to be on the safe side neat for now
let's set this to one so that's a base I
can already somewhat work with cards are
correctly located at their pivot Points
scaled based on the instance Z scale and
they all remain straight regardless of
the instance rotation so that's great
but obviously they all face the same
direction and are pretty boring looking
still so first I'd like to rotate
cards applying rotations can be tricky
I'd like to rotate cars around the taxis
randomly I suppose but although possibly
tilt CS towards a certain direction the
side likely need to apply a rotation
around the X and Y axis as well and
rotations are a bit tricky to stack it's
not impossible but that's a lot of
trigonometry just to oron cards
fortunately there's a better and simpler
solution I'm going to construct three
axis and use a 3X3 Matrix to rotate each
card and this method is actually going
to help me do crazy cool things but
let's start simple for now I'm going to
assume the z-axis is still the Z World
axis now I want to rotate cards randomly
around that z-axis how to do that well I
just need to tell that mesh that x-axis
of yours isn't the world x-axis anymore
but say that one and your y-axis is now
just the cross product between these two
and the 3X3 matrix multiplication will
result in vertices matching that new
coordinate system as simple as that now
I could mathematically generate a random
2D direction to create a unique x-axis
spare card but that comes at a cost a
better solution could be to compute that
AIS ahead of time and vertex color could
be used for this UVS as well you could
bake a random 2D Direction per card in
UVS right but I used another method I
used vertex normals I'll explain this in
a minute but I'm actually going to
generate my own normal in World space so
the normal stored in each vertex is kind
of irrelevant th why not make use of
that normal to store a random 2D
direction for free right to do this I
updated my data Baker blender addon it
now can generate a random 2D or 3D
Direction and bake it in vertx color or
normal
sweet as I note I also try to do this
using an action script and geometry
scripting but I hit some kind of road
block but still I'm going to to mention
it real quick so let's have a look at
the action script first it's made to
work with static mhes I get the selected
assets Loop through each static mesh
construct a dynamic mesh then for each
LS copy that LOD then I use the split
mesh by components function so that
essentially does that each card becomes
a unique Dynamic mesh right so then for
each card I generate a random 2D
Direction and store that direction in
the vertex normals next I open that c
card to at first an empty Dynamic mesh
so that reconstruct the grass mesh card
by card right and once all cards are
processed and merged into that single
Dynamic mesh I replace the original
static mesh ass set with it at that LOD
index and RSE and repeat for all lods I
also make sure to use a stream when
generating that random Direction so all
lods generate the same random direction
for a given grass card super important
all right let's have a look at it in
action then so that's the mesh I'm
starting with normals are oriented the
same way as
expected right click and click Generate
random 2D
normal and VOA see each card stores a
unique 2D Direction in the vertex
normals and that direction is consistent
across all
[Music]
lods until it is not because a given LOD
May simply delete cards so that array of
components may not be consistent between
lods and thus there's no easy way to
make sure the same normal is shared
between cards of different lods if that
makes sense plus because this approach
navely splits components while a single
grass card may be made of multiple
meshes right and thus would need to have
the same normal and yet these meshes
won't because they will be treated as
different components and I didn't find
an easy way to automate this you could
manually paint poly groups and split by
poly groups but that's not such a
pleasant user experience so in the end I
did that in blender to make sure allies
share the same data all right back to my
worldall position of seig again then now
that the vertex normal still that random
2D Direction per card I can use it as a
new x-axis and again the remaining y-
axis is simply the cross product between
these two unit orthogonal vectors one
last step just make sure to turn on two
sided here and Tada randomly rotated
cars
neat now let's say I want to allo oron
cards according to the L
landcape assuming this setting is set to
True these instances should be oriented
to match the landscape normal right so a
given instance Z Vector transformed from
local to World space gives me the lscape
normal at that instance World position
just keep in mind that a vector
transform applies both the rotation and
scale so here I need to normalize it to
get a unit Vector unless that instance
isn't scaled in Z but let's be on the
safe side and normalize it anyway so
let's use that unit Vector as the new
z-axis however at this point I need to
use one more cross product the reason
for this is simple I know have this sled
up Vector right and this flat 2D
Direction so to build the remaining axis
a single cross product between these two
vectors give me this third vector and
you can see that those three vectors are
not orthogonal so that 3x3 Matrix isn't
going to result in just a rotation but
is going to deform the mesh in an
undesired way so I first need to do a
cross product between these two that's
the first axis then then do a second
cross product between that one and the
vector that's my second axis and the
vector can be used as is as the third
axis those three vectors are not
orthogonal cool feed them to that 3x3
Matrix make sure to normalize cross
products when using nonorthogonal
vectors though and voila cards now do
indeed match the landscape orientation
great I can then use a l and control if
I want straight up or smed cards and
even exaggerate the effect the landscape
has on those cards orientation very cool
let's keep iterating on that Vector
though because this Z Vector is
normalized and as long as it doesn't
equal that Vector here that 3x3 Matrix
is well defined and stable so I can
shift this Z Vector in X and Y as much
as I want to til cards more and more so
I could very well use a texture of some
kind to shift that a vector in X and Y
and tilt cards in arbitrary directions
and create clums of
grass
turns out creating clums played a key
role in the final look so to create what
I call a clamp map I tried different
things I first used blender to generate
a ping height map then beg the normals
to get the X and Y Direction but that
was tedious and the result wasn't too
convincing I then tried to artistically
paint arbitrary directions using CR and
its NE warp mode but I still didn't get
the result I wanted and it was toed to
paint as well so next I I Tred to build
a tool in a new engine to generate that
Clump map for me it's nothing too
complicated but turns out it worked
really well it's made with an editor
utility widget here I have a bunch of
single property view widgets just have
to call set object on yourself and make
them point to a viable within this
blueprint and that's it UI creates a
widget for you to tweak that viable neit
I Alo made a simple button Nothing Fancy
on click event I call this function here
I do a bunch of safety checks nothing
important create the Rend Target get the
set path draw a bunch of stuff on that
Rend Target and then call this create
static texture function and W that tool
generates a texture and saves it in the
current asset browser
directory so let's have a look at this
draw clamp function really quick it's
nothing too complex here I create a r
Target then I create a dynamic instance
of what I called a brush material I then
call B draw to start drawing on the
fromont Target on a loop a bit more
efficiently and using a for loop I draw
that brush dozens or hundreds of times
each time I vary the brush parameters
and where it's drawn at so it's like the
tool does a single brush stroke maybe
here then maybe there there and so on
and so on using an additive process but
it doesn't draw just a simple spherical
gradient well almost but not quite I
compute the 2D position Delta between
the brush position in UV space and UVS
that Delta is then safely normalized to
derive a radial Direction UVS are also
started with a noise node to create
something a bit more intricate something
that has a bit more flow to it right
then that radial direction is masked
using a billionaire sphere mask and the
reason for this billionaire mask is
quite simple but important again I'm
going to use this Clump map this to the
noise texture to shift that Z Vector
here the one used to til cards right so
to create clumps I want to orient cards
toward the single point and that's what
this radial direction is going to do
it's going to shift that Z Vector toward
that point the thing is that may result
in cards Crossing each other at the
center point and that doesn't look too
great hence the Bonaire mask to fade in
the effect but also to fade it out near
the center point and prevent that from
happening now one more important thing
that brush material is following a
principle I explained in the previous
video it's duplicated and offsets three
times to make it tile and ensure that
the clump map itself does tile so that
brush is drawn and randomized a few
hundred times and I end up with that
kind of very organic noisy looking
texture and it works surprisingly well
to create clamps to add a bit of flow to
the grass and whatnot let's see how it
can be applied to the grass Shader I
could use the absolute worldall position
to project that texture in w space right
but that could deform the mesh quite
unpleasantly because two vertices at two
slightly different world positions could
sample an to slightly different
direction from that Clum map so I'd like
to get a single quote unquote Clump
sample pair card well easy enough use
the be pivots inwards space as texture
coordinates and that's it then add this
X and Y offset to the Z Vector before
it's normalized and voila cool but even
better I can randomize the texture
Coates and make that Clum map look a bit
more chaotic and here again there are so
many ways to do this here I'm simply
going to offset the world space texture
coordinates with that 2D random
Direction each card stores in the vertex
normals as simple as that you may also
add the pivots in local space same but
different so zero of set and the Clum
texture is sampled as is and is
specially coherent if that makes sense
and the more offset added the more
random it looks basically and it's cheap
to compute keep in mind that randomizing
texture cornetes like that usually comes
at a cost if I'm not mistaken it's my
understanding that this is generally not
a very friendly thing to do for your GPU
cash but oh well anyway voila grass
clums it adds a bit of chaos to the
picture and I kind of like it speaking
of clamps it's one thing to influence
the Tilt but what about the position
well that's precisely what this lurp is
for remember so I can very well control
that lurp with a noisy looking texture
of some kind and add even more
Randomness to the picture now here the
effect is kind of limited because the
Clum position is basically instance
position in an ideal world it would be
an arbitrary position and this could be
done using a 2d distance field something
to
[Music]
try at this point you may think this Z
Vector could be used to til cards away
from the wind and you're absolutely
right same exact principle I'm going to
use the same setup to sample the wind
texture and have the ability to break
the special Coran a bit and add some
Randomness to the wind
animation but I'm also going to do
something cool remember cards all face
the same direction at first and I rotate
them myself with this Matrix here this I
simply just know the direction each card
is facing plus the value sampled from
the Twin texture isn't just a scalar
value it's not just how much wind to
apply it's actual to the air flow the
wind velocity so I can safely normalize
that wind velocity and get the wind
direction and use a DOT product with the
direction cards are facing to modulate
how much wind to apply this might be
stupid but I figured a grass blade is
quite a flat piece of geometry so I
suppose it kind of acts as a sail and
much less reacts to the wind when it's
not facing it although realistically
it's probably negligible in the ground
scheme of things I'm not sure if that's
even something that can be observed
still it's quite cheap to implement and
it brings some extra Randomness to the
wind animation so why not it's fun to
try
things next I can use the topd gradient
I back in
UV and a l to fade in that offset along
the grass length and create some kind of
curvature
alternatively I can simply multiply each
of these two offsets to create
individual controls for the curvature
for the clump offset and for the window
set why
[Music]
not for things are happening we are
making good
progress now assuming there's no wind
and no Clump the grass still looks quite
naturally straight and rigid I'd like to
bend those cards and make them have a
nice resting pose right and again there
are many solutions to do this you could
bake a 2d curvature map similar to what
epic did for the grass in fortnite you
could maybe bake more Target in vertex
colors or UVS but I personally went with
a mathematical approach it uses a sign
and a cosine but it didn't measurably
impact performance so why not one thing
to keep in mind and I really should do
more research on that subject shaders
and gpus are complicated nothing scales
linearly meaning at times you may use a
sign and not even pay its cost occupancy
may be low for any reason the GPU may be
waiting for a texture to be fetched from
memory or something and this have
nothing else to do but math for free
while welting as long as it's not
dependent on what the GPU is waiting for
in the first place right don't quote me
on that though I'm for sure not an
expert and it's definitely out of the
scope of today's video anyway so back to
my mathematical band this HS code is
pretty much identical to the band
modifier I shared on my Twitter a while
ago it does just that it bends the mesh
around the x-axis and that's why the
grass mesh is exported with cards all
facing towards the x-axis only once
cards are bent do I apply the rotation
Matrix now this hrsl code not only bends
the mesh but also outputs the bend
direction if that makes sense and that's
my starting point to generate a worldall
space normal but more on that later on
let's stick to the worldall position of
set for now so this band amount is
driven by some noise texture to create
some variation
right I also use the wind's X and Y
magnitude to decrease band amount and
that creates a super interesting effect
I think grass is naturally curved when
standing still but is straighten the
stronger the wind
Force
plus the more wind the less that other
offet participates in the overall Z
Vector computation proportionally right
because of the normalization here so the
grass may be initially tilted to point
towards a certain direction because of
the landscape or the clump effect but it
will reorient itself to face the wind
the stronger the wind blows very cool
all right we are getting
[Music]
there super important thing when it
comes to grass is what I call the
perceived grass density ring on cards is
good for performance but it obviously
comes with a d side cards are visible
until they are not thus costing vertex
processing for no pixel
coverage using Billboards or camera
facing cards obviously solve this issue
pixel coverage is maximized regardless
of the view Direction Right but it's
quite an old school technique and Bill
BS can be quite apparent and OD looking
well let's try to make the most of this
technique anyway what would be the ideal
solution here I want for each grass card
to remain curved and bent and randomly
rotated and i' want to maximize pixel
coverage meaning make each triangle face
the camera as much as possible all right
let's start simple let's get rid of that
rotation Matrix and the B hlsl node as
well for now and let's use a matrix to
rotate these cards toward the camera
easy enough let's transform a z Vector
from view towards space and derive an
XYZ coordinate system from it okay the
billboard effect is quite apparent
indeed let's first get rid of the most
Shing part of it the
Tilt so let's get rid of the Z component
here and normalize the resulting 2D
Vector however that 2D Vector can now be
null when looking straight up or down
see if so the direction to use instead
is a y Vector converted from view to w
space so do that if the square length is
close enough to zero use that y Vector
instead cool the billboard effect is now
only two dimensional that looks a bit
better then I apply the band effect see
that's kind of cool the mesh kind of
rolls on itself to face the
camera now The Wider the grass cards the
more apparent and unappealing this
effect is going to look but here I have
quite thin cards for the most part so
it's
okay hold on let's press pose for second
view space means the point of view of
whatever rers the geometry thus during
the shadow pass that's from the lights
POV and thus Y cards face the light
during the shadow path and the camera
during the main path not ideal but to be
honest it's not even that noticeable
with plenty of grass
around you may still want to consider
using camera space instead that ensures
Vector transform is made from the
camera's POV even during the shadow path
there's no right answer here both of
their pros and cons for this specific
effect got to pick your poison on one
hand you have a different but stable
Shadow when using a view transform on
the other hand you have a consistent but
unstable Shadow when using a camera
transform by unstable I mean Shadows
kind of disappear when cards are
perpendicular to the lights Direction
and cards flicker a bit at that point as
well again that's only something that
can be really noticed with individual
cards and not that much of an issue with
tons of grass blades around so I
wouldn't worry about it too much you can
Al of course use a shadow pass switch to
have further control over what's
happening during the shadow pass maybe
disable the camera facing logic onar or
something up to you but enough about
Shadows now that cards face the camera
let's rotate them once more hm I'm kind
of back to square one cards are
obviously no longer facing the camera
because they are made to do so before
they are rotated however it needs to be
done that way because the camera facing
logic needs to be applied apped before
the bend effect else you get something
that looks really
bizarre and that bend logic needs to be
applied on x-axis aligned meshes so
before cards are rotated so this SE on
paper applied in the correct order but
break the camera facing logic hm quite a
puzzle so what's the solution well again
the issue is that cars are made to look
at the camera before they are rotated so
what if I could take that rotation into
account when Computing the camera facing
Matrix instead of using the actual 2D
view Vector I'm going to use that same
Vector but rotated by the inverse of
that upgoing c rotation so that once the
card rotation is applied that view
Vector is indeed the actual view Vector
that sounds complicated but it's not if
I rotate those cards with a matrix let's
un rotate the view Vector with an
inverse Matrix and because I work in Tod
space here it can be simplified to just
this so I'm going to un rotate that view
Vector with a c forward Vector used here
and that's
it voila this maximizes pixel coverage
while still allowing cars to be randomly
bent and rotated now you might think
this looks too weird and indeed it does
a bit but that's only really because
we're looking at a single grass mesh
here and so it becomes quite apparent
but in context the effect is pretty much
invisible yet it plays a huge role in
increasing the perceived grass density
this is without the camera facing effect
and this is with without with quite a
visible difference in Grass density but
same Vex count and it's not that
expensive to compute neat and that's
prettyy much it for the wall position of
set control the scale Bend position
clamping and orientation clamping with
textures to randomize these features and
you can get something that looks quite
natural speaking of scale let's add one
last thing to this W position of set
logic my stylized grass Shadow made use
of runtime viral textures to do plenty
of cool things for instance they were
used to match the landscape color but
for realistic grass I don't feel like
that's an absolute necessity although
it's common practice in AAA is to at
least give a bit of tint to the grph
based on the landscape color again it's
up to you I also used the runtime vual
texture to do a landscape projection and
the same trick could be used here as
well but I decided against it it doesn't
contribute that much visually on a is do
come at a cost plus a shadow that makes
you of aties is usually a bit more
Troublesome to migrate to other projects
it was definitely an issue for people
who tried to reuse my style as grass
Shader so this time I decided to not use
AES but that made me miss one very cool
trick if you remember the grass layer I
painted onto the landscape was Al
embedded into a nity to create some kind
of mask and smoothly shrink cards Bing
onto other layers dirt and whatnot and
to create a smoother and maybe more
natural looking transition and I kind of
wanted to do that still for my realistic
glass Shader I like a lot what this
technique adds to the overall look but
how to do that without air is well a
good old texture will do just fine this
method is unscalable and isn't likely to
work for a large open world right but
for most use cases it's still a viable
option so I built a tool similar to my
SC capture tool I released on my Paton
but simpler basically it lets you select
a landscape and a material and that
material is meant to put the painted
layer you want to capture click that
button and voila that's my landscape
grass layer baked into a texture it can
then be projected in World space in the
grass Shader using that offet and size
super easy and obviously that can be
used to drive the card scale and
smoothly shwing grass bleeding on the
dirt layer and do other cool things
that's without and that's with without
with
[Music]
cool normals oh boy buckle up it's it's
one thing to compute an offset for
vertices but fixing normals is usually
even more complicated the more ofet shig
guns you do the more complex that
usually is and at one point I find it
easier to just rebuild a world space
normal from scratch rather than fixing
up an existing one plus remember I
encoded a random Direction in normal so
I kind of shot myself in the foot here
I'll definitely have better luck
rebuilding a world space normal from the
ground up but what kind of world space
normal though because I feel like there
are schools of ss if I may say so for
stylized rendering the common method is
to have upward normals to unify the way
cards and the underlying ground are lit
and have something that looks a bit
easier on the eye for realistic
rendering the way to go at least on
paper is to work with the default vertex
normals if that makes sense and then
rely on a Shader to make the light bleed
through the geometry and prevent back
faces from being incorrectly lit and
looking too dark in UI you may do this
in many ways you could create your own
solution use subsurface cattering or
best use the two-sided foliage shading
model plus that Shader I believe
automatically set some variables for
Lumen to properly work with two-sided
cards but I'm not entirely sure on that
something I read a long time ago anyway
H there's nothing preventing you from
both tweaking normals and using some
kind of subsurface cattering right and
to be honest I don't think there's one
right answer even for realistic grass
both methods of their pros and cons
fortunately I'll be able to choose
between one or the other EAS and see
which one works best all right let's
give it a go first things first this is
a bit too much to work with so I'm going
to create a much simpler test SC I'm
going to use a single mesh with just
four cars and four directions encoded in
normals then I'm going to disable the
camera facing logic make sure the
material uses World space normals and
disable two sided here just to make sure
faces are correctly oriented before I go
any further and turns out they are not
so I must have messed up this 3x3 Matrix
oopsy see let's flip this axis and that
one better Alo that likely means I need
to flip that right Vector here as well
so let's
check yep cards are rotating the wrong
way now so let's do
that okay fixed sorry about
that next I'm going to switch to the
world normal buffer and let's add a
sphere while I'm at it just to have a
reference to work with okay I'm first
going to get the bent of Vector this
node
outputs this node works on x-axis
aligned meshes if you remember so the
normal is a 3D Vector but lies on a 2d
plane right to choosing between an
upward and a forward normal is just a
matter of swizzling components I'm going
to take the absolute value for the Z
component though I had a bug on this
fixed it and at this point I'm too tired
to ask why so that's the upward vector
and that's the forward Vector so let's
use a LP to select one or the other and
let's plug that in the matal normal pin
oh an error that's just because this
local position here is only available
for vertices not pixels basically so the
pixel Shader complains about it just
have to use a Vertex interpolator to fix
the issue which is a good thing actually
because I definitely wouldn't want to
compute this per pixel okay so working
with x-axis align cards at first means
the normal should face positive x-axis
at first and that's correct and as the
cards curve normals gradually shift
towards the Z direction as expected
using end up War normal same thing
except that we start here on the sphere
and end up around there same Arc but
different starting point so that works
great next I need to rotate those
normals the exact same way I rotate
cards right so do the very same
transform Matrix and
done this card is correct and LS to the
Z Vector this one is good that one is as
well and that one too now let's add some
fake wind to tilt cards and make sure
it's behaving as
expected and that seems to work normals
shift toward the right direction great
now let's see what happens if I choose a
forward
normal that card seems good normal start
here and end up around here with the
Tilt so the shift is correct however
that one doesn't seem to work and the
reason is simple that normal is a lined
with a tilt axis so that Matrix results
in no Visible Changes bummer and this
was a huge puzzle I spent way too much
time trying to find Anan solution I
ended up finding a worko a huge cheat if
I'm being honest but it works I'm going
to lurp the war normal towards the til
to the direction the greater the Tilt if
that makes sense and that's going to
ensure the wind and clim features have
an effect on the normals and th the
lighting regardless of what normal I
choose upward or forward normal and that
regardless of the cards forward axis as
well quite a mouseful and I'm not even
done there's one more tricky part adding
a normal map normal maps are usually in
Tangent space so relative to a 2d
surface and so applying a tangent space
normal map when you have nothing but a
world space normal can be tricky usually
i' use a transform Vector to go from one
space to the other but sometimes that
doesn't go according to plan the reason
for this is I think because tangents are
computed based on UVS and vertex normals
and so messing with normals can break
tangents I suppose it's something I've
experienced with my waterfall cool as
well when tweaking normals so here I
might have shot myself in the foot by
doing Shady stuff with the vertex
normals but nothing to worry about let's
think about it for a second that normal
map is baked in Tangent space meaning
relative to this planer surface and so
the z-axis points that way x-axis that
way and y axis that way well it's just a
matter of swizzling vectors to reorient
that XYZ system and then rotating the
resulting normal according to my
reconstructed wall normal meaning I'm
going going to say hey tangent space
normal map that z-axis of yours is no
that one your y AIS is one obtained
using a cross product like so and your
x-axis is the result of this second
cross product now this could be done a
bit more carefully with safe
normalization and so on but oh well I
battle tested it and haven't noticed any
issues and at this point I'm too lazy
and voila I successfully remapped this
tangent space normal to World space
according to the cards orientation Bend
and the Tilt inherited from the wind and
effect on top of having extra artistic
controls do I want upward or forward
normals one looks better in blow
daylight the other a bit better at
sunris and sunset well can't have both I
suppose although why not after all let's
mainly use a forward normal but slightly
shifted toward Z to get the best of both
worlds o quite a puzzle that normal
reconstruction almost got the best of me
but I'm glad I got it working moving
on r regarding opacity first I use theer
elodes to have a smoother transition
between elodes because they have to be
carefully managed here due to the costly
Vex Shadow Tri count must be drastically
reduced at a distance and desert lods
are great to make the level of detail
transition a bit less apparent desert
lods come at a small extra cost though
something to be aware of next I use
desert mask opacity quite uncommon for
grass I suppose but I feel like that
helped me get smoother edges and Achieve
that fluffy look there's one thing to
keep in mind though that's my grass
opacity texture and me maps are going to
turn that into a mush of great values
especially in my case I was probably too
aggressive with packing so at a distance
cards are going to be somewhat
transparent because of that dessert
masked opacity kicking
in there are two solutions probably more
but I know two first you can toy with
these options to tweak how me maps are
generated that may help although UI has
this option I'm not sure what it does
under the hood exactly but it seems to
ensure certain values are maintained
across the Meep chain see there's quite
a difference in brightness and that
helps to prevent meeps from reaching
that desert opacity threshold value
second solution you can manually tweak M
Maps Photoshop and even allows you
to do this here's a method with
just have to have a first layer named
like so duplicate it reduce its size by
half and name it MIP map
one rinse and repeat until you reach a
size of 1 pixel by one pixel and that
the meip chain then export to DDS with
the following options import it in UI
select leave existing mips in the
texture asset and voila you can manually
customize each meip so maybe unsure that
desert opacity threshold isn't reach in
certain mips and done that custom me
workflow can also be used to do plenty
of cool things you could for instance
embed some kind of fade in or Fade Out
based on distance in mips say me zero is
totally black why not see I didn't add
any logic to the the Shader yet I built
some kind of automated feding effect
that's just a MB zero on the deser
opacity doing that effect nothing else
quite cool it's Al commonly used to
reduce specular highlights in the
distance so you could cheat a bit and
reduce the value of your specular map
and increase the value of your roughness
map at a distance plenty of cool tricks
to do with meeps especially in VFX and
Tech art you can embed extra data in
meeps and all Epic did something like
this for their win system on fortnite
super cool one more Passage trick you
can use a shadow pass switch node to do
bizarre things for instance you could
say hey cards are entirely transparent
when rendered in the shadow path or hey
cars are completely opaque that's going
to increase the shadow coverage quite a
bit and make the grass look thicker and
more dense but it's now quite apparent
that Shadows are casted from the
geometry and the geometry alone so you
could choose to do this still but in the
distance maybe use a switch that is
enabled on the material instance used on
distant lods that may help to create a
dancer grass in the distance that's
without and that's with keep in mind
that now may make the LOD transition a
bit more noticeable next trick at a
close wrench you could say do the
opposite you could use deser jumpol AA
to fake light bleeding through the grass
and casting a weaker Shadow super simple
yet very effective I was made aware of
that trick on Twitter so shout out to
you guys super cool that shadow pass
switch know could also be used in the
wall position of that logic to do crazy
things like say double the grass card
size during the shadow pass to increase
Shadow coverage I'm not sure why you
would do this but there are plenty of
cool things to
try to get a dense enough grass well you
need quite a lot of grass plates but
it's unlikely you can afford one single
grass card or mesh pair grass blade
that's probably too much got to find
some kind of in between and have cards
with more than a few grass blades on
them right that tends to look quite flat
and old school though but adding some
pixel depth offet may help to get rid of
that boring flat card look here I simply
rendered a random value perir grass
blade and I simply use that texture to
push pixels away in camera space super
simple but it creates the illusion of
certain grass blades being further away
from the camera and gives a bit of
depths to the grass
cards now again that texture is going to
turn into a mush of values at a distance
with mid Maps right and because pixel
depth of set creates self shadowing
artifacts with Dynamic lighting it's
probably best to ensure that at a
distance that dep's value from the
texture isn't average to a constant
value it's not that big of a deal but
here personally I gradually FedEd out
that depth by fixing mips manually
arguably that's not going to make a
noticeable difference especially
considering Shadow maps have limited
range anyway but I thought it was worth
mentioning I'm not sure how it be
behaves with virtual Shadow map though
something to
check the rest of the Shader is super
straight forward so I'm going to Bree
through it first base color nothing
fancy I'm just using a simple texture
roughness and specular just using two
textures as well opacity mask already
explained World position of set same and
normal and pixel depth of set as well
here I configure the two-sided foliage
Shader so it needs a subsurface color
I'm just reusing the base color really
but you could use the texture and the
material opacity controls the
transmission amount zero is fully
translucent and that's it so the pixel
Shader is actually quite simple and
cheap the vertex Shader however there's
quite a lot going on thus yes this grass
definitely has a cost so it's really
important to keep the vertex count under
control and be quite aggressive with
lods and prevent as much quad overdraw
as possible still with a large amount of
instances in a somewhat Long View
distance performance remains quite
decent I'd say please note I'm not using
nanite nor virtual Shadow Marx here they
both are great but they come with down
sides I'm not yet comfortable with
namely they don't cope well with World
position offset although it's gotten
much better recently and considering the
idea behind this whole project was to
see how far I could go with World
position offsets I chose to stick with
what I know and what I'm familiar with
and Shadow maps and non Nite meshes are
still Rock Solid anyway and I feel like
I sort of achieved my initial goal I
feel like I managed to recreate most
features presented in this Tech talk but
at what cost and is it worth it I
personally feel like it's a bit much
especially the normal reconstruction
part where it's leaning a bit too much
on the hcky sketchy side of things for
my own taste but I'll let you be the
judge of that it was a fun thing to try
on a very good exercise anyway vo that's
pretty much it as promised the third
video is coming up soonish I'll cover my
workflow for creating foliage Assets in
blender and I'm actually working on a
blender addon to hopefully facilitate
this process I as mention a few other
things it should be quite an interesting
video in the meantime if you want to get
your hands on this project files are
available as a tier three reward on my
patreon I also release the lscape layer
capture tool and clamp map tool I
mentioned during the video as tier one
reward that's it I hope you found the
video useful or entertaining or both and
if you did feel free to leave a like and
consider subscribing to my YouTube
channel we're slowly growing so thanks
to you all thanks so much for the
incredible support on my patreon as well
I just wouldn't be able to do these
projects and videos without you so my
props to you all you are definitely
noticed and much appreciated all right
thanks so much for watching I'll see you
in the next video take care of yourself
bye-bye
[Music]
[Music]
[Music]
Ver Más Videos Relacionados
5.0 / 5 (0 votes)