wireframe improvements

This commit is contained in:
Ricardo Luís Vaz Silva 2025-01-12 22:39:36 -03:00 committed by Magnus Norddahl
commit 8d0ab22e05
11 changed files with 217 additions and 165 deletions

View file

@ -246,12 +246,34 @@ public:
mSurfaceUniforms.uVertexNormal = { norm.X, norm.Y, norm.Z, 0.f };
}
void SetWireframe(int mode)
{
mWireframe = mode;
mWireframeColor = toFVector4(PalEntry(0xffffffff));
}
void SetWireframe(int mode, FVector4 color)
{
mWireframe = mode;
mWireframeColor = color;
}
void SetWireframe(int mode, PalEntry color)
{
mWireframe = mode;
mWireframeColor = toFVector4(color);
}
void SetWireframeColor(FVector4 color)
{
mWireframeColor = color;
}
void SetWireframeColor(PalEntry color)
{
mWireframeColor = toFVector4(color);
}
void SetNormal(float x, float y, float z)
{
mSurfaceUniforms.uVertexNormal = { x, y, z, 0.f };
@ -566,7 +588,6 @@ public:
SetMaterial(tex, upscalemask, scaleflags, clampmode, translation.index(), overrideshader, cls);
}
void SetClipSplit(float bottom, float top)
{
mSurfaceUniforms.uClipSplit.X = bottom;

View file

@ -235,6 +235,7 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin
if (!key.AlphaTest) definesBlock << "#define NO_ALPHATEST\n";
if (key.GBufferPass) definesBlock << "#define GBUFFER_PASS\n";
if (key.AlphaTestOnly) definesBlock << "#define ALPHATEST_ONLY\n";
if (key.Simple3D) definesBlock << "#define SIMPLE\n#define SIMPLE3D\n";
switch(key.LightBlendMode)
{

View file

@ -104,7 +104,8 @@ public:
uint64_t LightAttenuationMode : 1; // LIGHT_ATTENUATION_LINEAR , LIGHT_ATTENUATION_INVERSE_SQUARE
uint64_t UseRaytracePrecise : 1; // USE_RAYTRACE_PRECISE
uint64_t ShadowmapFilter : 4; // SHADOWMAP_FILTER
uint64_t Unused : 32;
uint64_t Simple3D : 1; // SIMPLE3D
uint64_t Unused : 31;
};
uint64_t AsQWORD = 0;
};

View file

@ -283,6 +283,8 @@ void VkRenderState::ApplyRenderPass(int dt)
pipelineKey.ShaderKey.Detailmap = (uTextureMode & TEXF_Detailmap) != 0;
pipelineKey.ShaderKey.Glowmap = (uTextureMode & TEXF_Glowmap) != 0;
pipelineKey.ShaderKey.Simple3D = mWireframe; // simple notexture drawing for wireframe
pipelineKey.ShaderKey.DepthFadeThreshold = mSurfaceUniforms.uDepthFadeThreshold > 0.0f;
// The way GZDoom handles state is just plain insanity!
@ -1115,6 +1117,8 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip
if (!mTextureEnabled || mWireframe)
pipelineKey.ShaderKey.EffectState = SHADER_NoTexture;
pipelineKey.ShaderKey.Simple3D = mWireframe; // simple notexture drawing for wireframe
mPipelineKey = pipelineKey;
PushConstants pushConstants = {};

View file

@ -1240,7 +1240,7 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state)
state.SetFogballIndex(-1);
}
state.SetWireframe(0, {});
state.SetWireframe(0);
}

View file

@ -17,54 +17,58 @@ vec3 rgb2hsv(vec3 c)
void main()
{
#ifdef NO_CLIPDISTANCE_SUPPORT
if (ClipDistanceA.x < 0 || ClipDistanceA.y < 0 || ClipDistanceA.z < 0 || ClipDistanceA.w < 0 || ClipDistanceB.x < 0) discard;
#endif
#if defined(USE_LEVELMESH)
const int lightTileSize = 1 + 16 * 4;
uLightIndex = int(uint(gl_FragCoord.x) / 64 + uint(gl_FragCoord.y) / 64 * uLightTilesWidth) * lightTileSize;
#endif
#ifdef SIMPLE3D
Material material = CreateMaterial();
FragColor = vec4(material.Base.rgb, 1.0);
#else
#ifdef NO_CLIPDISTANCE_SUPPORT
if (ClipDistanceA.x < 0 || ClipDistanceA.y < 0 || ClipDistanceA.z < 0 || ClipDistanceA.w < 0 || ClipDistanceB.x < 0) discard;
#endif
#ifndef NO_ALPHATEST
if (material.Base.a <= uAlphaThreshold) discard;
#endif
#if defined(USE_LEVELMESH)
const int lightTileSize = 1 + 16 * 4;
uLightIndex = int(uint(gl_FragCoord.x) / 64 + uint(gl_FragCoord.y) / 64 * uLightTilesWidth) * lightTileSize;
#endif
#ifndef ALPHATEST_ONLY
Material material = CreateMaterial();
#ifdef USE_DEPTHFADETHRESHOLD
float behindFragmentDepth = texelFetch(LinearDepth, uViewOffset + ivec2(gl_FragCoord.xy), 0).r;
material.Base.a *= clamp((behindFragmentDepth - pixelpos.w) / uDepthFadeThreshold, 0.0, 1.0);
#endif
#ifndef NO_ALPHATEST
if (material.Base.a <= uAlphaThreshold) discard;
#endif
FragColor = ProcessLightMode(material);
#ifndef ALPHATEST_ONLY
#ifdef DITHERTRANS
int index = (int(pixelpos.x) % 8) * 8 + int(pixelpos.y) % 8;
const float DITHER_THRESHOLDS[64] =
float[64](
1.0 / 65.0, 33.0 / 65.0, 9.0 / 65.0, 41.0 / 65.0, 3.0 / 65.0, 35.0 / 65.0, 11.0 / 65.0, 43.0 / 65.0,
49.0 / 65.0, 17.0 / 65.0, 57.0 / 65.0, 25.0 / 65.0, 51.0 / 65.0, 19.0 / 65.0, 59.0 / 65.0, 27.0 / 65.0,
13.0 / 65.0, 45.0 / 65.0, 5.0 / 65.0, 37.0 / 65.0, 15.0 / 65.0, 47.0 / 65.0, 7.0 / 65.0, 39.0 / 65.0,
61.0 / 65.0, 29.0 / 65.0, 53.0 / 65.0, 21.0 / 65.0, 63.0 / 65.0, 31.0 / 65.0, 55.0 / 65.0, 23.0 / 65.0,
4.0 / 65.0, 36.0 / 65.0, 12.0 / 65.0, 44.0 / 65.0, 2.0 / 65.0, 34.0 / 65.0, 10.0 / 65.0, 42.0 / 65.0,
52.0 / 65.0, 20.0 / 65.0, 60.0 / 65.0, 28.0 / 65.0, 50.0 / 65.0, 18.0 / 65.0, 58.0 / 65.0, 26.0 / 65.0,
16.0 / 65.0, 48.0 / 65.0, 8.0 / 65.0, 40.0 / 65.0, 14.0 / 65.0, 46.0 / 65.0, 6.0 / 65.0, 38.0 / 65.0,
64.0 / 65.0, 32.0 / 65.0, 56.0 / 65.0, 24.0 / 65.0, 62.0 / 65.0, 30.0 / 65.0, 54.0 / 65.0, 22.0 /65.0
);
#ifdef USE_DEPTHFADETHRESHOLD
float behindFragmentDepth = texelFetch(LinearDepth, uViewOffset + ivec2(gl_FragCoord.xy), 0).r;
material.Base.a *= clamp((behindFragmentDepth - pixelpos.w) / uDepthFadeThreshold, 0.0, 1.0);
#endif
vec3 fragHSV = rgb2hsv(FragColor.rgb);
float brightness = clamp(1.5*fragHSV.z, 0.1, 1.0);
if (DITHER_THRESHOLDS[index] < brightness) discard;
else FragColor *= 0.5;
#endif
FragColor = ProcessLightMode(material);
#ifdef GBUFFER_PASS
FragFog = vec4(AmbientOcclusionColor(), 1.0);
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
#endif
#ifdef DITHERTRANS
int index = (int(pixelpos.x) % 8) * 8 + int(pixelpos.y) % 8;
const float DITHER_THRESHOLDS[64] =
float[64](
1.0 / 65.0, 33.0 / 65.0, 9.0 / 65.0, 41.0 / 65.0, 3.0 / 65.0, 35.0 / 65.0, 11.0 / 65.0, 43.0 / 65.0,
49.0 / 65.0, 17.0 / 65.0, 57.0 / 65.0, 25.0 / 65.0, 51.0 / 65.0, 19.0 / 65.0, 59.0 / 65.0, 27.0 / 65.0,
13.0 / 65.0, 45.0 / 65.0, 5.0 / 65.0, 37.0 / 65.0, 15.0 / 65.0, 47.0 / 65.0, 7.0 / 65.0, 39.0 / 65.0,
61.0 / 65.0, 29.0 / 65.0, 53.0 / 65.0, 21.0 / 65.0, 63.0 / 65.0, 31.0 / 65.0, 55.0 / 65.0, 23.0 / 65.0,
4.0 / 65.0, 36.0 / 65.0, 12.0 / 65.0, 44.0 / 65.0, 2.0 / 65.0, 34.0 / 65.0, 10.0 / 65.0, 42.0 / 65.0,
52.0 / 65.0, 20.0 / 65.0, 60.0 / 65.0, 28.0 / 65.0, 50.0 / 65.0, 18.0 / 65.0, 58.0 / 65.0, 26.0 / 65.0,
16.0 / 65.0, 48.0 / 65.0, 8.0 / 65.0, 40.0 / 65.0, 14.0 / 65.0, 46.0 / 65.0, 6.0 / 65.0, 38.0 / 65.0,
64.0 / 65.0, 32.0 / 65.0, 56.0 / 65.0, 24.0 / 65.0, 62.0 / 65.0, 30.0 / 65.0, 54.0 / 65.0, 22.0 /65.0
);
vec3 fragHSV = rgb2hsv(FragColor.rgb);
float brightness = clamp(1.5*fragHSV.z, 0.1, 1.0);
if (DITHER_THRESHOLDS[index] < brightness) discard;
else FragColor *= 0.5;
#endif
#ifdef GBUFFER_PASS
FragFog = vec4(AmbientOcclusionColor(), 1.0);
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
#endif
#endif
#endif
}

View file

@ -7,3 +7,9 @@
#include "shaders/scene/light_spot.glsl"
#endif
#ifdef SIMPLE3D
#include "shaders/scene/material.glsl"
#endif

View file

@ -1,97 +1,104 @@
vec3 lightContribution(int i, vec3 normal)
{
vec4 lightpos = lights[i];
vec4 lightcolor = lights[i+1];
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float radius = abs(lightpos.w);
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
if (radius < lightdistance)
return vec3(0.0); // Early out lights touching surface but not this fragment
vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz);
float dotprod = dot(normal, lightdir);
if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues.
float attenuation = distanceAttenuation(lightdistance, radius, lightspot2.w, lightspot1.w);
if (lightpos.w < 0.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); // Sign bit is the spotlight flag
if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag
#ifndef SIMPLE3D
vec3 lightContribution(int i, vec3 normal)
{
attenuation *= clamp(dotprod, 0.0, 1.0);
}
vec4 lightpos = lights[i];
vec4 lightcolor = lights[i+1];
vec4 lightspot1 = lights[i+2];
vec4 lightspot2 = lights[i+3];
float radius = abs(lightpos.w);
if (attenuation > 0.0) // Skip shadow map test if possible
{
attenuation *= shadowAttenuation(lightpos, lightcolor.a, lightspot2.z);
return lightcolor.rgb * attenuation;
}
else
{
return vec3(0.0);
}
}
float lightdistance = distance(lightpos.xyz, pixelpos.xyz);
if (radius < lightdistance)
return vec3(0.0); // Early out lights touching surface but not this fragment
vec3 ProcessMaterialLight(Material material, vec3 color)
{
vec4 dynlight = uDynLightColor;
vec3 normal = material.Normal;
vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz);
float dotprod = dot(normal, lightdir);
if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues.
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
if (lightRange.z > lightRange.x)
float attenuation = distanceAttenuation(lightdistance, radius, lightspot2.w, lightspot1.w);
if (lightpos.w < 0.0)
attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); // Sign bit is the spotlight flag
if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag
{
// modulated lights
for(int i=lightRange.x; i<lightRange.y; i+=4)
{
dynlight.rgb += lightContribution(i, normal);
}
// subtractive lights
for(int i=lightRange.y; i<lightRange.z; i+=4)
{
dynlight.rgb -= lightContribution(i, normal);
}
attenuation *= clamp(dotprod, 0.0, 1.0);
}
}
#ifdef LIGHT_BLEND_CLAMPED
vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
#elif defined(LIGHT_BLEND_COLORED_CLAMP)
vec3 frag = color + desaturate(dynlight).rgb;
frag = material.Base.rgb * ((frag / max(max(max(frag.r, frag.g), frag.b), 1.4) * 1.4));
#else // elif defined(LIGHT_BLEND_UNCLAMPED)
vec3 frag = material.Base.rgb * (color + desaturate(dynlight).rgb);
#endif
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
if (lightRange.w > lightRange.z)
if (attenuation > 0.0) // Skip shadow map test if possible
{
vec4 addlight = vec4(0.0,0.0,0.0,0.0);
// additive lights
for(int i=lightRange.z; i<lightRange.w; i+=4)
{
addlight.rgb += lightContribution(i, normal);
}
frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0);
attenuation *= shadowAttenuation(lightpos, lightcolor.a, lightspot2.z);
return lightcolor.rgb * attenuation;
}
else
{
return vec3(0.0);
}
}
return frag;
}
vec3 ProcessMaterialLight(Material material, vec3 color)
{
vec4 dynlight = uDynLightColor;
vec3 normal = material.Normal;
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
if (lightRange.z > lightRange.x)
{
// modulated lights
for(int i=lightRange.x; i<lightRange.y; i+=4)
{
dynlight.rgb += lightContribution(i, normal);
}
// subtractive lights
for(int i=lightRange.y; i<lightRange.z; i+=4)
{
dynlight.rgb -= lightContribution(i, normal);
}
}
}
#ifdef LIGHT_BLEND_CLAMPED
vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
#elif defined(LIGHT_BLEND_COLORED_CLAMP)
vec3 frag = color + desaturate(dynlight).rgb;
frag = material.Base.rgb * ((frag / max(max(max(frag.r, frag.g), frag.b), 1.4) * 1.4));
#else // elif defined(LIGHT_BLEND_UNCLAMPED)
vec3 frag = material.Base.rgb * (color + desaturate(dynlight).rgb);
#endif
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
if (lightRange.w > lightRange.z)
{
vec4 addlight = vec4(0.0,0.0,0.0,0.0);
// additive lights
for(int i=lightRange.z; i<lightRange.w; i+=4)
{
addlight.rgb += lightContribution(i, normal);
}
frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0);
}
}
return frag;
}
#else
vec3 ProcessMaterialLight(Material material, vec3 color)
{
return material.Base.rgb;
}
#endif

