- rewrite the user shader support for materials - new syntax is to create a 'Material ProcessMaterial()' function

This commit is contained in:
Magnus Norddahl 2018-07-15 23:01:40 +02:00
parent 7817e6a7b2
commit 8a500a25f5
15 changed files with 220 additions and 108 deletions

View file

@ -226,13 +226,31 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump);
FMemLump pp_data = Wads.ReadLump(pp_lump);
if (pp_data.GetString().IndexOf("ProcessTexel") < 0)
if (pp_data.GetString().IndexOf("ProcessMaterial") < 0)
{
// this looks like an old custom hardware shader.
// We need to replace the ProcessTexel call to make it work.
fp_comb.Substitute("vec4 frag = ProcessTexel();", "vec4 frag = Process(vec4(1.0));");
// add ProcessMaterial function that calls the older ProcessTexel function
int pl_lump = Wads.CheckNumForFullName("shaders/glsl/func_defaultmat.fp");
if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultmat.fp");
FMemLump pl_data = Wads.ReadLump(pl_lump);
fp_comb << "\n" << pl_data.GetString().GetChars();
if (pp_data.GetString().IndexOf("ProcessTexel") < 0)
{
// this looks like an even older custom hardware shader.
// We need to replace the ProcessTexel call to make it work.
fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));");
}
if (pp_data.GetString().IndexOf("ProcessLight") >= 0)
{
// The ProcessLight signatured changed. Forward to the old one.
fp_comb << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n";
}
}
fp_comb << RemoveLegacyUserUniforms(pp_data.GetString()).GetChars();
fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders.
@ -477,11 +495,11 @@ static const FDefaultShader defaultshaders[]=
{"Default", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", ""},
{"Warp 1", "shaders/glsl/func_warp1.fp", "shaders/glsl/material_normal.fp", ""},
{"Warp 2", "shaders/glsl/func_warp2.fp", "shaders/glsl/material_normal.fp", ""},
{"Brightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_normal.fp", ""},
{"Specular", "shaders/glsl/func_normal.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"},
{"SpecularBrightmap", "shaders/glsl/func_brightmap.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"},
{"PBR","shaders/glsl/func_normal.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"},
{"PBRBrightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"},
{"Brightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_normal.fp", "#define BRIGHTMAP\n"},
{"Specular", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"},
{"SpecularBrightmap", "shaders/glsl/func_spec.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n#define BRIGHTMAP\n"},
{"PBR","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"},
{"PBRBrightmap","shaders/glsl/func_pbr.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n#define BRIGHTMAP\n"},
{"Paletted", "shaders/glsl/func_paletted.fp", "shaders/glsl/material_nolight.fp", ""},
{"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", ""},
{"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""},
@ -495,9 +513,7 @@ static const FDefaultShader defaultshaders[]=
{nullptr,nullptr,nullptr,nullptr}
};
TArray<FString> usershaders;
TArray<FString> usermaterials;
TArray<FString> usershaderdefs;
TArray<UserShaderDesc> usershaders;
struct FEffectShader
{
@ -646,10 +662,9 @@ void FShaderCollection::CompileShaders(EPassType passType)
for(unsigned i = 0; i < usershaders.Size(); i++)
{
FString name = ExtractFileBase(usershaders[i]);
FName sfn = name;
FShader *shc = Compile(sfn, usershaders[i], usermaterials[i], usershaderdefs[i], true, passType);
FString name = ExtractFileBase(usershaders[i].shader);
FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines;
FShader *shc = Compile(name, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, passType);
mMaterialShaders.Push(shc);
}

View file

@ -31,6 +31,8 @@
EXTERN_CVAR(Bool, gl_texture_usehires)
extern TArray<UserShaderDesc> usershaders;
//===========================================================================
//
//
@ -127,12 +129,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
mShaderIndex = SHADER_Default;
sourcetex = tex = tx;
// TODO: apply custom shader object here
/* if (tx->CustomShaderDefinition)
{
}
else
*/
if (tx->UseType == ETextureType::SWCanvas && tx->WidthBits == 0)
{
mShaderIndex = SHADER_Paletted;
@ -152,48 +148,50 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
}
else
{
if (tx->shaderindex >= FIRST_USER_SHADER)
if (tx->Normal && tx->Specular)
{
for (auto &texture : tx->CustomShaderTextures)
for (auto &texture : { tx->Normal, tx->Specular })
{
if(texture == nullptr) continue;
ValidateSysTexture(texture, expanded);
mTextureLayers.Push(texture);
}
mShaderIndex = tx->shaderindex;
mShaderIndex = SHADER_Specular;
}
else
else if (tx->Normal && tx->Metallic && tx->Roughness && tx->AmbientOcclusion)
{
if (tx->Normal && tx->Specular)
for (auto &texture : { tx->Normal, tx->Metallic, tx->Roughness, tx->AmbientOcclusion })
{
for (auto &texture : { tx->Normal, tx->Specular })
{
ValidateSysTexture(texture, expanded);
mTextureLayers.Push(texture);
}
mShaderIndex = SHADER_Specular;
}
else if (tx->Normal && tx->Metallic && tx->Roughness && tx->AmbientOcclusion)
{
for (auto &texture : { tx->Normal, tx->Metallic, tx->Roughness, tx->AmbientOcclusion })
{
ValidateSysTexture(texture, expanded);
mTextureLayers.Push(texture);
}
mShaderIndex = SHADER_PBR;
ValidateSysTexture(texture, expanded);
mTextureLayers.Push(texture);
}
mShaderIndex = SHADER_PBR;
}
tx->CreateDefaultBrightmap();
if (tx->Brightmap != NULL)
tx->CreateDefaultBrightmap();
if (tx->Brightmap)
{
ValidateSysTexture(tx->Brightmap, expanded);
mTextureLayers.Push(tx->Brightmap);
if (mShaderIndex == SHADER_Specular)
mShaderIndex = SHADER_SpecularBrightmap;
else if (mShaderIndex == SHADER_PBR)
mShaderIndex = SHADER_PBRBrightmap;
else
mShaderIndex = SHADER_Brightmap;
}
if (tx->shaderindex >= FIRST_USER_SHADER)
{
const UserShaderDesc &usershader = usershaders[tx->shaderindex - FIRST_USER_SHADER];
if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
{
ValidateSysTexture(tx->Brightmap, expanded);
mTextureLayers.Push(tx->Brightmap);
if (mShaderIndex == SHADER_Specular)
mShaderIndex = SHADER_SpecularBrightmap;
else if (mShaderIndex == SHADER_PBR)
mShaderIndex = SHADER_PBRBrightmap;
else
mShaderIndex = SHADER_Brightmap;
for (auto &texture : tx->CustomShaderTextures)
{
if (texture == nullptr) continue;
ValidateSysTexture(texture, expanded);
mTextureLayers.Push(texture);
}
mShaderIndex = tx->shaderindex;
}
}
}

View file

@ -45,14 +45,13 @@
#include "a_dynlight.h"
#include "textures/skyboxtexture.h"
#include "hwrenderer/postprocessing/hw_postprocessshader.h"
#include "hwrenderer/textures/hw_material.h"
void AddLightDefaults(FLightDefaults *defaults, double attnFactor);
void AddLightAssociation(const char *actor, const char *frame, const char *light);
void InitializeActorLights(TArray<FLightAssociation> &LightAssociations);
extern TArray<FString> usershaders;
extern TArray<FString> usermaterials;
extern TArray<FString> usershaderdefs;
extern TArray<UserShaderDesc> usershaders;
extern TDeletingArray<FLightDefaults *> LightDefaults;
@ -1379,10 +1378,11 @@ class GLDefsParser
bool thiswad = false;
bool iwad = false;
int maplump = -1;
FString maplumpname;
FString materiallumpname = "shaders/glsl/material_normal.fp";
FString texnameDefs = "";
UserShaderDesc desc;
desc.shaderType = SHADER_Default;
TArray<FString> texNameList;
TArray<FString> texNameIndex;
FString texnameDefs = "";
float speed = 1.f;
sc.MustGetString();
@ -1396,12 +1396,25 @@ class GLDefsParser
if (sc.Compare("shader"))
{
sc.MustGetString();
maplumpname = sc.String;
desc.shader = sc.String;
}
else if (sc.Compare("material"))
{
sc.MustGetString();
materiallumpname = sc.String;
MaterialShaderIndex typeIndex[6] = { SHADER_Default, SHADER_Brightmap, SHADER_Specular, SHADER_SpecularBrightmap, SHADER_PBR, SHADER_PBRBrightmap };
const char *typeName[6] = { "normal", "brightmap", "specular", "specularbrightmap", "pbr", "pbrbrightmap" };
bool found = false;
for (int i = 0; i < 6; i++)
{
if (sc.Compare(typeName[i]))
{
desc.shaderType = typeIndex[i];
found = true;
break;
}
}
if (!found)
sc.ScriptError("Unknown material type '%s' specified\n", sc.String);
}
else if (sc.Compare("speed"))
{
@ -1419,7 +1432,6 @@ class GLDefsParser
sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex? tex->Name.GetChars() : "(null)");
}
}
texNameList.Push(textureName);
sc.MustGetString();
bool okay = false;
for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++)
@ -1432,7 +1444,8 @@ class GLDefsParser
sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex? tex->Name.GetChars() : "(null)");
}
texnameDefs.AppendFormat("#define %s texture%d\n", textureName.GetChars(), i + 2);
texNameList.Push(textureName);
texNameIndex.Push(i);
okay = true;
break;
}
@ -1460,7 +1473,24 @@ class GLDefsParser
return;
}
if (maplumpname.IsNotEmpty())
int firstUserTexture;
switch (desc.shaderType)
{
default:
case SHADER_Default: firstUserTexture = 2; break;
case SHADER_Brightmap: firstUserTexture = 3; break;
case SHADER_Specular: firstUserTexture = 4; break;
case SHADER_SpecularBrightmap: firstUserTexture = 5; break;
case SHADER_PBR: firstUserTexture = 6; break;
case SHADER_PBRBrightmap: firstUserTexture = 7; break;
}
for (unsigned int i = 0; i < texNameList.Size(); i++)
{
texnameDefs.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture);
}
if (desc.shader.IsNotEmpty())
{
if (tex->bWarped != 0)
{
@ -1470,17 +1500,15 @@ class GLDefsParser
tex->shaderspeed = speed;
for (unsigned i = 0; i < usershaders.Size(); i++)
{
if (!usershaders[i].CompareNoCase(maplumpname) &&
!usermaterials[i].CompareNoCase(materiallumpname) &&
!usershaderdefs[i].Compare(texnameDefs))
if (!usershaders[i].shader.CompareNoCase(desc.shader) &&
usershaders[i].shaderType == desc.shaderType &&
!usershaders[i].defines.Compare(texnameDefs))
{
tex->shaderindex = i + FIRST_USER_SHADER;
return;
}
}
tex->shaderindex = usershaders.Push(maplumpname) + FIRST_USER_SHADER;
usermaterials.Push(materiallumpname);
usershaderdefs.Push(texnameDefs);
tex->shaderindex = usershaders.Push(desc) + FIRST_USER_SHADER;
}
}
}

