Sins II Dev Journal #24: Shaders - The Virtual Fabric of Reality
Published on Wednesday, May 7, 2025 By Unikraken In Sins Dev Journals
This month, Paul Kiesling (Set), lead 3D artist for Sins II, returned to share his latest shader explorations. His insights aim to inspire fans and modders during his research for future updates.
The word shader gets thrown around a lot when talking about video games and for most people it's essentially technobabble, but what is a shader and how does it work? That's a great question and simply put, a shader is a small program that renders graphics data. It renders the visual elements of the game. Using math to replicate certain visual effects whether that be proper PBR (Physically Based Rendering) or something more stylized like Cel shading and anywhere in between.
I want to preface before diving into this that I am by no means a subject matter expert and this will not be exhaustive in terms of its overview. I have been experimenting in my off time to better understand them myself and figured it is worth demonstrating how they can be manipulated for specific visual effect for the benefit of our modding community and other interested fans. We will go over some simple examples and the math involved in how the visual changes are realized. This will be a learning experience for both of us.
Starting with the basics, Sins 2 uses HLSL which stands for High-Level Shader Language. It's a shader language created by Microsoft for use with DirectX. If you have a basic understanding of how math works and understand how declarations work, HLSL is pretty easy to understand. Tinkering with shaders has a low barrier to entry and a very high skill ceiling, as what can be accomplished is essentially limitless. Shader code as hinted at is the math that makes the smoke and mirrors of video games work in practicality.
I currently have been putting together a Cel shader for Sins and here is a stark example of the difference shaders can have on the resulting output of how your assets look in game.
Both of shots of the Halcyon share the same models, textures and references. There is no functional difference between them except for how the game chooses to render them via the shader pipeline. Here is another example of the same shader applied to the Advent Loyalist Titan (Coronata).
For this Cel Shader we have a function and a call. A function file is separate from the main uber shader, that contains a large portion of the math required to render said function.
We are going to be focusing on how the shadow effect is accomplished but we will define some terms to avoid confusion when reading the snippet above.
Here we are modifying the gamma of the base color to avoid the mesh from looking washed out in white. Gamma correction transforms colors from a linear to non-linear space to better emulate people's perception. In this instance a gamma correction of about 2.0 landed the effect in the sweet spot of cartoony perception.
Now the Advent looked fantastic from the get-go and their materials responded very well to the Cel shader, Vasari and TEC required a bit of tinkering to create a more cartoony effect from their textures without changing their source art. The posterization effect reduces the number of colors and tones in the source texture, creating a slightly more desirable cartoony-like effect.
Coupled with the cel shading-like effects applied by the rest of the shader, the outcome is much more in line with the look and feel I was going for out of the shader.
This isn't the whole thing, the whole function is a bit too big to reasonably include in a single picture but it's the definitional math that gets called in the main mesh_pbr_ps uber shader.
In simple terms the Cel Shader suppresses most of the material properties for the ship, so things like metalness, roughness, and occlusion. I added a bit to suppress the normals as well to prevent any odd behaviors with the light. In Sins 2 normally the shadows have a cascade function that creates smooth natural shadows across the surface of an object; in the same way you would expect them to behave in reality. With a Cel shader you're intentionally going for non-realistic so quite a few artistic liberties can be had with how that raw asset data is interpreted.
In the instance of the Cel shader the most important element is the shadow steps. We don't want natural cascades we want hard defined steps with a bit of irregularity, so they appear as though they have been drawn by a human hand.
To avoid confusion, a float is just a data type that represents a 32-bit floating point number. Its designed to store and control fractional numbers in shaders. Its necessary for things like texture coordinates, colors, and a number of other necessary math functions required to make shaders do what they do.
Let's break this down so it makes sense: For the shadow bands we have 8 steps. So 8 hard transitions between shades of shadows. looking at step0 we can see how the math works.
float3 step0 = baseColor * 0.02
float3 - This is a float3 because you are referencing three channels in baseColor (R,G,
step0 - This is the first and darkest step of the Cel shader shadows
baseColor * 0.02 - To get this step is its taking the baseColor and multiplying by 0.02 which is what creates the darkest band of shadows.
float3 result = step0;
result = lerp(result, step1, smoothstep(0.125, 0.127, NdotL));
Let's break this down too so you know how the steps are blended to avoid aliasing (jaggies.) The first step defines step0 which is the darkest shadow step being applied. The next line is taking the results of the first line.
result - what the transition will be between step0 and step1
lerp - This means linear interpolation and its performing that between result, step1, and the smoothstep.
smoothstep(0.125, 0.127, NdotL) - this is performing a smoothstep or gradual transition based on the defined numbers and a dot product of normal and light direction.
To avoid confusion a dot() is a function that takes two vectors as inputs and computes the length of one vector projected onto the other. It can be thought of as a measure of how parallel the two input vectors are to each other.
I fully understand a lot of this may seem to be confusing or overwhelming and frankly, I agree with you. It's a lot to understand and as I have been experimenting the only thing I realize is how much I don't know.
Now that we have tackled a bunch of the technicals we can get to the best part - the results! Getting something to render even when wrong is still very rewarding. Even mistakes can provide some interesting results that you leave you thinking about how that can be used or tinkered with to provide more interesting results.
When working on the Cel shader I was tinkering with creating a hand drawn look and feel and accidently created this effect while using a time modifier. Granted it's not entirely useful when trying to enhance the Cel shader BUT the effect does get my imagination going as to what else it can be used for on things moving forward.
Could this be exploited for better clouds, sun surface, or gas giants? Who knows but half the fun is seeing results even if they aren't what you intended.
After finding out some level of texture animation is possible, I had a crazy idea to potentially use a similar effect to add a ripple effect to the water of a planet. Granted this effect is perhaps a bit too exaggerated, but getting unusual effects can have a knock-on effect that allows you to think of a new and exciting way to make your mod project or base game mod stand out from the rest.
In this video I decided to tinker with the specular effect to create a iridescence effect. This creates the effect of the color shifting when the object comes in line with light from the point light star at the center of a map. Not entirely sure how useful that is but nonetheless its a cool effect to have render successfully in game. Now lets kick it up a notch before wrapping this up.
In this video I took the iridescent effect and applied a rain type capillary effect over time. It's very visually trippy but as stated earlier sometimes even accidents can have useful outcomes.
This was by far the most ridiculous of examples I have but one of the most useful experiments because it shows effects can be isolated to specific mask layers and isolated on the object. I took the animated iridescent effect and isolated it to the primary team color channel. It looks ridiculous but is extremely useful for if you want to take an interesting shader effect and restrict it to a very particular part of the ship.
I want to wrap up this article by sharing my final thoughts; projects and mods for Sins 2 can be so much more than their predecessors. Shaders offer an opportunity for people who chose to create content for Sins 2 to go further than new assets and effects. Total conversion mods can now be drastically visually different from each other. My greatest hope is that articles like this further fan the flames of creativity and spur those of you who truly want to learn this as a craft to have a greater understanding of how to get there.
I want to shout an individual creator this week, Wildstar, from the Five Years of Fire mod. He is doing a mod based on an old anime and tried to create the look and feel of it which is what inspired me to go down the rabbit hole of doing a Cel shader. I will leave you with a final video of the Coronata in its most cartoony greatness. If you find this alternate shader intriguing, we would love to hear your thoughts!
Thank you,
Set