Seeking an actual example of a step shader with threshold

I’m an artist. I can ‘code’ a bit but only to the extent of getting the job done. I use visual-scripting and blueprints for absolutely everything I do.

I have tried to learn ‘pure’ coding, c#, etc. I got fairly far with javascript but not anything else. At this point, I’ve come to the accepting and undeniable fact that It’s just not how my mind works.

I am attempting to get the 90 degree threshold Step Shader, used in Guilty Gear Xrd and Xrd Revelator going inside a UE4 project. I want to do this so I can practice more-so from the asset set-up perspective.

I’ve watched the GDC video enough to memorize it. I understand in full why the shader works but I don’t know enough about HLSL to determine if they literally provided the code or not.

Here is the explanation they provided in the GDC video:

"Generic step(Threshold, dot(Light, Normal))

  • Determine if a surface is lit or not.

If the surface Normal is facing the Light source, it is lit.
If it is facing away more than 90dg (the threshold), it is not lit."

Am I to take this to mean that the ‘code’ is quite literally?
“generic step(Threshold, dot(Light, Normal))”?
If so does it need a semi-colon on the end of it?
Example: “generic step(Threshold, dot(Light, Normal);”

How would I indicate the 90-degree threshold? Do I do that in the code? Or through a ‘node’ in the blueprint? both?

Quite literally all I am looking for is the proper syntax for an HLSL shader in which you indicate whether a surface normal is lit or not and whether or not the light source is head on, or more than 90 degrees away. Just as their explanation states it should work.

Alternatively, can this exact same thing be accomplished with a blueprint? Because I understand blueprints so I’m totally open to being given a few reference links.

I can handle every single aspect of the asset set up (vertex colors, etc) on my own. but I simply cannot understand HLSL and the supporting documentation does not serve to explain how multiple parts work together (it’s not friendly to a non-programmer)

Thanks for taking the time to read this. Hopefully someone can provide guidance. Have an awesome day.

I’m afraid you’re not going to get very far without actually taking the time to learn how HLSL works and how all the parts fit together. You might want to try looking at example shaders (there are tons all over the internet) and checking out things like ShaderToy (https://www.shadertoy.com/).

To actually answer your question, the step function takes two values (y, x - note the order) and returns 1 if x is greater than or equal y, or 0 otherwise. It returns the same type as whatever x and y are (float, generally).

float LitOrNot = step(Threshold, dot(Light, Normal));

The dot product of vectors A and B returns the length of A times the length of B times the cosine of the angle between them ( dot(A, B) = |A|*|B|*cos(theta)). The Light and Normal vectors are probably unit length, so that dot product returns the cosine of the angle between them. This will be 1 if they are facing in the same direction, -1 if they are facing opposite directions, and 0 if they are perpendicular. The Threshold value is being compared to that cosine, so you could simply take the cosine of whatever angle you wish to test against and use that as the threshold - cosine(90deg) is 0, in your case.

I assume you’d rather implement this inside a material node graph than attempt to modify the underlying HLSL shaders. If you use the Unlit shading model, you can implement this “lighting model” yourself by using the following node graph, with the caveat that you must pass in the light vector yourself through a parameter:

Implementing a full cel-shaded lighting model that “just works” without you having to do a bunch of extra setup would involve actually adding a new shading model to the engine, but you might want to search for other examples, as I’m sure someone else has already done so.

1 Like

Thank you very much for your reply. I fully expected I’d have put the work in. Though I didn’t realize there was more to do on the engine side of things. I had mistakenly assumed I’d be spending less on that and more on vertex coloring and overall asset production (character models, etc).

This is exactly the explanation and example I needed to get rolling. I appreciate the help.