View file

@ -72,6 +72,12 @@ enum MaterialShaderIndex
FIRST_USER_SHADER
};
struct UserShaderDesc
{
FString shader;
MaterialShaderIndex shaderType;
FString defines;
};
struct FloatRect
{

View file

@ -1,11 +1,9 @@
vec4 ProcessTexel()
Material ProcessMaterial()
{
return getTexel(vTexCoord.st);
}
vec4 ProcessLight(vec4 color)
{
vec4 brightpix = desaturate(texture(brighttexture, vTexCoord.st));
return vec4(min (color.rgb + brightpix.rgb, 1.0), color.a);
Material material;
material.Base = getTexel(vTexCoord.st);
material.Normal = ApplyNormalMap(vTexCoord.st);
material.Bright = texture(brighttexture, vTexCoord.st);
return material;
}

View file

@ -1,5 +1,17 @@
vec4 ProcessLight(vec4 color)
#if defined(BRIGHTMAP)
vec4 ProcessLight(Material material, vec4 color)
{
vec4 brightpix = desaturate(material.Bright);
return vec4(min(color.rgb + brightpix.rgb, 1.0), color.a);
}
#else
vec4 ProcessLight(Material material, vec4 color)
{
return color;
}
#endif

View file

@ -0,0 +1,11 @@
Material ProcessMaterial()
{
Material material;
material.Base = ProcessTexel();
material.Normal = ApplyNormalMap(vTexCoord.st);
#if defined(BRIGHTMAP)
material.Bright = texture(brighttexture, vTexCoord.st);
#endif
return material;
}

View file

@ -1,6 +1,8 @@
vec4 ProcessTexel()
Material ProcessMaterial()
{
return getTexel(vTexCoord.st);
Material material;
material.Base = getTexel(vTexCoord.st);
material.Normal = ApplyNormalMap(vTexCoord.st);
return material;
}

View file

@ -0,0 +1,14 @@
Material ProcessMaterial()
{
Material material;
material.Base = getTexel(vTexCoord.st);
material.Normal = ApplyNormalMap(vTexCoord.st);
material.Metallic = texture(metallictexture, vTexCoord.st).r;
material.Roughness = texture(roughnesstexture, vTexCoord.st).r;
material.AO = texture(aotexture, vTexCoord.st).r;
#if defined(BRIGHTMAP)
material.Bright = texture(brighttexture, vTexCoord.st);
#endif
return material;
}

View file

@ -0,0 +1,14 @@
Material ProcessMaterial()
{
Material material;
material.Base = getTexel(vTexCoord.st);
material.Normal = ApplyNormalMap(vTexCoord.st);
material.Specular = texture(speculartexture, vTexCoord.st).rgb;
material.Glossiness = uSpecularMaterial.x;
material.SpecularLevel = uSpecularMaterial.y;
#if defined(BRIGHTMAP)
material.Bright = texture(brighttexture, vTexCoord.st);
#endif
return material;
}

View file

@ -12,10 +12,24 @@ layout(location=1) out vec4 FragFog;
layout(location=2) out vec4 FragNormal;
#endif
struct Material
{
vec4 Base;
vec4 Bright;
vec3 Normal;
vec3 Specular;
float Glossiness;
float SpecularLevel;
float Metallic;
float Roughness;
float AO;
};
vec4 Process(vec4 color);
vec4 ProcessTexel();
vec4 ProcessLight(vec4 color);
vec3 ProcessMaterial(vec3 material, vec3 color);
Material ProcessMaterial();
vec4 ProcessLight(Material mat, vec4 color);
vec3 ProcessMaterialLight(Material material, vec3 color);
//===========================================================================
//
@ -288,7 +302,7 @@ mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv)
return mat3(t * invmax, b * invmax, n);
}
vec3 ApplyNormalMap()
vec3 ApplyNormalMap(vec2 texcoord)
{
#define WITH_NORMALMAP_UNSIGNED
#define WITH_NORMALMAP_GREEN_UP
@ -296,7 +310,7 @@ vec3 ApplyNormalMap()
vec3 interpolatedNormal = normalize(vWorldNormal.xyz);
vec3 map = texture(normaltexture, vTexCoord.st).xyz;
vec3 map = texture(normaltexture, texcoord).xyz;
#if defined(WITH_NORMALMAP_UNSIGNED)
map = map * 255./127. - 128./127.; // Math so "odd" because 0.5 cannot be precisely described in an unsigned format
#endif
@ -312,7 +326,7 @@ vec3 ApplyNormalMap()
return bumpedNormal;
}
#else
vec3 ApplyNormalMap()
vec3 ApplyNormalMap(vec2 texcoord)
{
return normalize(vWorldNormal.xyz);
}
@ -332,7 +346,7 @@ vec3 ApplyNormalMap()
//
//===========================================================================
vec4 getLightColor(vec4 material, float fogdist, float fogfactor)
vec4 getLightColor(Material material, float fogdist, float fogfactor)
{
vec4 color = vColor;
@ -371,12 +385,12 @@ vec4 getLightColor(vec4 material, float fogdist, float fogfactor)
//
// apply brightmaps (or other light manipulation by custom shaders.
//
color = ProcessLight(color);
color = ProcessLight(material, color);
//
// apply dynamic lights
//
return vec4(ProcessMaterial(material.rgb, color.rgb), material.a * vColor.a);
return vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a);
}
//===========================================================================
@ -425,7 +439,8 @@ vec3 AmbientOcclusionColor()
void main()
{
vec4 frag = ProcessTexel();
Material material = ProcessMaterial();
vec4 frag = material.Base;
#ifndef NO_ALPHATEST
if (frag.a <= uAlphaThreshold) discard;
@ -476,7 +491,7 @@ void main()
fogfactor = exp2 (uFogDensity * fogdist);
}
frag = getLightColor(frag, fogdist, fogfactor);
frag = getLightColor(material, fogdist, fogfactor);
//
// colored fog
@ -510,7 +525,7 @@ void main()
case 4: // simple 2D (reuses a uniform for the special colormap for the color overlay.)
{
frag = frag * ProcessLight(vColor);
frag = frag * ProcessLight(material, vColor);
frag.rgb = frag.rgb + uFogColor.rgb;
break;
}
@ -522,4 +537,3 @@ void main()
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
#endif
}

