October 15, 2016
Jake Progress
Jake is my personal pet project. I use this project to learn new techniques, and I've made some good progress over time. I first started working on the project with the 4.6 build of UE4, and I've continued to update it ever since. Somewhere around version 4.10 I decided to completely scrap the old project and start all over. I didn't like the direction of the original, which had very small islands, portals, and very little space to work with. Now, it has taken a life of its own.
I'll get into the details of the character Jake and the rest of the gameplay later. For now, you can just enjoy this gorgeous WIP shot of the windmill section in this game.
And now the technical details: The grass and flowers are procedurally generated using UE4's grass tool, developed for the Kite Demo. It uses the landscape's surface information to position the grass. Unfortunately, the flowers and grass must be combined together, so you cannot have multiple different kinds of grass layers with different flowers.
The grass and flowers blow in the wind based off of some combined normal maps that pan over the surface (via world position mapping). Normal maps contain information in a -1:1 range. The normal maps are then converted from local space to world space to determine the actual normals and positioning of the meshes. This saves a lot of shader instructions because we use textures instead of expensive procedural methods or vertex normal tangents to determine the normals and positioning, and the same code feeds both. It's relatively easy to set up, too. However, this method is not to be confused with tessellation as tessellation does not support local space transforms. The object vertices are the only ones needed for the animation.
The rope fence is one of my favorite personal touches and details in this project. The project looked very barren without some environmental aspect to it, but I needed something non-invasive to really blend in with the landscape. Then I recalled Super Mario Sunshine's elastic ropes. My ropes do sway in the breeze with vertex animation, again using local transform to swing the ropes from side to side. The post itself is a custom Blueprint where I can select the next post in sequence and the rope is spawned automatically. Using look at rotation, I can spawn the ropes with the right rotation and scale them to the right length. A squareish shape for the rope actually aids in the gameplay (flat top side is obviously up) and also in the vertex count. A single rope only has 160 vertices.
The windmills themselves have the Perfect Tile System assets applied, and they also have parallax occlusion mapping on them. The modeling is very basic, but I take good care of my surface materials to make sure it looks right in the scene. The cloth uses the two-sided shader. The wood is opaque. Shadows are cast on the cloth, and the cloth casts shadows as well.
The sky is a custom shader I made myself that takes normals into account for the clouds. It's entirely unlit, but I use light vector information to model shading in the clouds. The horizon is much brighter than the zenith, giving a sense of atmosphere in the distance and better contrast with the clouds up above.
September 28, 2016
Tessellation for Landscape
Pros to tessellation on landscape:
- Use artistic displacement maps to bump real geometry!
- Does not require premade geometry, only landscape material and displacement map!
- Proper sillhouettes! Proper ambient occlusion and shadows! Proper depth! Etc.
- Extremely and easily customizable! Since tessellation is realtime generated, surface values can change over time and are impacted immediately.
- Can be blended with other materials very easily.
- Tessellation can be baked into physical properties of the landscape heightfield.
- Cheaper than POM (in some cases)!
Limitations of tessellation on landscape:
- ...None!
- Some distant objects will render flat, but their depths would typically not be noticed anyways, and other methods would reveal more artifacts.
- In some extremely large landscapes with far less efficient LODs, POM or simple parallax is more performant than tessellation.
It is recommended that landscapes with tessellation have a very efficient LOD system. More sections and components at somewhat smaller sizes (31x31 quads or smaller) would render more efficiently than larger sizes and fewer components. This is because the triangle explosion result of tessellation would yield too many polygons for large sections and components to render efficiently. Also, DirectX 12 cuts draw call times by 1/8, so you can render more draw calls and components efficiently.
In order for tessellation to be enabled, go down the basic material settings under the Tessellation category and under D3D11 Tessellation Mode choose "Flat Tessellation." PN Triangles does smooth out the surface through splines, but the differences won't be noticeable under either method, and Flat Tessellation will be cheaper. I left adaptive tessellation checked on to lower the LOD in the distance, but it might be forcibly enabled just by being a landscape material, so your selection there may not matter.
The easiest setup for tessellated displacement is to multiply your heightmap by the vertex normal, then multiply that by a scalar parameter for your displacement. If you are blending heightmaps together, the final blend will be fine. I also recommend setting the tessellation multiplier down to 0.5 to save a bit on performance. The "reference plane" defaults to the ground, and all tessellation is lifted from the standard surface level. To change this to displace downwards (like POM default settings), subtract your heightmaps by 1. Subtract by 0.5 for an even 50:50 displacement above and below the surface (though the exact balance depends on the range of your heightmaps as well).
To make less triangles explode, under Project Settings > Rendering > Tessellation > Adaptive pixels per triangle, set this to a higher number (default is 48). For a game running in 4K using tessellation on landscape for medium-sized bumps, you might be able to get away with 200-600 pixels per triangle. Keep in mind the distance LOD is controlled by the Tessellation Multiplier while the number of triangles is controlled by the adaptive pixels-per-triangle value in the Project Settings when optimizing.
Also make sure to keep in mind that tessellation, while correctly calculating shadows, will not calculate the new surface normal. You will still need to provide a proper normal map with your displacement map to get accurate shading and lighting. Once you enable tessellation, you can even do things like animated displacement for lava flow. And since tessellation is compatible with texture maps, you are not limited to vertices for your shading. Your only limit is your imagination!
September 15, 2016
Seamless Mountain Texturing in UE4
Landscape materials in UE4 can be quite daunting to tackle. Most of what your player will be looking at in your environment is the landscape, yet if the landscape material is too complex, it will become the worst performance hit in your project. Multiple surfaces need to blend in with each other, and the surface needs to work both up close and further in the distance, which means expensive materials all around! But mountain ranges are especially tricky with those tall, vertical mountainsides that stretch out textures beyond belief. So, how exactly is anyone expected to make a good mountain range or cliff using landscape in a videogame, exactly? Turns out, the answer is pretty novel: use world positioning to map a texture at the X and Y planes, blend around the edges, then blend that with a top surface to prevent too much texture stretching at the top. Along with that, you can use another simple color blend texture (1 pixel wide, 64+ pixels tall) to wrap up and create those nice Grand-Canyon-esque layers in the rock.
Benefits to this method:
- Completely seamless texturing!
- Supports normal maps, roughness maps, parallax occlusion, and all other texturing methods!
- Looks great on both steep cliffs and smooth slopes!
- World-aligned means you can set up geologic layers in the rock, and no matter how your models are positioned the material will still look appropriate!
- World-aligned also means you don't need to setup UVs on any objects! Yay!
- Cheaper than most complex materials to achieve XYZ texturing (22 extra instructions to go from basic UV texturing to XYZ seamless).
Limitations of this method:
- The cost is more expensive than basic texturing via UV coordinates: plenty of blending and interpolation needs to be done to get it to function properly. But this cost is not bad for the final result.
- Can be tricky to get complex textures to look good. Wrapping textures and smooth tops work the best. Complex blends can work with a more advanced mask setup, but also costs more in performance.
This method was used on a rock surface costing only 110 instructions (vs. 88 for basic texturing). All things considered, this is the cheapest and best-looking XYZ blendable method I know of.
![]() |
| Side blend (-X and +X are white, -Y and |
![]() | ||
Top blend (Z+ is white, perpendicular and bottom is black)
|
![]() |
| Final lit blend |
This technique works on any kind of rocky assets! Just note that texture seams in the UVs will also cause the vertex normal to split, and, by association, this texturing method as well. If you're serious about using this method for perfectly seamless texturing on rocks, you can import your model without any UVs at all. Smooth normals alone will be fine. But if you like your Z-Brush normals, you can use a world-space version of those instead of the vertex normals :)
August 15, 2016
Water for Games - Cheap, Simple, Effective
71% of the Earth's surface is water. Yet, of all the materials I've ever made, water seems to be the most difficult to get right. Even in UDK with planar reflections and Phong shading, water was still incredibly complex. Once you crack the code to good water, your game can turn from a nice scene to a gorgeous, luscious environment. For the sake of this blog post, I will avoid delving into vertex displacement and dive right into translucent rendering. This kind of water is good for a calm ocean, a shimmering lake, the famous Carribbean seas, inter-coastal waterways, and pool water, with more emphasis on translucency and reflective effects. Raging oceans and rivers will be very different.
I first really got excited about realtime water with Super Mario Sunshine. For years I crowned its water as a technical and artistic achievement of the highest order. Keep in mind games like Goldeneye 007 released just 4 years prior to this game, and this was before we got a chance to experience the water from Half Life 2, Assassin's Creed, Uncharted, and Crysis. Before all these games, there was Super Mario Sunshine. The water was just so blue and seemed to look so beautiful without ever being inappropriate. But as it turns out, the water in Sunshine was, for the most part, a hoax. The water surface itself was just a texture that bobbed up and down with the waves. At close distance the water was completely translucent, while the "shimmering" texture would be emphasized further away. The water itself was clear: objects underneath the water were vertex painted to a clear blue color giving the water that strong Caribbean blue saturation. Sunshine used custom mipmaps to push the shimmering effect away from the player, but we can use other means to simulate this.
In real life, water reflects, refracts, and scatters light. You can make the shader much easier to render by mimicking the results instead of the effects. The combination of reflections and refractions looks like turbulence that bends around the bulges in the water's surface. Specularity can help to define actual reflections on the surface. The scattering can be simplified to a depth-based color.
Pros to my water technique (inspired by a combination of Super Mario Sunshine and Super Mario Galaxy's techniques):
All you need to create this effect is a simple distortion texture (a tiling bubbly normal map), a shimmery, circular noise grayscale texture, and that's it! For a more advanced version with GGX specular highlights from the sun, you'll also need a normal map of that circular noise grayscale texture.
This material only costs 46 pixel shader instructions and 45 vertex shader instructions despite being a translucent material with depth fading. If you have a sand texture underneath, this water will be cheaper to render than the sky. Making the material unlit and removing vertex fog will eliminate a ton of instructions.
In the picture above, the Roughness GGX Specular is not even used, so the distortion is actually doing most of the heavy lifting for this effect. Pan the bubbly normals, mask RG, and scale down by 0.05 to 0.1, or however strong you wish the distortion to be. Add that to the UV coordinates of your water texture (tile it as many times as you need). If the texture is imported as an uncompressed linear grayscale, multiplying it by itself will give you a cheap gamma-corrected version to add on. Multiply it by the brightness you wish the highlights to be, and add it to your ocean color. A deep saturated cerulean blue with some extra intensity works great. The depth fade in opacity will make your water more translucent with objects closer to the surface and more colored when objects beneath the water are further away. For an ocean and most water surfaces in general, this means you will get a more opaque appearance in the distance.
To get the right texture you need, start with a 256x256 pixel grayscale noise. Enlarge this to 2048x2048. Use the gradient map tool to make white circular bands according to the noise texture. Two bands through the gradient map adjustment is enough to get a good effect. Convert this "heightmap" to a normal map, and you can use the normal map instead (or both).
The GGX specular method calculates a specular highlight using the same principled GGX specular code that UE4 uses for calculating specular highlights for stationary and dynamic lights. The HLSL GGX code in the custom node is:
float a = Roughness * Roughness;
float a2 = a * a;
float d = ( NoH * a2 - NoH ) * NoH + 1;
return a2 / ( PI*d*d );
And the two inputs are Roughness and NoH, where NoH is the Blinn model. I added a Lambertian diffuse and multiplied it by itself to get a more focused, gamma-corrected result. The light vector is pulled from a Blueprint actor that is placed in the level and automatically grabs the directional light/sunlight's rotation.
This code will then feed to a Material Parameter Collection that communicates with the material to set up a specular highlight on the water.
This version of the water shader replaces the texture highlights with the GGX specular highlights calculated from the normals, so there is no texture 74 pixel shader instructions, 2 textures.
And this version adds both the texture and the normal specular for highlight rendering. The texture is not multiplied, only added. 76 instructions, 3 textures.
I first really got excited about realtime water with Super Mario Sunshine. For years I crowned its water as a technical and artistic achievement of the highest order. Keep in mind games like Goldeneye 007 released just 4 years prior to this game, and this was before we got a chance to experience the water from Half Life 2, Assassin's Creed, Uncharted, and Crysis. Before all these games, there was Super Mario Sunshine. The water was just so blue and seemed to look so beautiful without ever being inappropriate. But as it turns out, the water in Sunshine was, for the most part, a hoax. The water surface itself was just a texture that bobbed up and down with the waves. At close distance the water was completely translucent, while the "shimmering" texture would be emphasized further away. The water itself was clear: objects underneath the water were vertex painted to a clear blue color giving the water that strong Caribbean blue saturation. Sunshine used custom mipmaps to push the shimmering effect away from the player, but we can use other means to simulate this.
In real life, water reflects, refracts, and scatters light. You can make the shader much easier to render by mimicking the results instead of the effects. The combination of reflections and refractions looks like turbulence that bends around the bulges in the water's surface. Specularity can help to define actual reflections on the surface. The scattering can be simplified to a depth-based color.
Pros to my water technique (inspired by a combination of Super Mario Sunshine and Super Mario Galaxy's techniques):
- Cheap! 45 instructions for texture highlights, 72 for Phong specular, 74 for GGX specular, 76 for texture+GGX specular.
- Fluid! Looks like flowing, fluid water.
- Translucent! You can see objects underneath. And those objects have proper depth.
- Distance opacity! The depth method inherently makes the water more "reflective" in the distance and more translucent up close.
- Tilable, but doesn't look it! 2048 and different tiling factors between the distortion asset and texture/normal asset reduces tiling in the long range.
- Memory and texture sampler efficient! While the 2048 texture can seem like a lot, you can hide this in a channel of a compressed 2k mask, effectively getting this endless ocean for less than 1MB of texture data. And if you use 1k maps, you can cut that size by 1/4. And the distortion normal map only needs to be 256x256 pixels. Two textures for beautiful water!
- Flexible. Since the lighting is handled using forward-rendering techniques, you can get benefits out of this system that you can't with UE4's deferred renderer, like changing the color of the specularity, coloring by sphere maps, iridescent effects.
- Supports day/night cycle. By updating the sun's rotation in blueprints, the specularity on the water can change according to the sun's position.
- Supports color gradient by depth. Expanding the depth fade and lerping the result to different colors, you can make deeper waters a much darker blue than shallow areas.
Limitations of my water technique:
- No shadows. While you can multiply the specularity by a custom texture map or through vertex painting, there is no real process to get shadows baked on here.
- Only supports one light. The sunlight. This method will not work for reflections from lights on a pier. But it can provide general water shading to support such methods.
- Some manual effort required to provide light direction.
All you need to create this effect is a simple distortion texture (a tiling bubbly normal map), a shimmery, circular noise grayscale texture, and that's it! For a more advanced version with GGX specular highlights from the sun, you'll also need a normal map of that circular noise grayscale texture.
This material only costs 46 pixel shader instructions and 45 vertex shader instructions despite being a translucent material with depth fading. If you have a sand texture underneath, this water will be cheaper to render than the sky. Making the material unlit and removing vertex fog will eliminate a ton of instructions.
In the picture above, the Roughness GGX Specular is not even used, so the distortion is actually doing most of the heavy lifting for this effect. Pan the bubbly normals, mask RG, and scale down by 0.05 to 0.1, or however strong you wish the distortion to be. Add that to the UV coordinates of your water texture (tile it as many times as you need). If the texture is imported as an uncompressed linear grayscale, multiplying it by itself will give you a cheap gamma-corrected version to add on. Multiply it by the brightness you wish the highlights to be, and add it to your ocean color. A deep saturated cerulean blue with some extra intensity works great. The depth fade in opacity will make your water more translucent with objects closer to the surface and more colored when objects beneath the water are further away. For an ocean and most water surfaces in general, this means you will get a more opaque appearance in the distance.
To get the right texture you need, start with a 256x256 pixel grayscale noise. Enlarge this to 2048x2048. Use the gradient map tool to make white circular bands according to the noise texture. Two bands through the gradient map adjustment is enough to get a good effect. Convert this "heightmap" to a normal map, and you can use the normal map instead (or both).
The GGX specular method calculates a specular highlight using the same principled GGX specular code that UE4 uses for calculating specular highlights for stationary and dynamic lights. The HLSL GGX code in the custom node is:
float a = Roughness * Roughness;
float a2 = a * a;
float d = ( NoH * a2 - NoH ) * NoH + 1;
return a2 / ( PI*d*d );
And the two inputs are Roughness and NoH, where NoH is the Blinn model. I added a Lambertian diffuse and multiplied it by itself to get a more focused, gamma-corrected result. The light vector is pulled from a Blueprint actor that is placed in the level and automatically grabs the directional light/sunlight's rotation.
This code will then feed to a Material Parameter Collection that communicates with the material to set up a specular highlight on the water.
This version of the water shader replaces the texture highlights with the GGX specular highlights calculated from the normals, so there is no texture 74 pixel shader instructions, 2 textures.
And this version adds both the texture and the normal specular for highlight rendering. The texture is not multiplied, only added. 76 instructions, 3 textures.
Who Wants to Be a Millionaire: Breakdown of Sound Design
I might be making a quiz game soon for a client, and I think I can learn from the design decisions of what has to be the greatest quiz game ever made, bar none: Who Wants to Be a Millionaire. More specifically, the sound and music. The sound doesn't just get more ominous as the game progresses, the sound design is actually quite complicated with many surprising twists along the way.
$100, $200, $300, $500, $1,000 Questions: https://www.youtube.com/watch?v=P4utAJ-JraE
At the beginning, there are two big "let's play" tracks for the start of the game at $100 and the continuation before $200. This is a fanfare that hones in the game at the beginning. The game as a whole is designed to be intimidating and make the player feel very uncomfortable. This makes winning high jackpots feel very rewarding. At the game's beginning, sound effects for wins are very unobtrusive and lightweight. The music is lighter, and bouncier, and more sensitive to wins. There are no sounds just for answering or playing because the assumption is you should be able to pass each question without trouble. It helps push players up and out of this section to move on to harder questions and bigger risks.
The surprise here is, why bother wasting time on questions you know people can answer? Shouldn't the whole game be intimidating? This section is included in the game to give it a fast start and a more dynamic introduction. You pull people in with these questions. You challenge them later on. Again, the real surprise here is that the soundtrack is actually more repetitive, less solemn, and less epic than the previous phase. You'd think the sound should get lonelier as you approach the top, but it doesn't. I believe this is, ironically, intended to push players closer to the $1,000,000 question faster by means of the anxious repetition, and from watching the show we know this is where many people screw up very quickly and drop back down to $32,000. The drama of the risk involved was soaked for all it was worth in the last phase, but now that the jackpot is so great, it would be much more interesting just to see someone just make it to that last question, and the faster, more repetitive music divides to accomplish both: it pushes the brightest to the top quicker while the lesser freefall sooner.
$2,000 Question: https://www.youtube.com/watch?v=6vvDsRJz5yg
$4,000 Question: https://www.youtube.com/watch?v=NtwRulZOIA4
$8,000 Question: https://www.youtube.com/watch?v=H_v0pfU5tPc
$16,000 Question: https://www.youtube.com/watch?v=fP7xiTn6GM8
$32,000 Question: https://www.youtube.com/watch?v=2ZGA_I3g0e8
$2,000 Answer: https://www.youtube.com/watch?v=x4eMmc9d8vk
$4,000 Answer: https://www.youtube.com/watch?v=lwfltI3AOMw
$8,000 Answer: https://www.youtube.com/watch?v=im2Nnx_Jp3s
$16,000 Answer: https://www.youtube.com/watch?v=2FN0IshDnE8
$32,000 Answer: https://www.youtube.com/watch?v=9R7LsLhWcOU
After the $1,000 mark, the music undergoes a dramatic change, getting much quieter, more ominous, and just selecting an answer now has a sound effect. Surprisingly, and I didn't realize this until after researching, every question's sound ascends keys in minor scale from $2,000 all the way up to $32,000. This is true for both the question's music and the final answer sound effect. You'd think the music should descend the scale, but the purpose of having higher sound as you progress is to indicate the rising jackpot, and the rising risks. The majority of the game is spent in this segment, squeezing the drama for all it's worth.
$64,000 Question: https://www.youtube.com/watch?v=LEtilc3aT7g
$125,000 Question: https://www.youtube.com/watch?v=WqCzloBlrXY
$250,000 Question: https://www.youtube.com/watch?v=oSWq9yKstmM
$500,000 Question: https://www.youtube.com/watch?v=glIfOjdisq4
$64,000 Answer: https://www.youtube.com/watch?v=0vosrBa5jgk
$125,000 Answer: https://www.youtube.com/watch?v=TqMnQ0X-ifs
$250,000 Answer: https://www.youtube.com/watch?v=KJbzYA9hfjg
$500,000 Answer: https://www.youtube.com/watch?v=m4dkR_u56Xk
$1,000,000 Answer: https://www.youtube.com/watch?v=OJSCnWKq3Bw
The $64,000 question marks another significant change as we go back to the bottom of the scale, this time with a different, more repetitive "heartbeat" soundtrack, interspersed with the ambient sitar for more atmospheric connotations. However, because the song is completely different, the change in scale is not as noticeable until the final answer sound effect at the end of the $64,000 mark. It is the same sound, same scale, same key as the $2,000 answer. Compared to the higher tone of the previous $32,000 question, this moment doesn't just mark the final phase as beginning, but as having already begun, and it catches everyone by surprise.
$1,000,000 Question: https://www.youtube.com/watch?v=cN1DEXYBEjE
The final question is a doozy. It is the most repetitive, the most ominous, the most solemn, and of all the tracks heard by far it is definitely the darkest track of anything I've ever known. It's just a 3 second looping beat and a droning pad that never stops. It's easy to see why this choice was made as no other soundtrack could possibly be more conspicuous than a repetitive 3 second loop, but it flies in the face of game shows that try to make their larger prizes more like bonus rounds and fun, happy, crazy dances. This is not. This is the final question. There are no more questions after this. If you lose, you risk $468,000. If you win, you will be a millionaire.
Overall, the progression follows the show's intimidating and daunting experience, using key and soundtrack changes to push players through the easy questions, dramatize the difficult questions, and force them to fall quickly or climb to the top. The feedback is so subliminal, but very much intended by design as though it was a deliberate story. The complexity of Millionaire's sound design is something that many developers should learn from regarding how to use sound to set the drama of an interactive game into a story.
August 1, 2016
Rolling Displacement: Cheap AND Good-Looking Cloth for Console and PC
88 instructions - The number of instructions necessary to render beautiful silk cloth
75 instructions - Vertex shader cost of 3D cloth displacement
I have spent years trying to get APEX cloth to work on characters without needing NVIDIA's APEX integration with Maya or 3DS Max, but I cannot figure out how to authorize it, nor have I seen anyone else do it. In my open world project, Jake, the main character was always butt-naked. He was intended to have a red flowing cape. My folk's chargin with having a naked character and insistence that he wear something made me decide to try a different tactic: cloth displacement and normal calculation from textures. And surprisingly, the results from this method look even better than low-density APEX simulations.
The overall gist of this method is to offset sine and cosine waves flowing down the cloth by textures to flow in a unique pattern, transform from local space to world space and combine them to form the resulting vertex displacement, and using the sine data to drive a normal calculation. To the best of my knowledge, nobody has come up with a displacement/normal driven technique like this before. I'm calling this method "Rolling Cloth" due to the way the sine waves roll with the curvature of bends in the cloth rather than across them.
The benefits of this method are:
75 instructions - Vertex shader cost of 3D cloth displacement
I have spent years trying to get APEX cloth to work on characters without needing NVIDIA's APEX integration with Maya or 3DS Max, but I cannot figure out how to authorize it, nor have I seen anyone else do it. In my open world project, Jake, the main character was always butt-naked. He was intended to have a red flowing cape. My folk's chargin with having a naked character and insistence that he wear something made me decide to try a different tactic: cloth displacement and normal calculation from textures. And surprisingly, the results from this method look even better than low-density APEX simulations.
The overall gist of this method is to offset sine and cosine waves flowing down the cloth by textures to flow in a unique pattern, transform from local space to world space and combine them to form the resulting vertex displacement, and using the sine data to drive a normal calculation. To the best of my knowledge, nobody has come up with a displacement/normal driven technique like this before. I'm calling this method "Rolling Cloth" due to the way the sine waves roll with the curvature of bends in the cloth rather than across them.
The benefits of this method are:
- Extraordinarily cheap and detailed cloth displacement (great for console, mobile, and PC, assuming the API can handle texture displacement)
- Rolling normals calculation looks great on low-poly cloth, even with no displacement at all
- Highly scaleable to intended hardware
- Normal calculation is fairly accurate
- Artistically driven by textures for great flexibility in final results
- Looks great with smaller textures (64-128 pixels)
- Easily supports tiling cloth texture normals
- Requires API to be capable of running textures to vertex displacement
- Wind is manually driven by attributes in local space, not automatic in world space
- Oddly enough, this is why the shader does not support triangle explosion through tessellation, because transforming from local to world space is incompatible with tessellation
- The cloth is NOT simulated, so it will pass through world objects and characters
- Movement rolls with bends in the fabric instead of across them
July 15, 2016
Inverse Sine Distribution and Seeding (And Sparkling Materials)
The Perfect Tile System is a fairly mature system, but there's always room for improvement. One example is how to handle random seeding with features like tile tilting and roughness, to give each tile a unique tilt in the normals or shift in the roughness. This method can be used to give a nice sparkling finish to a granular material. I noticed that the old distribution (sine waves), while cheap, favored extreme angles to a more centered distribution: a sine wave rounds out on the ends, not in the middle. The distribution I needed was the opposite: an inverse sine, where the center values are more typical along the distribution path, with sharper falloffs into the extreme.
In HLSL:
asin (x)
Inverse sine calculations, unfortunately, are very expensive (10 instructions by itself), and requires the input to be bound between [-1:1]. But I needed the input to be unbound so the distribution can be used to completely randomize and seed values. If you want a purely coded distribution method, you need to use the oscillation BEFORE the function, at which point, why bother doing this seeding calculation 3 times? All being said, the coded inverse sine was NOT going to be efficient at ALL.
So in my research, I found two alternate methods to make this type of distribution much cheaper: the texture/data table method, and the smooth curve method. The cheapest and most flexible technique was the Texture Seeding/Data Table Method. It is 3-5 times cheaper than the coded method.
Random Map > multiply by constant seed value > Mask and offset UVs of Asine/Sine/Linear gradient texture > Interpolate and/or bias to final values.
The texture method is similar to a data table: use the seed values to randomize the UVs of a texture containing a single sine distribution. This method is really cheap, and costs only 5 instructions to seed (from random values to [0:1] asine distribution). I used a 1x512 texture to map out the values from 0-255 along an inverse sine wave, and the whole thing wraps around. The values themselves were figured out using a formula in Excel.
This Excel function plots one arc of the inverse sine from 0-1 using 256 steps:
=(ASIN((ROW(A1)-2)/255))/(PI()/2)*256
Note: This single arc must be manipulated into a corrected asine distribution. I made a corrected Excel data table below of the raw numbers.
From those values, it just takes a lot of manual labor in Photoshop to color a texture 512 pixels long. There are only 256 values that can be plotted in a single pixel on a texture. That being said, trilinear filtering DOES smooth out the resolution of the data set, giving you an effectively accurate inverse sine distribution for no more cost than any other data set in the texture seeding method. The texture must be imported with sRGB checked OFF with the Linear Grayscale compression settings (uncompressed, one channel). This method costs only 5 instructions for the seeding, 7 total for including interpolating. Using the same method for a linear gradient will give you a linear distribution. Sine gradient, a sine distribution.
Download raw Excel data table
Download Asine.tga 512-pixel gradient
In HLSL:
asin (x)
Inverse sine calculations, unfortunately, are very expensive (10 instructions by itself), and requires the input to be bound between [-1:1]. But I needed the input to be unbound so the distribution can be used to completely randomize and seed values. If you want a purely coded distribution method, you need to use the oscillation BEFORE the function, at which point, why bother doing this seeding calculation 3 times? All being said, the coded inverse sine was NOT going to be efficient at ALL.
So in my research, I found two alternate methods to make this type of distribution much cheaper: the texture/data table method, and the smooth curve method. The cheapest and most flexible technique was the Texture Seeding/Data Table Method. It is 3-5 times cheaper than the coded method.
![]() |
| Coded Seeding Method (Bottom Asine is 2-vector) |
![]() |
| Texture Seeding Method (Asine is embedded as gradient texture) |
Random Map > multiply by constant seed value > Mask and offset UVs of Asine/Sine/Linear gradient texture > Interpolate and/or bias to final values.
The texture method is similar to a data table: use the seed values to randomize the UVs of a texture containing a single sine distribution. This method is really cheap, and costs only 5 instructions to seed (from random values to [0:1] asine distribution). I used a 1x512 texture to map out the values from 0-255 along an inverse sine wave, and the whole thing wraps around. The values themselves were figured out using a formula in Excel.
This Excel function plots one arc of the inverse sine from 0-1 using 256 steps:
=(ASIN((ROW(A1)-2)/255))/(PI()/2)*256
Note: This single arc must be manipulated into a corrected asine distribution. I made a corrected Excel data table below of the raw numbers.
From those values, it just takes a lot of manual labor in Photoshop to color a texture 512 pixels long. There are only 256 values that can be plotted in a single pixel on a texture. That being said, trilinear filtering DOES smooth out the resolution of the data set, giving you an effectively accurate inverse sine distribution for no more cost than any other data set in the texture seeding method. The texture must be imported with sRGB checked OFF with the Linear Grayscale compression settings (uncompressed, one channel). This method costs only 5 instructions for the seeding, 7 total for including interpolating. Using the same method for a linear gradient will give you a linear distribution. Sine gradient, a sine distribution.
Download raw Excel data table
Download Asine.tga 512-pixel gradient
Subscribe to:
Posts (Atom)
























