Friday, 6 December 2024

Tech Art Fall Final Project 2024 - Sand Shader



    Our capstone game Husk Planet cites Journey as an inspiration for the art style, so I wanted to try my hand at make the sand shader within Unreal. I found this incredibly helpful tutorial by Alan Zucconi that describes in detail how he achieved this shader within Unity, as well as a download for a demo Journey scene on Github by AtwoodDengthe GDC recording with thatgamecompany's John Edwards explaining how they did it, a sand shader tutorial from Ben Cloward and a Unreal Engine Desert Guide by Gatyh Interactive. I also found a post by Gastón Zabala on his Journey inspired shader inside of Unreal. All of these resources were heavily influential in developing this project. 

The Landscape

     I followed this tutorial here for the desert geo: https://www.sidefx.com/tutorials/procedural-desert/


    Basically you start with a heightfield and then generate several types of noise, manipulate it with different masks and then blend them all back together again. 
Final Landscape
    The tutorial goes further and makes masks for different materials to be used in Unreal, but I don't necessarily need it since I'm only making one material. Export this network as a 
as a Houdini Digital Asset.

Inside Unreal

    Inside of Unreal I imported the landscape (make sure your Houdini Engine plugin is installed for Unreal). 

Diffuse Model

Use this as the alpha channel for a lerp node between the sand color and the shadow color
    These section is taken from 
Gastón Zabala's node network and is itself based off of the Diffuse Reflectance model that John Edwards said they used for Journey.

Normals

Normal Ripples
    This part was taken from the Gatyh Interactive video. It uses both a slope mask and a noise variation mask to Lerp between the ripples and a flattened normal. 
Slope Mask
Noise Variation Mask
    For the random noise, I used a gaussian noise image generated from photoshop (got this technique from Ben Cloward), and then used a Mipmap folding function explained below.

Random Noise Normals
    I really struggled here because I wanted the noise to be visible, but not to cause visual glitches. Before the mipmap folding function, the distant dunes would not show any noise because mipmaps cause noisey images to be blurry and unusable. 

Mipmap folding

    While following Alan Zucconi's tutorial, he mentioned this blog post from Paul Nasdalack on indieburg about improving the glitter in the sand by using a technique called Mipmap folding. I used the code he suplied and made a material function inside of unreal to make a texture sample node for texture objects that I turned mipmaps off. 
    I am unsure if I have successfully recreated his function inside of Unreal. For some reason I could not get the function tex2Dlod to work inside of Unreal's custom, I would always get the error 'Unsupported intrinsic'. I believe this has something to do with the sampler variable you have to supply. 
    The function tex2Dlod is a function similar to Texture2DSample(), except you explicitly state the mipmap level you wish to call upon. You have to supply the sampler state you wish to use, the texture coordinates, and then the mipmap level you want (GPUs can automatically calculate a mipmap for you using powers of 2). When I used Texture2DSample it works fine. 
float4 color = Texture2DSample(texObject, texObjectSampler, txd.texScale(uv,1));
    Note that if your input texture object is named 'texObject' your sampler state will be 'texObjectSampler'. But this doesn't work with tex2Dlod so I'm not sure why. But I tried translating the mipfold function into unreal nodes so here is the Material Function:

Specular 

Rim Color
    The Rim color is also from Gastón Zabala's and not much has changed
Ocean Specular
    Ocean Specular also from  Gastón Zabala's, but I also added the more subtle shine area from the Github journey demo scene. I also used the Normal Ripples instead of the just the normals to use in the dot product. 
Glitter

    For this I took the glitter distribution function from the github journey demo scene, as well as using the Random Normals for the mask.

Post Processing

    I saw a tutorial that had you create a custom LUT table for Unreal by taking the base rgb table from the Unreal documentation, bring it and a screenshot of your scene into photoshop and just using photoshop adjustments to get the color you want. Then export just that LUT with all the ajustments still on it and use it in Unreal. Pretty nifty tool but I found out later it's not a great idea to rely upon it completely because the LUTs conversion happen after Unreal converts it from HDR to LDR, so it won't affect monitors that support HDR (something along those lines I'm not entirely sure myself).
    

    And that's about it for the shader. I'd like to come back to this later and maybe revisit the noise or the ripples to create something in substance designer to use. 

Other Resources I found that helped through the process:

No comments:

Post a Comment

Shader Tool Week 3 - Surface Mapping

 Texture Cubes     Also known as cube maps, its 6 2D texture maps corresponding to the faces of an axis-aligned cube. Used in lighting a sce...