View file

@ -1,5 +1,5 @@
vec3 ProcessMaterial(vec3 material, vec3 color)
vec3 ProcessMaterialLight(Material material, vec3 color)
{
return material * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4);
return material.Base.rgb * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4);
}

View file

@ -35,10 +35,10 @@ vec3 lightContribution(int i, vec3 normal)
}
}
vec3 ProcessMaterial(vec3 material, vec3 color)
vec3 ProcessMaterialLight(Material material, vec3 color)
{
vec4 dynlight = uDynLightColor;
vec3 normal = ApplyNormalMap();
vec3 normal = material.Normal;
if (uLightIndex >= 0)
{
@ -59,7 +59,7 @@ vec3 ProcessMaterial(vec3 material, vec3 color)
}
}
vec3 frag = material * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
if (uLightIndex >= 0)
{

View file

@ -56,18 +56,19 @@ float quadraticDistanceAttenuation(vec4 lightpos)
return attenuation;
}
vec3 ProcessMaterial(vec3 albedo, vec3 ambientLight)
vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
{
vec3 worldpos = pixelpos.xyz;
albedo = pow(albedo, vec3(2.2)); // sRGB to linear
vec3 albedo = pow(material.Base.rgb, vec3(2.2)); // sRGB to linear
ambientLight = pow(ambientLight, vec3(2.2));
float metallic = texture(metallictexture, vTexCoord.st).r;
float roughness = texture(roughnesstexture, vTexCoord.st).r;
float ao = texture(aotexture, vTexCoord.st).r;
float metallic = material.Metallic;
float roughness = material.Roughness;
float ao = material.AO;
vec3 N = ApplyNormalMap();
vec3 N = material.Normal;
vec3 V = normalize(uCameraPos.xyz - worldpos);
vec3 F0 = mix(vec3(0.04), albedo, metallic);

View file

@ -34,12 +34,12 @@ vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA)
return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp));
}
vec3 ProcessMaterial(vec3 material, vec3 color)
vec3 ProcessMaterialLight(Material material, vec3 color)
{
vec4 dynlight = uDynLightColor;
vec4 specular = vec4(0.0, 0.0, 0.0, 1.0);
vec3 normal = ApplyNormalMap();
vec3 normal = material.Normal;
vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz);
if (uLightIndex >= 0)
@ -70,8 +70,7 @@ vec3 ProcessMaterial(vec3 material, vec3 color)
dynlight.rgb = clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
specular.rgb = clamp(desaturate(specular).rgb, 0.0, 1.4);
vec4 materialSpec = texture(speculartexture, vTexCoord.st);
vec3 frag = material * dynlight.rgb + materialSpec.rgb * specular.rgb;
vec3 frag = material.Base.rgb * dynlight.rgb + material.Specular * specular.rgb;
if (uLightIndex >= 0)
{