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

# Conflicts:
#	src/gl/shaders/gl_shader.cpp
#	src/hwrenderer/textures/hw_material.cpp
#	src/r_data/gldefs.cpp
#	wadsrc/static/shaders/glsl/main.fp
This commit is contained in:
Magnus Norddahl 2018-07-15 23:01:40 +02:00 committed by drfrag666
parent 8f509bf784
commit 9c74c9629a
15 changed files with 219 additions and 108 deletions

View file

@ -321,13 +321,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.
@ -582,11 +600,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"},
{"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", ""},
{"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""},
{"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", "shaders/glsl/material_normal.fp", ""},
@ -599,9 +617,7 @@ static const FDefaultShader defaultshaders[]=
{nullptr,nullptr,nullptr,nullptr}
};
TArray<FString> usershaders;
TArray<FString> usermaterials;
TArray<FString> usershaderdefs;
TArray<UserShaderDesc> usershaders;
struct FEffectShader
{
@ -749,10 +765,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

@ -54,6 +54,8 @@ EXTERN_CVAR(Int, gl_lightmode)
EXTERN_CVAR(Bool, gl_precache)
EXTERN_CVAR(Bool, gl_texture_usehires)
extern TArray<UserShaderDesc> usershaders;
//===========================================================================
//
// The GL texture maintenance class
@ -443,12 +445,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
mShaderIndex = SHADER_Default;
tex = tx;
// TODO: apply custom shader object here
/* if (tx->CustomShaderDefinition)
{
}
else
*/
if (tx->bWarped)
{
mShaderIndex = tx->bWarped; // This picks SHADER_Warp1 or SHADER_Warp2
@ -464,55 +460,56 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
}
else
{
if (tx->gl_info.shaderindex >= FIRST_USER_SHADER)
if (tx->gl_info.Normal && tx->gl_info.Specular)
{
for (auto &texture : tx->CustomShaderTextures)
for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Specular })
{
if(texture == nullptr) continue;
ValidateSysTexture(texture, expanded);
mTextureLayers.Push({ texture, false });
}
mShaderIndex = tx->gl_info.shaderindex;
mShaderIndex = SHADER_Specular;
}
else
else if (tx->gl_info.Normal && tx->gl_info.Metallic && tx->gl_info.Roughness && tx->gl_info.AmbientOcclusion)
{
if (tx->gl_info.Normal && tx->gl_info.Specular)
for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Metallic, tx->gl_info.Roughness, tx->gl_info.AmbientOcclusion })
{
for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Specular })
{
ValidateSysTexture(texture, expanded);
mTextureLayers.Push({ texture, false });
}
mShaderIndex = SHADER_Specular;
}
else if (tx->gl_info.Normal && tx->gl_info.Metallic && tx->gl_info.Roughness && tx->gl_info.AmbientOcclusion)
{
for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Metallic, tx->gl_info.Roughness, tx->gl_info.AmbientOcclusion })
{
ValidateSysTexture(texture, expanded);
mTextureLayers.Push({ texture, false });
}
mShaderIndex = SHADER_PBR;
ValidateSysTexture(texture, expanded);
mTextureLayers.Push({ texture, false });
}
mShaderIndex = SHADER_PBR;
}
tx->CreateDefaultBrightmap();
if (tx->gl_info.Brightmap != NULL)
tx->CreateDefaultBrightmap();
if (tx->gl_info.Brightmap)
{
ValidateSysTexture(tx->gl_info.Brightmap, expanded);
mTextureLayers.Push({ tx->gl_info.Brightmap, false} );
if (mShaderIndex == SHADER_Specular)
mShaderIndex = SHADER_SpecularBrightmap;
else if (mShaderIndex == SHADER_PBR)
mShaderIndex = SHADER_PBRBrightmap;
else
mShaderIndex = SHADER_Brightmap;
}
if (tx->gl_info.shaderindex >= FIRST_USER_SHADER)
{
const UserShaderDesc &usershader = usershaders[tx->gl_info.shaderindex - FIRST_USER_SHADER];
if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
{
ValidateSysTexture(tx->gl_info.Brightmap, expanded);
FTextureLayer layer = {tx->gl_info.Brightmap, false};
mTextureLayers.Push(layer);
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, false });
}
mShaderIndex = tx->gl_info.shaderindex;
}
}
}
mBaseLayer = ValidateSysTexture(tx, expanded);
mWidth = tx->GetWidth();
mHeight = tx->GetHeight();
mLeftOffset = tx->LeftOffset;

View file

@ -51,14 +51,13 @@
#include "a_dynlight.h"
#include "textures/skyboxtexture.h"
#include "gl/shaders/gl_postprocessshader.h"
#include "gl/textures/gl_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;
@ -1385,10 +1384,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();
@ -1402,12 +1402,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"))
{
@ -1425,7 +1438,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++)
@ -1438,7 +1450,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;
}
@ -1466,7 +1479,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)
{
@ -1476,17 +1506,15 @@ class GLDefsParser
tex->gl_info.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->gl_info.shaderindex = i + FIRST_USER_SHADER;
return;
}
}
tex->gl_info.shaderindex = usershaders.Push(maplumpname) + FIRST_USER_SHADER;
usermaterials.Push(materiallumpname);
usershaderdefs.Push(texnameDefs);
tex->gl_info.shaderindex = usershaders.Push(desc) + FIRST_USER_SHADER;
}
}
}

View file

@ -69,6 +69,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 @@ out vec4 FragFog;
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);
//===========================================================================
//
@ -270,7 +284,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
@ -278,7 +292,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
@ -294,7 +308,7 @@ vec3 ApplyNormalMap()
return bumpedNormal;
}
#else
vec3 ApplyNormalMap()
vec3 ApplyNormalMap(vec2 texcoord)
{
return normalize(vWorldNormal.xyz);
}
@ -314,7 +328,7 @@ vec3 ApplyNormalMap()
//
//===========================================================================
vec4 getLightColor(vec4 material, float fogdist, float fogfactor)
vec4 getLightColor(Material material, float fogdist, float fogfactor)
{
vec4 color = vColor;
@ -353,12 +367,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);
}
//===========================================================================
@ -407,7 +421,8 @@ vec3 AmbientOcclusionColor()
void main()
{
vec4 frag = ProcessTexel();
Material material = ProcessMaterial();
vec4 frag = material.Base;
#ifndef NO_ALPHATEST
if (frag.a <= uAlphaThreshold) discard;
@ -438,7 +453,7 @@ void main()
fogfactor = exp2 (uFogDensity * fogdist);
}
frag = getLightColor(frag, fogdist, fogfactor);
frag = getLightColor(material, fogdist, fogfactor);
//
// colored fog
@ -493,4 +508,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

@ -32,10 +32,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)
{
@ -56,7 +56,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)
{