View file

@ -1,6 +1,8 @@
#include "shaders/scene/material_getTexel.glsl"
#include "shaders/scene/material_normalmap.glsl"
#ifndef SIMPLE3D
#include "shaders/scene/material_getTexel.glsl"
#include "shaders/scene/material_normalmap.glsl"
#endif
struct Material
{
@ -38,44 +40,46 @@ Material CreateMaterial()
return material;
}
void SetMaterialProps(inout Material material, vec2 texCoord)
{
#ifdef NPOT_EMULATION
if (uNpotEmulation.y != 0.0)
#ifndef SIMPLE3D
void SetMaterialProps(inout Material material, vec2 texCoord)
{
float period = floor(texCoord.t / uNpotEmulation.y);
texCoord.s += uNpotEmulation.x * floor(mod(texCoord.t, uNpotEmulation.y));
texCoord.t = period + mod(texCoord.t, uNpotEmulation.y);
#ifdef NPOT_EMULATION
if (uNpotEmulation.y != 0.0)
{
float period = floor(texCoord.t / uNpotEmulation.y);
texCoord.s += uNpotEmulation.x * floor(mod(texCoord.t, uNpotEmulation.y));
texCoord.t = period + mod(texCoord.t, uNpotEmulation.y);
}
#endif
material.Base = getTexel(texCoord.st);
material.Normal = ApplyNormalMap(texCoord.st);
// OpenGL doesn't care, but Vulkan pukes all over the place if these texture samplings are included in no-texture shaders, even though never called.
#ifndef NO_LAYERS
#if defined(TEXF_Brightmap)
material.Bright = desaturate(texture(brighttexture, texCoord.st));
#endif
#if defined(TEXF_Detailmap)
vec4 Detail = texture(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z;
material.Base.rgb *= Detail.rgb;
#endif
#if defined(TEXF_Glowmap)
material.Glow = desaturate(texture(glowtexture, texCoord.st));
#endif
#ifdef PBR
material.Metallic = texture(metallictexture, texCoord.st).r;
material.Roughness = texture(roughnesstexture, texCoord.st).r;
material.AO = texture(aotexture, texCoord.st).r;
#endif
#ifdef SPECULAR
material.Specular = texture(speculartexture, texCoord.st).rgb;
material.Glossiness = uSpecularMaterial.x;
material.SpecularLevel = uSpecularMaterial.y;
#endif
#endif
}
#endif
material.Base = getTexel(texCoord.st);
material.Normal = ApplyNormalMap(texCoord.st);
// OpenGL doesn't care, but Vulkan pukes all over the place if these texture samplings are included in no-texture shaders, even though never called.
#ifndef NO_LAYERS
#if defined(TEXF_Brightmap)
material.Bright = desaturate(texture(brighttexture, texCoord.st));
#endif
#if defined(TEXF_Detailmap)
vec4 Detail = texture(detailtexture, texCoord.st * uDetailParms.xy) * uDetailParms.z;
material.Base.rgb *= Detail.rgb;
#endif
#if defined(TEXF_Glowmap)
material.Glow = desaturate(texture(glowtexture, texCoord.st));
#endif
#ifdef PBR
material.Metallic = texture(metallictexture, texCoord.st).r;
material.Roughness = texture(roughnesstexture, texCoord.st).r;
material.AO = texture(aotexture, texCoord.st).r;
#endif
#ifdef SPECULAR
material.Specular = texture(speculartexture, texCoord.st).rgb;
material.Glossiness = uSpecularMaterial.x;
material.SpecularLevel = uSpecularMaterial.y;
#endif
#endif
}
#endif

View file

@ -1,5 +1,9 @@
void SetupMaterial(inout Material material)
{
material.Base = desaturate(uObjectColor);
#ifdef SIMPLE3D
material.Base = uObjectColor;
#else
material.Base = desaturate(uObjectColor);
#endif
}

View file

@ -36,7 +36,7 @@ void main()
vColor = aColor;
#endif
#ifndef SIMPLE
#if !defined(SIMPLE) || defined(SIMPLE3D)
vLightmap = vec3(aLightmap, aPosition.w);
pixelpos.xyz = worldcoord.xyz;
@ -69,7 +69,7 @@ void main()
vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0);
vEyeNormal = NormalViewMatrix * vec4(normalize(vWorldNormal.xyz), 1.0);
#endif
#ifdef SPHEREMAP
vec3 u = normalize(eyeCoordPos.xyz);
vec4 n = normalize(NormalViewMatrix * vec4(parmTexCoord.x, 0.0, parmTexCoord.y, 0.0));
@ -122,6 +122,6 @@ void main()
#endif
gl_PointSize = 1.0;
ModifyVertex();
ModifyVertex();
}