Hi friends,
You may have heard of HLSL before. It's an alternative to the default language(GLSL ES), specifically designed for Windows and Xbox (Direct3D).
Tutorial Difficulty: Advanced
Today we're going to show how to write your first HLSL coming from a GLSL ES perspective. HLSL stands for High-Level Shading Language.
To start, you'll have to right-click your shader to switch to HLSL:
HLSL Features
You might be wondering why you'd want to use HLSL instead of GLSL, which runs on any platform? There are a few reasons to consider.
Firstly, is efficiency. If you want to squeeze as much performance as possible out of your code, HLSL will help you do it. In GameMaker, when you compile your game for Windows, GM internally coverts your GLSL ES code to HLSL. This gives you extra control of your code, so you can fine tune every line.
Secondly, HLSL gives you some extra features: extra functions, Multiple Render Targets (although you can now do this in GLSL ES with gl_FragData[]), native support for derivatives without extensions, built-in transpose, etc.
Thirdly, personal preference. Many coders like the language and syntax better. It's arguably more consistent and therefore easier to remember compared to GLSL.
Okay, so now you know if HLSL is worth learning for you! Let's dig in!
Format Differences
The biggest difference is with how HLSL shaders interact with the outside. Instead of "attributes" and "varying" for inputs and outputs, HLSL uses custom structs. HLSL attribute looks like this:
struct ATTRIBUTE
{
float3 pos : POSITION;
float2 tex : TEXCOORD0;
float4 col : COLOR;
};
It doesn't have to be called "ATTRIBUTES", I just picked that to make the comparison more clear. You can also rename "pos", "tex", and "col". The important parts are "POSITION", "TEXCOORD0-7" and "COLOR" which are directly linked to the attributes from outside of the shader.
You also do the same for varying vectors and color outputs as "COLOR0-3" (the equivalent of gl_FragData[X]). This means you can actually output different colors to separate surfaces using surface_set_target_ext()
, but most of the time just one output is used (the equivalent of gl_FragColor).
So the HLSL main function looks like this:
VARYING main(ATTRIBUTE INPUT)
There's one argument using our ATTRIBUTE struct and returns our VARYING struct.
The pixel shader is quite similar:
TARGET main(VARYING INPUT) : SV_TARGET
Except you gotta include the SV_TARGET.
The full code will be shared at the end!
Data Types and Functions
Let's talk about the data types naming differences:
GLSL
=>
HLSL
vec2-vec4 => float2-float4
ivec2-ivec4 => int2-int4
mat2-mat4 => float2x2-float4x4
float, int and sampler2D are unchanged
Some of the functions have also been renamed:
GLSL
=>
HLSL
mod(a,b) => fmod(a,b)
mix(a,b,c) => lerp(a,b,c)
fract(x) => frac(x)
inversesqrt(x) => rsqrt(x)
clamp(x,0.0,1.0) <= saturate(x)
log(x) / log(10.) <= log10(x)
if (x<0.0) discard; <= clip(x)
1.0/x <= rcp(x)
atan(y,x) => atan2(x,y)
dFdx(x)* => ddx(x)
dFdy(x)* => ddy(x)
Textures and Samplers
And finally, we can talk about textures. In GLSL, you only have to care about samplers, but in HLSL textures and samplers are separate parts.
To sample a texture, we use the "Sample" function instead of texture2D:
float4 base = texture_name.Sample(sampler_name, texcoord);-
So for example, with the base texture, you use "gm_BaseTextureObject" for the texture name and "gm_BaseTexture" for the sampler:
float4 base = gm_BaseTextureObject.Sample(gm_BaseTexture, INPUT.tex);
If you need to use multiple textures you have to register them in the shader:
Texture2D texture_name : register(t1);
t0 is for the base texture, but you can use t1, t2, t3... for additional textures.
"texture_name" can be replaced with whatever you like.
SamplerState sampler_name : register(s1);
Again, we number them s1, s2, s3...
"sampler_name" would be the name of the uniform used in GML. Nothing needs to change on the GML side!
Conclusion
Here's the full code for a basic passthrough HLSL 11 shader. And just like that, you learned 90% of HLSL! Hopefully, this was easy enough to follow along while still being useful. If you want to do further reading, I'd advise starting here!
Anyway, thanks for reading. Have a great night!