{"id":841,"date":"2015-07-23T15:59:16","date_gmt":"2015-07-23T13:59:16","guid":{"rendered":"http:\/\/www.michalorzelek.com\/blog\/?p=841"},"modified":"2015-07-23T18:45:12","modified_gmt":"2015-07-23T16:45:12","slug":"pseudo-realistic-sand-accumulation-material","status":"publish","type":"post","link":"https:\/\/www.michalorzelek.com\/blog\/pseudo-realistic-sand-accumulation-material\/","title":{"rendered":"Pseudo realistic sand accumulation material"},"content":{"rendered":"<h2 style=\"text-align: justify;\">Introduction<\/h2>\n<p style=\"text-align: justify;\">In this article I\u2019m going to show how to create realistically looking rocky surfaces covered with sand in Unreal Engine 4. Most basic\u00a0approach is to linearly interpolate two textures based on some designer defined value(i.e.. vertex painting). While the effect looks acceptable\u00a0in some cases, there are situations where simple blending breaks the realism. One such situation will occur when trying to mix sand with gravel\u00a0or rocks.<\/p>\n<p style=\"text-align: justify;\"><div class=\"su-youtube su-u-responsive-media-yes\"><iframe loading=\"lazy\" width=\"640\" height=\"400\" src=\"https:\/\/www.youtube.com\/embed\/4whn0h5X65U?\" frameborder=\"0\" allowfullscreen allow=\"autoplay; encrypted-media; picture-in-picture\" title=\"\"><\/iframe><\/div>\n<p style=\"text-align: justify;\"><!--more--><\/p>\n<p style=\"text-align: justify;\"><span style=\"color: #333333;\">This tutorial will focus on creating material that will procedurally accumulate sand on surfaces\u00a0based on their shape and slope. I assume you have basic knowledge of UE4 Material editor and\u00a03D math. If you are here just for the content, download link is at the bottom of this page.<\/span><\/p>\n<p style=\"text-align: justify;\"><span style=\"color: #000000;\"><strong>Disclaimer: Downloadable samples\u00a0use assets from &#8222;Arid Desert Pack&#8221; package available on the Marketplace. If you didn&#8217;t buy\u00a0this package, you will have to provide your own sand and gravel textures.<\/strong><\/span><\/p>\n<h2 style=\"text-align: justify;\">Mimicking \u00a0sand behavior<\/h2>\n<p style=\"text-align: justify;\">In real world, dry sand behaves much like fluids behave. It &#8222;flows&#8221; under influence of gravity and it adapts it&#8217;s shape to the containing vessel. Therefore, sand will accumulate more on flat surfaces and less on slopes. In UE4 this effect can be easily achieved \u00a0using material editor.<\/p>\n<p style=\"text-align: justify;\">To create\u00a0desired effect there are two main\u00a0points to consider:<\/p>\n<ul style=\"text-align: justify;\">\n<li style=\"text-align: justify;\">detecting surface steepness,<\/li>\n<li style=\"text-align: justify;\">blending two materials based on heightmap texture.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">The easiest way to detect in shader whether surface is flat or uneven is producing\u00a0dot product between surface normal vector and constant vector [0 0 1]. As a result we will receive a [-1, 1] mask. The more flat\u00a0surface is, the value will be closer to 1, while \u00a090 degrees wall will produce value of 0.<\/p>\n<p style=\"text-align: justify;\"><div class=\"su-custom-gallery su-custom-gallery-align-left su-custom-gallery-title-hover su-lightbox-gallery\"><div class=\"su-custom-gallery-slide\" style=\"width:650px;height:380px\"><a href=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/SlopeDetection.png\" title=\"SlopeDetection\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/SlopeDetection-650x380.png\" alt=\"SlopeDetection\" width=\"650\" height=\"380\" \/><span class=\"su-custom-gallery-title\">SlopeDetection<\/span><\/a><\/div><div class=\"su-clear\"><\/div><\/div>\n<p style=\"text-align: justify;\">Now that we have slope detection we need a way of controlling the acceptable angle below which, sand can accumulate. For example: accumulate sand for every surface inclined at an angle below 30 degrees. We could connect dot output to the\u00a0<em>if<\/em> node and return\u00a01 or 0 depending if input angle is higher or lower than specified threshold parameter. This will work, but there will be hard\u00a0transition between sand and underlying surface &#8211; the result will look fake. Instead we will introduce something that I call smooth threshold. We should still be able to detect slopes but we also want to smooth out the transition.<\/p>\n<p style=\"text-align: justify;\">Once we know\u00a0which part of surface is\u00a0flat enough to accumulate sand, we have to define how sand will accumulate in relation to underlying surface(gravel in this case) . Typically it will concentrate inside cracks or between rocks where they are least influenced by wind and rain. To simulate this we need to know how rocky surface is shaped. For our purpose, heightmaps provide this information. A heightmap is just a greyscale texture storing elevation data. The brighter pixel is, the higher altitude it represents.<\/p>\n<h2 style=\"text-align: justify;\">Implementing soft threshold function<\/h2>\n<p style=\"text-align: justify;\">In the content browser create a new Material Function asset and name it\u00a0<em>MF_SoftThreshold and open it in the editor<\/em>. Start with adding three function input nodes of scalar type with following names:<\/p>\n<ol style=\"text-align: justify;\">\n<li style=\"text-align: justify;\"><em>Input value<\/em><\/li>\n<li style=\"text-align: justify;\"><em>Threshold<\/em><\/li>\n<li style=\"text-align: justify;\"><em>Deviation<\/em><\/li>\n<\/ol>\n<p style=\"text-align: justify;\">Then implement following formula:<\/p>\n<p style=\"text-align: justify;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-860\" src=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MF_SoftThreshold_EQ.png\" alt=\"MF_SoftThreshold_EQ\" width=\"282\" height=\"104\" \/><\/p>\n<p style=\"text-align: justify;\">\u00a0T is <em>Threshold<\/em>, D is <em>Deviation<\/em> and x is <em>Input Value<\/em><\/p>\n<p style=\"text-align: justify;\">Clamp the equation to [0,1] and connect it to the\u00a0<em>Output Result<\/em> node. Save the asset and close material editor. \u00a0The final network should look as follows.<\/p>\n<p style=\"text-align: justify;\"><div class=\"su-custom-gallery su-custom-gallery-align-left su-custom-gallery-title-hover su-lightbox-gallery\"><div class=\"su-custom-gallery-slide\" style=\"width:650px;height:380px\"><a href=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MF_SoftThreshold.png\" title=\"MF_SoftThreshold\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MF_SoftThreshold-650x380.png\" alt=\"MF_SoftThreshold\" width=\"650\" height=\"380\" \/><span class=\"su-custom-gallery-title\">MF_SoftThreshold<\/span><\/a><\/div><div class=\"su-clear\"><\/div><\/div>\n<h2 style=\"text-align: justify;\">Fun with sand<\/h2>\n<p style=\"text-align: justify;\">Now, in content browser create another material function and call it MF_RockSandBlend and change output value type to . This is where all the magic\u00a0happens. Start with adding <em>texture samplers<\/em> for all relevant gravel and sand textures. In my case I have Diffuse, Normal and Specular maps for sand and Diffuse, Normal, Specular, Gloss and Height maps for gravel.\u00a0Then, create texture coordinate nodes and plug them into each sampler. To give more control over texture tiling, let&#8217;s multiply texture coords with <em>SandTiling<\/em> and <em>GravelTiling<\/em> scalar parameters before connecting them to sampler UV inputs.<\/p>\n<p style=\"text-align: justify;\">Now that we have our textures in place, let&#8217;s implement slope detection. Same as previously, start with computing dot product of VertexNormalWS and constant vector [0 0 1]. Add two more scalar parameters and name them Threshold and Deviation. Open content browser and drag your MF_SoftThreshold over to material editor. Connect parameters to corresponding function inputs and connect dot product output to<em> Input value<\/em> pin. The output value should be inverted\u00a0so connect it to\u00a0<em>1-x<\/em> node.<\/p>\n<p style=\"text-align: justify;\">We now have a proper mask dependent on how steep surface is. Let&#8217;s combine 1-x node with our gravel heightmap. After multiplying we get a modified mask telling us elevation of any given point on the surface. If it&#8217;s white, we have either slope or rock sticking above ground. If black &#8211; surface is even or it&#8217;s a crack between rocks. For user convenience we can provide a parameter that controls amount of sand on slopes. Create scalar parameter\u00a0<em>SandAmount<\/em>, clamp it to [0, 1] values. Create <em>lerp<\/em> node and connect clamped parameter to the\u00a0<em>alpha<\/em> pin. Create two scalar constants, assign values of 1 and 200 and conenct them to A and B pins. Connect lerp output to new multiply node. As second multiply input connect our slope-height mask and clamp the result to [0, 1].<\/p>\n<p style=\"text-align: justify;\">\u00a0We are almost there. Create 4 lerps and connect sand-gravel texture pairs for each channel: BaseColor, Specular, Normal, Roughness. For each alpha value, connect our mask. Create\u00a0<em>MakeMaterialAttributes<\/em> and connect previous lerps to corresponding channels. Finally, connect your attributes to material function output. The final material network should look like this:<\/p>\n<p style=\"text-align: justify;\"><div class=\"su-custom-gallery su-custom-gallery-align-left su-custom-gallery-title-hover su-lightbox-gallery\"><div class=\"su-custom-gallery-slide\" style=\"width:600px;height:300px\"><a href=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MF_RocksSandBlend.png\" title=\"MF_RocksSandBlend\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MF_RocksSandBlend-600x300.png\" alt=\"MF_RocksSandBlend\" width=\"600\" height=\"300\" \/><span class=\"su-custom-gallery-title\">MF_RocksSandBlend<\/span><\/a><\/div><div class=\"su-clear\"><\/div><\/div>\n<p style=\"text-align: justify;\">Our magicmaterial is in place, but to use it we have to create actual material. Let&#8217;s call it <em>M_Landscape_Master.<\/em>\u00a0In it&#8217;s settings enable Material Attributes and set Tesselation to Flat. Create new\u00a0<em>MaterialFunctionCall<\/em> node and set function to MF_RockSandBlend. Connect this node to material output. And That&#8217;s it.<a href=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MaterialDetails1.png\"><br \/>\n<\/a><\/p>\n<p style=\"text-align: justify;\"><div class=\"su-custom-gallery su-custom-gallery-align-left su-custom-gallery-title-hover su-lightbox-gallery\"><div class=\"su-custom-gallery-slide\" style=\"width:600px;height:300px\"><a href=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MaterialDetails1.png\" title=\"MaterialDetails\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.michalorzelek.com\/blog\/wp-content\/uploads\/2015\/07\/MaterialDetails1-600x300.png\" alt=\"MaterialDetails\" width=\"600\" height=\"300\" \/><span class=\"su-custom-gallery-title\">MaterialDetails<\/span><\/a><\/div><div class=\"su-clear\"><\/div><\/div>\n<h2 style=\"text-align: justify;\">Summary<\/h2>\n<p>This short tutorial presents a method to speed up level design\u00a0with procedural materials. Instead of hand painting\u00a0textures on landscapes you can define set of rules and have your landscape painted automatically. This is especially useful when dealing with vast terrains where where a lot of time has to be spent on painting. Instead of focusing\u00a0on every inch of world, artist can use this approach\u00a0and then focus on hand tweaking most important areas. While results are pleasant already, there is still much room for improvement. One can expand \u00a0material with additional rules: grass blending? blending different textures based on height? Make sand accumulate accordingly to wind direction and speed? Only limit is your imagination.<\/p>\n<p>Tutorial files: <div class=\"sdm_download_button_box_default\"><div class=\"sdm_download_link\"><a href=\"https:\/\/www.michalorzelek.com\/blog\/?sdm_process_download=1&download_id=879\" class=\"sdm_download green\" title=\"Pseudo realistic sand accumulation material &#8211; tutorial files\" >Download Now!<\/a><\/div><\/div>\n<p>You can also access\u00a0project on <a href=\"https:\/\/github.com\/pminiszewski\/UE4-HeightBlending\" target=\"_blank\">GitHub<\/a>.<\/p>\n<p style=\"text-align: justify;\">\n","protected":false},"excerpt":{"rendered":"<p>Introduction In this article I\u2019m going to show how to create realistically looking rocky surfaces covered with sand in Unreal Engine 4. Most basic\u00a0approach is to linearly interpolate two textures based on some designer defined value(i.e.. vertex painting). While the effect looks acceptable\u00a0in some cases, there are situations where simple blending breaks the realism. One &hellip; <a href=\"https:\/\/www.michalorzelek.com\/blog\/pseudo-realistic-sand-accumulation-material\/\" class=\"more-link\">Czytaj dalej <span class=\"screen-reader-text\">Pseudo realistic sand accumulation material<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[16,17,15],"class_list":["post-841","post","type-post","status-publish","format-standard","hentry","category-tutorials","tag-material","tag-tutorial","tag-ue4"],"_links":{"self":[{"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/posts\/841","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/comments?post=841"}],"version-history":[{"count":33,"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/posts\/841\/revisions"}],"predecessor-version":[{"id":887,"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/posts\/841\/revisions\/887"}],"wp:attachment":[{"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/media?parent=841"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/categories?post=841"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.michalorzelek.com\/blog\/wp-json\/wp\/v2\/tags?post=841"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}