Skip to content

Instantly share code, notes, and snippets.

@saberhawk
Last active April 7, 2018 18:30
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save saberhawk/199235c38a2b1051f06f0340cec9b5b4 to your computer and use it in GitHub Desktop.
W3D shader generator
#define CBUFFER_BEGIN(name) cbuffer name { struct {
#define CBUFFER_BEGIN_SHARED(name) shared cbuffer name { struct {
#define CBUFFER_END(name) } name; };
CBUFFER_BEGIN(VertexMaterial)
float3 Diffuse;
float Opacity;
float3 Ambient;
float3 Emissive;
CBUFFER_END(VertexMaterial)
CBUFFER_BEGIN(EngineLighting)
float4 DirectionX;
float4 DirectionY;
float4 DirectionZ;
float3 Diffuse[4];
float3 Ambient;
CBUFFER_END(EngineLighting)
CBUFFER_BEGIN(EnginePerDraw)
float4x4 matrixW;
float4x4 matrixWIT;
CBUFFER_END(EnginePerDraw)
CBUFFER_BEGIN(EnginePerDrawMapper)
float4x4 matrixT0;
float4x4 matrixT1;
float4 BumpMatrix;
CBUFFER_END(EnginePerDrawMapper)
CBUFFER_BEGIN_SHARED(EnginePerCamera)
float4x4 matrixVP;
float4x4 matrixV;
float3 WorldCameraPosition;
CBUFFER_END(EnginePerCamera)
CBUFFER_BEGIN_SHARED(DistanceFog)
float4 Constants;
float3 Color;
float3 SunDirection;
float3 SunColor;
CBUFFER_END(DistanceFog);
void HandleUVSource(StringClass& params, int uv_source, const StringClass& stage_name)
{
if (uv_source & UV_SOURCE_PROJECTED)
params += stage_name + "_UV_SOURCE_PROJECTED;";
switch (uv_source & ~UV_SOURCE_PROJECTED)
{
case 0: params += stage_name + "_UV_SOURCE0;"; break;
case 1: params += stage_name + "_UV_SOURCE1;"; break;
case 2: params += stage_name + "_UV_SOURCE2;"; break;
case 3: params += stage_name + "_UV_SOURCE3;"; break;
case UV_SOURCE_VIEWNORMAL: params += stage_name + "_UV_SOURCE_VIEWNORMAL;"; break;
case UV_SOURCE_VIEWPOSITION: params += stage_name + "_UV_SOURCE_VIEWPOSITION;"; break;
case UV_SOURCE_VIEWREFLECT: params += stage_name + "_UV_SOURCE_VIEWREFLECT;"; break;
case UV_SOURCE_WORLDNORMAL: params += stage_name + "_UV_SOURCE_WORLDNORMAL;"; break;
case UV_SOURCE_WORLDREFLECT: params += stage_name + "_UV_SOURCE_WORLDREFLECT;"; break;
case UV_SOURCE_CLIPPOSITION: params += stage_name + "_UV_SOURCE_CLIPPOSITION;"; break;
default: assert("Unsupported" && false); break;
}
}
StringClass MaterialGroup::BuildShaderParamString() const
{
StringClass params("LIGHTING;", true);
if (material->Use_Vertex_Colors()) params += "VERTEX_COLOR;";
if (textures[0]) params += "MAIN_TEXTURE;";
if (material->Peek_Mapper(0) || material->Peek_Mapper(1))
{
params += "TEXTURE_MAPPER;";
}
HandleUVSource(params, material->Get_UV_Source(0), "MAIN");
HandleUVSource(params, material->Get_UV_Source(1), "DETAIL");
switch (blend_state.Get_Primary_Gradient())
{
case ShaderClass::GRADIENT_DISABLE: params += "GRADIENT_DISABLE;"; break;
case ShaderClass::GRADIENT_MODULATE: params += "GRADIENT_MODULATE;"; break;
case ShaderClass::GRADIENT_ADD: params += "GRADIENT_ADD;"; break;
case ShaderClass::GRADIENT_BUMPENVMAP: params += "GRADIENT_BUMPENVMAP;"; break;
case ShaderClass::GRADIENT_BUMPENVMAPLUMINANCE: params += "GRADIENT_BUMPENVMAPLUMINANCE;"; break;
case ShaderClass::GRADIENT_DOTPRODUCT3: params += "GRADIENT_DOTPRODUCT3;"; break;
}
auto detail_color = blend_state.Get_Post_Detail_Color_Func();
auto detail_alpha = blend_state.Get_Post_Detail_Alpha_Func();
if (textures[1]) params += "DETAIL_TEXTURE;";
else
{
detail_color = ShaderClass::DETAILCOLOR_DISABLE;
detail_alpha = ShaderClass::DETAILALPHA_DISABLE;
}
switch (detail_color)
{
case ShaderClass::DETAILCOLOR_DISABLE: params += "DETAILCOLOR_DISABLE;"; break;
case ShaderClass::DETAILCOLOR_DETAIL: params += "DETAILCOLOR_DETAIL;"; break;
case ShaderClass::DETAILCOLOR_SCALE: params += "DETAILCOLOR_SCALE;"; break;
case ShaderClass::DETAILCOLOR_INVSCALE: params += "DETAILCOLOR_INVSCALE;"; break;
case ShaderClass::DETAILCOLOR_ADD: params += "DETAILCOLOR_ADD;"; break;
case ShaderClass::DETAILCOLOR_SUB: params += "DETAILCOLOR_SUB;"; break;
case ShaderClass::DETAILCOLOR_SUBR: params += "DETAILCOLOR_SUBR;"; break;
case ShaderClass::DETAILCOLOR_BLEND: params += "DETAILCOLOR_BLEND;"; break;
case ShaderClass::DETAILCOLOR_DETAILBLEND: params += "DETAILCOLOR_DETAILBLEND;"; break;
}
switch (detail_alpha)
{
case ShaderClass::DETAILALPHA_DISABLE: params += "DETAILALPHA_DISABLE;"; break;
case ShaderClass::DETAILALPHA_DETAIL: params += "DETAILALPHA_DETAIL;"; break;
case ShaderClass::DETAILALPHA_SCALE: params += "DETAILALPHA_SCALE;"; break;
case ShaderClass::DETAILALPHA_INVSCALE: params += "DETAILALPHA_INVSCALE;"; break;
}
if (blend_state.Get_Alpha_Test() == ShaderClass::ALPHATEST_ENABLE)
params += "ALPHA_TEST;";
switch (blend_state.Get_Fog_Func())
{
case ShaderClass::FOG_ENABLE: params += "FOG;"; break;
case ShaderClass::FOG_SCALE_FRAGMENT: params += "FOG;FOG_SCALE_FRAGMENT;"; break;
case ShaderClass::FOG_WHITE: params += "FOG;FOG_WHITE;"; break;
}
return params;
}
#include "engine.fxh"
#material vertex vs_main
#material pixel ps_main
#if MAIN_TEXTURE
Texture2D MainTexture;
SamplerState MainTextureSampler;
#endif
#if DETAIL_TEXTURE
Texture2D DetailTexture;
SamplerState DetailTextureSampler;
#endif
#if NORMAL_MAP
Texture2D NormalMap;
SamplerState NormalMapSampler;
#endif
struct vertexInput
{
float3 Position : POSITION;
#if LIGHTING
float3 Normal : NORMAL;
#endif
#if NORMAL_MAP
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
#endif
#if VERTEX_COLOR
float4 Color : COLOR0;
#endif
#if MAIN_UV_SOURCE0 || DETAIL_UV_SOURCE0
float2 TexCoord0 : TEXCOORD0;
#endif
#if MAIN_UV_SOURCE1 || DETAIL_UV_SOURCE1
float2 TexCoord1 : TEXCOORD1;
#endif
#if MAIN_UV_SOURCE2 || DETAIL_UV_SOURCE2
float2 TexCoord2 : TEXCOORD2;
#endif
#if MAIN_UV_SOURCE3 || DETAIL_UV_SOURCE3
float2 TexCoord3 : TEXCOORD3;
#endif
#if MAIN_UV_SOURCE4 || DETAIL_UV_SOURCE4
float2 TexCoord4 : TEXCOORD4;
#endif
};
struct vertexOutput
{
float4 Position : SV_POSITION;
#if VERTEX_COLOR
float4 Color : COLOR0;
#endif
#if MAIN_TEXTURE
float3 TexCoord0 : TEXCOORD0;
#endif
#if DETAIL_TEXTURE
float3 TexCoord1 : TEXCOORD1;
#endif
float4 WorldPos : TEXCOORD2;
#if LIGHTING
#if NORMAL_MAP
float3 Normal : TEXCOORD3;
float3 Tangent : TEXCOORD4;
float3 Binormal : TEXCOORD5;
#else
float3 Normal : TEXCOORD3;
#endif
#endif
#if LIGHTING || FOG
float3 View : TEXCOORD6;
#endif
#if FOG
float3 Fog : TEXCOORD7;
#endif
};
#define pixelInput vertexOutput
vertexOutput vs_main(vertexInput IN)
{
vertexOutput OUT;
float4 world_position = mul(float4(IN.Position, 1), EnginePerDraw.matrixW);
float4 clip_position = mul(world_position, EnginePerCamera.matrixVP);
OUT.Position = clip_position;
OUT.WorldPos = world_position;
#if LIGHTING
float3 world_normal = mul(float4(IN.Normal, 0), EnginePerDraw.matrixWIT).xyz;
OUT.Normal = world_normal;
#if NORMAL_MAP
float3 world_tangent = mul(float4(IN.Tangent, 0), EnginePerDraw.matrixWIT).xyz;
OUT.Tangent = world_tangent;
float3 world_binormal = mul(float4(IN.Binormal, 0), EnginePerDraw.matrixWIT).xyz;
OUT.Binormal = world_binormal;
#endif
#endif
#if VERTEX_COLOR
OUT.Color = float4(pow(abs(IN.Color.rgb), 2.2f), IN.Color.a);
#endif
#if MAIN_UV_SOURCE_WORLDREFLECT || DETAIL_UV_SOURCE_WORLDREFLECT || MAIN_UV_SOURCE_VIEWREFLECT || DETAIL_UV_SOURCE_VIEWREFLECT
float3 incident = world_position.xyz - EnginePerCamera.WorldCameraPosition;
#endif
float4 texcoord;
#if MAIN_TEXTURE
#if MAIN_UV_SOURCE0
texcoord = float4(IN.TexCoord0.xy, 1, 0);
#elif MAIN_UV_SOURCE1
texcoord = float4(IN.TexCoord1.xy, 1, 0);
#elif MAIN_UV_SOURCE2
texcoord = float4(IN.TexCoord2.xy, 1, 0);
#elif MAIN_UV_SOURCE3
texcoord = float4(IN.TexCoord3.xy, 1, 0);
#elif MAIN_UV_SOURCE_WORLDNORMAL
texcoord = float4(world_normal, 0);
#elif MAIN_UV_SOURCE_WORLDREFLECT
texcoord = normalize(float4(reflect(incident, world_normal), 0));
texcoord.w = 1;
#elif MAIN_UV_SOURCE_VIEWNORMAL
texcoord = mul(float4(world_normal, 0), EnginePerCamera.matrixV);
texcoord.w = 1;
#elif MAIN_UV_SOURCE_VIEWPOSITION
texcoord = mul(float4(world_position.xyz, 1), EnginePerCamera.matrixV);
texcoord.w = 1;
#elif MAIN_UV_SOURCE_VIEWREFLECT
texcoord = normalize(mul(float4(reflect(incident, world_normal), 0), EnginePerCamera.matrixV));
texcoord.w = 1;
#elif MAIN_UV_SOURCE_CLIPPOSITION
texcoord = clip_position;
#endif
#if TEXTURE_MAPPER
texcoord = mul(texcoord, EnginePerDrawMapper.matrixT0);
#endif
#if MAIN_UV_SOURCE_PROJECTED
OUT.TexCoord0 = float3(texcoord.xy, texcoord.w);
#else
OUT.TexCoord0 = float3(texcoord.xy, 1);
#endif
#endif
#if DETAIL_TEXTURE
#if DETAIL_UV_SOURCE0
texcoord = float4(IN.TexCoord0.xy, 1, 0);
#elif DETAIL_UV_SOURCE1
texcoord = float4(IN.TexCoord1.xy, 1, 0);
#elif DETAIL_UV_SOURCE2
texcoord = float4(IN.TexCoord2.xy, 1, 0);
#elif DETAIL_UV_SOURCE3
texcoord = float4(IN.TexCoord3.xy, 1, 0);
#elif DETAIL_UV_SOURCE_WORLDNORMAL
texcoord = float4(world_normal, 0);
#elif DETAIL_UV_SOURCE_WORLDREFLECT
texcoord = normalize(float4(reflect(incident, world_normal), 0));
texcoord.w = 1;
#elif DETAIL_UV_SOURCE_VIEWNORMAL
texcoord = mul(float4(world_normal, 0), EnginePerCamera.matrixV);
texcoord.w = 1;
#elif DETAIL_UV_SOURCE_VIEWPOSITION
texcoord = mul(float4(world_position.xyz, 1), EnginePerCamera.matrixV);
texcoord.w = 1;
#elif DETAIL_UV_SOURCE_VIEWREFLECT
texcoord = normalize(mul(float4(reflect(incident, world_normal), 0), EnginePerCamera.matrixV));
texcoord.w = 1;
#elif DETAIL_UV_SOURCE_CLIPPOSITION
texcoord = clip_position;
#endif
#if TEXTURE_MAPPER
texcoord = mul(texcoord, EnginePerDrawMapper.matrixT1);
#endif
#if DETAIL_UV_SOURCE_PROJECTED
OUT.TexCoord1 = float3(texcoord.xy, texcoord.w);
#else
OUT.TexCoord1 = float3(texcoord.xy, 1);
#endif
#endif
#if LIGHTING || FOG
OUT.View = normalize(EnginePerCamera.WorldCameraPosition - world_position.xyz);
#endif
#if FOG
OUT.Fog = clip_position.xyz;
#endif
return OUT;
};
float4 ps_main(vertexOutput IN): SV_TARGET
{
float4 color_out = float4(VertexMaterial.Emissive, VertexMaterial.Opacity);
float3 material_diffuse, material_ambient;
float4 view_pos = mul(float4(IN.WorldPos.xyz, 1), EnginePerCamera.matrixV);
#if VERTEX_COLOR
color_out *= IN.Color;
material_diffuse = VertexMaterial.Diffuse.rgb * IN.Color.rgb;
material_ambient = VertexMaterial.Ambient.rgb * IN.Color.rgb;
#else
material_diffuse = VertexMaterial.Diffuse.rgb;
material_ambient = VertexMaterial.Ambient.rgb;
#endif
#if LIGHTMAP
float2 light_uv = IN.LightmapUV.xy;
float4 lightmap = tex2D(LightmapTexture, light_uv);
#endif
#if LIGHTING
#if NORMAL_MAP
float3x3 tbn;
tbn[0] = normalize(IN.Tangent);
tbn[1] = normalize(IN.Binormal);
tbn[2] = normalize(IN.Normal);
float3 normal_map = NormalMap.Sample(NormalMapSampler, IN.TexCoord0.xy).rgb * 2 - 1;
float3 N = normalize(mul(normal_map, tbn));
#else
float3 N = normalize(IN.Normal);
#endif
float4 lambert;
lambert = EngineLighting.DirectionX * N.x;
lambert += EngineLighting.DirectionY * N.y;
lambert += EngineLighting.DirectionZ * N.z;
lambert = max(0, lambert);
float3 diffuse = EngineLighting.Diffuse[0].rgb * lambert.x;
diffuse += EngineLighting.Diffuse[1].rgb * lambert.y;
diffuse += EngineLighting.Diffuse[2].rgb * lambert.z;
diffuse += EngineLighting.Diffuse[3].rgb * lambert.w;
#if LIGHTMAP
color_out.rgb += lightmap.rgb;
#else
color_out.rgb += EngineLighting.Ambient.rgb * material_ambient;
#endif
color_out.rgb += diffuse * material_diffuse;
#else
color_out.rgb = material_diffuse.rgb;
#endif
#if MAIN_TEXTURE
#if MAIN_UV_SOURCE_PROJECTED
float4 main_texture = MainTexture.Sample(MainTextureSampler, IN.TexCoord0.xy / IN.TexCoord0.z);
#else
float4 main_texture = MainTexture.Sample(MainTextureSampler, IN.TexCoord0.xy);
#endif
#if GRADIENT_DISABLE
color_out = main_texture;
#elif GRADIENT_BUMPENVMAP
IN.TexCoord1.x += main_texture.r * EnginePerDrawMapper.BumpMatrix.x + main_texture.g * EnginePerDrawMapper.BumpMatrix.z;
IN.TexCoord1.y += main_texture.r * EnginePerDrawMapper.BumpMatrix.y + main_texture.g * EnginePerDrawMapper.BumpMatrix.w;
#elif GRADIENT_MODULATE
color_out *= main_texture;
#elif GRADIENT_ADD
color_out.rgb += main_texture.rgb;
color_out.a = main_texture.a;
#endif
#endif
#if DETAIL_TEXTURE
#if DETAIL_UV_SOURCE_PROJECTED
float4 detail_texture = DetailTexture.Sample(DetailTextureSampler, IN.TexCoord1.xy / IN.TexCoord1.z);
#else
float4 detail_texture = DetailTexture.Sample(DetailTextureSampler, IN.TexCoord1.xy);
#endif
#if DETAILCOLOR_DETAIL
color_out.rgb = detail_texture.rgb;
#elif DETAILCOLOR_SCALE
color_out.rgb *= detail_texture.rgb;
#elif DETAILCOLOR_INVSCALE
color_out.rgb = detail_texture.rgb + color_out.rgb * (1 - detail_texture.rgb);
#elif DETAILCOLOR_ADD
color_out.rgb += detail_texture.rgb;
#elif DETAILCOLOR_SUB
color_out.rgb = detail_texture.rgb - color_out.rgb;
#elif DETAILCOLOR_SUBR
color_out.rgb -= detail_texture.rgb;
#elif DETAILCOLOR_BLEND
color_out.rgb = lerp(color_out.rgb, detail_texture.rgb, detail_texture.a);
#elif DETAILCOLOR_DETAILBLEND
color_out.rgb = lerp(color_out.rgb, detail_texture.rgb, color_out.a);
#endif
#if DETAILALPHA_DETAIL
color_out.a = detail_texture.a;
#elif DETAILALPHA_SCALE
color_out.a *= detail_texture.a;
#elif DETAILALPHA_INVSCALE
color_out.a = detail_texture.a + color_out.a * (1 - detail_texture.a);
#endif
#endif
#if FOG
float3 fog_color;
#if FOG_SCALE_FRAGMENT
fog_color = 0;
#elif FOG_WHITE
fog_color = 1;
#else
float sun_amount = max(dot(IN.View, normalize(DistanceFog.SunDirection)), 0);
float3 sun_color = lerp(DistanceFog.Color, DistanceFog.SunColor, 0.25f);
fog_color = lerp(DistanceFog.Color, sun_color, pow(sun_amount, 16));
#endif
float fog = saturate(length(IN.Fog) * DistanceFog.Constants.x + DistanceFog.Constants.y);
color_out.rgb = lerp(fog_color, color_out.rgb, fog);
#endif
#if ALPHA_TEST
if (color_out.a < 0.375)
discard;
#endif
return color_out;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment