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:
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
The limitations of this method are:
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
The whole material setup and finished result. Not too complicated, but looks great!
UVs on my cloth are set up so I can use a simple texture coordinate gradient as a mask and flow direction. In the mask, black areas will be swayed before white areas. The mask may require some fiddling to get right. For the trigonometry waves, I suggest the Face and Vertical waves are Sine and Cosine of the same period so you get a nice self-preserving circular motion. The negative of the first sine wave will just yield an unnatural linear displacement diagonally. The Lateral wave should be different than the first two swaying back and forth. If you want to prevent the cloth from looping, you can adjust the lateral motion or add more waves here at different periods.
The strengths of the Face/Lateral/Vertical transforms are purely visual. Eyeball it. If it looks right, it is right. The normals calculation, though, works the best when divided by the number of transforms, and when it's scaled to their intensity. You can replace the 0,0,1 in the normals generator with a tiling normal map and it will work just as well. That "Normal of Mask" is actually a normal map of the grayscale mask. It's important the mask and normals are smooth, so don't be afraid to use a gaussian blur or low-res textures for them.
Multiply each wave times the mask, then add them together for the normals calculation. For the transform, multiply each transform by its corresponding Wave*Mask result, then simply add the results together. For this cloth, I wanted a silky cloth, so I used a 0.7 semi-metallic level and 0.6 roughness. You can mess with these numbers for different types of silk. Subsurface looks the best when I multiply the color by 0.2. This material is Two-sided, and using the Two-sided shading model. Cloth shading can yield nice cloth results as well. You can even use an opacity mask to show holes through the cloth.
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.
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
Here is a mock business card design I made in Adobe Illustrator. Took only a few hours from start to finish.
I really like the contrast between the two typefaces. Bodoni MT for the serif face, and Gill Sans MT for the sans serif face. I feel designs are always stronger in black and white than in color. This is true, the rods in the human eye which sense light and value are more accurate than the cones that detect color. So a design that's stronger in value will be more refined than a design that uses color. Since color can start complicating designs, creating contrast between different colors even though they have the same value, designs can start to look a bit faded. Perhaps a better approach for design is to condemn subtlety in using different shades of color. That way, say, a darker blue would always contrast in value with a lighter yellow. Of course, my portfolio has gradients of colors as well, but it's very easy to get lost if you don't know what you're doing.
To be fair, I think I could die and still not know what I'm doing. There are some people who seriously like ugly colors and hate anything in grayscale. I'll never be able to understand these people.
So, I was contacted by someone in South Africa who works at a tile shop about making a tile viewer capable of previewing their tiles. I made this setup which uses Blueprints to allow users to dynamically change the presets. The names are pulled automatically from the material preset names, and the texture preview in the HUD also gets pulled from the same preset. The only manual work that needs to be done to enter new materials in this system is to add them to the array of parameters. Everything else is precomputed.
Codewise, this is probably the third heaviest code project I undertook (first is 2115, the game for Mote Marine, second is the Perfect Tile System shader itself), and it is definitely the most ambitious Blueprint projects I've ever made. With this project I learned how much code goes into that extra polish phase. For instance, the resolution menu used to allow people to choose resolutions far beyond the top resolution of their monitor. I had to write code in to get the supported resolutions and disable the resolutions that don't fit. The ID system would continue scrolling to infinity unless you clamp it down to a maximum value, so I used the length of the parameter array to get that max value. Changing the grout color as you hover over them with the mouse feels very smooth and nice, but when I had this easy change feature everywhere, it turned the menu into a landmine! Now the quick hover change only works for the grout color, and clicking a grout color will lock in the color for a second so you don't accidentally select a color you don't want.
I'd like to take this time to talk a little bit about controls and the user experience because they are SO important. Even for a project as simple as this, the user experience needs to be fluid and smooth. The biggest challenge was maintaining what I like to call "natural rest" over the most used buttons. In all my project controls, I don't want players to keep letting go of keys and changing positions in order to control the game. In this case, everything from pulling up menus and making selections while changing the floor ID and scaling should all be completed without the player's hands ever leaving the natural rest state (WASD, Shift, Mouse). Aside from quitting the game (Escape) and toggling the help menu (H), no possible action would require leaving this state, and if the state must leave (for instance, to switch from the left mouse button to the middle one), the change corresponds to a shift in the mode of the user experience (scrolling through IDs/opening the menu VS selecting items in the menu). This psychological separation and organization of the controls makes the user experience feel natural, fluid, and inherently clear.
At the moment, there is a 3D-printed contraption that allows players to use all their fingers to access buttons on the controller they wouldn't normally be able to reach without their fingers leaving other buttons. This is how players identify bad controls: when a device like this is viewed as favorable, or necessary in order to play a game well. Maybe a particular move is more difficult to reach than the inventory menu, but the move is used more often. Maybe the design of the controller has a lot of buttons with important functions outside the natural rest state. It all has an effect on the player, teaching them which moves should be used most often, which moves can be used together, and how different modes switch.
Using the scroll wheel, it is very easy to scroll through all of the parameters and select the right one. Holding shift lets you scroll 5 times as fast (or faster/slower, the variable can be changed). If there were 500 presets in this viewer, it would be possible to quickly scroll through any of the 500 presets with only the shift button and the mouse wheel in 2-3 seconds, without ever needing to take your fingers off the main controls. And since both buttons are on opposite hands, it actually helps players focus on the action. It's also possible to enter an ID and go to the preset you have in mind, and it will automatically prevent you from entering a letter or an ID beyond what exists in the system.
I love UE4's UMG. It is so easy to design a beautiful user interface with programmable buttons and popup menus that it makes everything a breeze. How do I know the user experience is good? My mom likes it, and is able to use it. My mom has trouble using e-mail.
I am so proud to call myself good friends with Meng Wang. He is an insanely talented sculptor at Ringling College: by far the greatest in the school when it comes to anatomy and the human body. Recently, he posted his final senior thesis, a 3-person trailer project pitting vikings against elves... in space. The idea is so Gabriel!
I helped my friend figure out the viking character's materials and some of the holograms on the opening scene. I also helped with experimenting surfaces for the ship, and experiments with the lighting. I managed to recreate what looked like a NASA Space Shuttle receiving plenty of sunlight with stark shadows and almost no indirect illumination at all, but it looked almost too realistic and didn't fit with the darker themes of the project. I also saw early footage of this trailer and suggested the camera move slower to heighten the sense of scale. Cameras have to move very fast around a large object if you want to swing around it. In real life, that kind of fast movement is impossible, and the point of such movement is not to convey breakneck speed, so the end result is it just makes the objects seem much smaller than they truly are. But slower movements and lower FOVs seem much more epic. This trailer also looks amazing when fully lit.
I am so proud of my good friend. I wish him all the best.
Just a simple graphic for learning piano scales. Enjoy!
Note: I showed this to a friend who studied music theory and they said it was wrong. All wrong. The way scales work they can be in different keys, so the same scale can be done a number of different ways. But I've gotten some very good sounds out of it. Not being trained myself, I found it quite useful... but yeah, this is a disclaimer. Scales don't really work like this.