-
Notifications
You must be signed in to change notification settings - Fork 0
Putting HLSL in the shader file
Zack edited this page May 31, 2025
·
15 revisions
Replace PixelShader = <pSdr> with PixelShader = compile ps_1_1 ShaderName() to use the game's compiler
The game supports shader models 1_1 to 3_0, you should use 3.0 for the most features, but I'll write it for 1_1 here since it's a bit more limited
Texture Tex0;
Texture Tex1;
Texture Tex2;
Texture Tex3;
const string inputStreamFormat = "PosNormColorTex1";
// There is one flaw, getting the compiler to respect reserved constants is quite difficult.
// localToWorld's last row is considered unused, it gets treated like a 4x3 which doesn't sound right, but I guess that means it's not needed?
// That might be why it doesn't work with the validator
float4x4 localToScreen : register(c0);
float4x4 localToWorld : register(c4);
#define LocalToScreen(x) mul(x, localToScreen)
#define LocalToWorld(x) mul(x, localToWorld)
// I did try changing this line thinking it confused the compiler or something, but no.
#define RotateToWorld(x) mul(x, (float3x3)localToWorld)
float4 CAMERA : register(c8);
float4 CAMDIR : register(c9);
float4 TIME : register(c14);
float4 PLANEX : register(c17);
float4 PLANEY : register(c18);
float4 PLANEZ : register(c19);
struct VSInput
{
float3 pos : POSITION;
float3 nrm : NORMAL;
float4 diff : COLOR;
float2 uv : TEXCOORD0;
};
struct PSInput
{
float4 pos : POSITION;
// In shader model 1, the coordinate inputs need to match the textures
float2 uv1 : TEXCOORD0;
float3 reflectionUV : TEXCOORD1;
float2 uv2 : TEXCOORD2;
float3 normalUV : TEXCOORD3;
float4 AMBIENT : COLOR0;
float4 EXTRA : COLOR1;
};
#define FRESNEL AMBIENT.a
#define BLEND EXTRA.a
PSInput MyVertexShader(VSInput i)
{
PSInput o;
o.pos = LocalToScreen(float4(i.pos, 1));
o.uv1 = i.uv;
o.uv2 = i.uv;
float4 worldPos = LocalToWorld(float4(i.pos, 1));
float4 worldNormal;
worldNormal.xyz = RotateToWorld(i.nrm);
worldNormal.a = 1.0f;
o.normalUV = worldNormal.xyz;
float3 incident = normalize(worldPos.xyz - CAMERA.xyz);
o.reflectionUV = reflect(incident, worldNormal.xyz);
o.AMBIENT.x = sqrt(dot(worldNormal, PLANEX));
o.AMBIENT.y = sqrt(dot(worldNormal, PLANEY));
o.AMBIENT.z = sqrt(dot(worldNormal, PLANEZ));
float2 f;
f.x = abs(dot(worldNormal.xyz, incident));
f.x = 1.0f - f.x;
f.y = f.x * f.x * f.x;
o.FRESNEL = f.y * 0.5 + 0.5;
o.BLEND = i.diff.a;
o.EXTRA.rgb = float3(1.0f, 1.0f, 1.0f);
return o;
}
float4 SHADOW : register(c2);
sampler2D colour : register(s0);
samplerCUBE specular : register(s1);
sampler2D dirt : register(s2);
samplerCUBE lighting : register(s3);
float4 MyPixelShader(PSInput i) : COLOR
{
float4 c = texCUBE(specular, i.reflectionUV) * i.FRESNEL;
c = saturate(c + lerp(tex2D(colour, i.uv1), tex2D(dirt, i.uv2), i.BLEND));
float4 l = texCUBE(lighting, i.normalUV).a * SHADOW;
l = float4(saturate(i.AMBIENT.rgb * 0.6f + l), 1);
return c * l;
}
// The technique and pass name is the same across everything
Technique T0
{
Pass P0
{
// In FlatOut 2 the pass can require either a bit of setup or a lot depending on the shader
Texture[0] = <Tex0>;
Texture[1] = <Tex1>;
Texture[2] = <Tex2>;
Texture[3] = <Tex3>;
VertexShader = compile vs_1_1 MyVertexShader();
PixelShader = compile ps_1_1 MyPixelShader();
}
}