Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to smooth out shadows #88

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions BSPConvert.Cmd/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class Options
[Option("nozones", Required = false, HelpText = "Ignore timer zone triggers.")]
public bool IgnoreZones { get; set; }

[Option("smoothshadows", Required = false, Default = 1, HelpText = "Increase color range for smoother shadows. Higher values may negatively impact brighter areas [1-16].")]
public int SmoothShadows { get; set; }

//[Option("oldbsp", Required = false, HelpText = "Use BSP version 20 (HL2 / CS:S).")]
//public bool OldBSP { get; set; }

Expand Down Expand Up @@ -56,6 +59,9 @@ static void RunCommand(Options options)
if (options.DisplacementPower < 2 || options.DisplacementPower > 4)
throw new ArgumentOutOfRangeException("Displacement power must be between 2 and 4.");

if (options.SmoothShadows < 1 || options.SmoothShadows > 16)
throw new ArgumentOutOfRangeException("Smooth shadow multiplier must be between 1 and 16.");

if (options.OutputDirectory == null)
options.OutputDirectory = Path.GetDirectoryName(options.InputFiles.First());

Expand All @@ -68,6 +74,7 @@ static void RunCommand(Options options)
DisplacementPower = options.DisplacementPower,
minDamageToConvertTrigger = options.MinDamageToConvertTrigger,
ignoreZones = options.IgnoreZones,
smoothShadows = options.SmoothShadows,
//oldBSP = options.OldBSP,
prefix = options.Prefix,
inputFile = inputEntry,
Expand Down
9 changes: 6 additions & 3 deletions BSPConvert.Lib/Source/BSPConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public int DisplacementPower
}
public int minDamageToConvertTrigger;
public bool ignoreZones;
public int smoothShadows;
public bool oldBSP;
public string prefix;
public string inputFile;
Expand Down Expand Up @@ -220,7 +221,7 @@ private void CreatePakFile()

private void ConvertMaterials()
{
var materialConverter = new MaterialConverter(contentManager.ContentDir, shaderDict);
var materialConverter = new MaterialConverter(contentManager.ContentDir, shaderDict, options.smoothShadows);
foreach (var texture in quakeBsp.Textures)
materialConverter.Convert(texture.Name);
}
Expand Down Expand Up @@ -1468,7 +1469,8 @@ private void ConvertInternalLightmaps()
var color = ColorUtil.ConvertQ3LightmapToColorRGBExp32(
qLightmapData[q3LightmapOffset + index * 3 + 0],
qLightmapData[q3LightmapOffset + index * 3 + 1],
qLightmapData[q3LightmapOffset + index * 3 + 2]);
qLightmapData[q3LightmapOffset + index * 3 + 2],
4 * options.smoothShadows); // internal lightmaps need * 4 brightness, darker than external lightmaps.

lmColors.Add(color);
}
Expand Down Expand Up @@ -1536,7 +1538,8 @@ private void ConvertExternalLightmaps()
var color = ColorUtil.ConvertQ3LightmapToColorRGBExp32(
lmData.data[index * 3 + 0],
lmData.data[index * 3 + 1],
lmData.data[index * 3 + 2]);
lmData.data[index * 3 + 2],
options.smoothShadows);

lmColors.Add(color);
}
Expand Down
42 changes: 35 additions & 7 deletions BSPConvert.Lib/Source/MaterialConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace BSPConvert.Lib
{
public class MaterialConverter
{
private int smoothShadows;
private string pk3Dir;
private Dictionary<string, Shader> shaderDict;
private Dictionary<string, string> pk3ImageDict;
Expand All @@ -23,8 +24,9 @@ public class MaterialConverter
"up"
};

public MaterialConverter(string pk3Dir, Dictionary<string, Shader> shaderDict)
public MaterialConverter(string pk3Dir, Dictionary<string, Shader> shaderDict, int smoothShadows)
{
this.smoothShadows = smoothShadows;
this.pk3Dir = pk3Dir;
this.shaderDict = shaderDict;
pk3ImageDict = GetImageLookupDictionary(pk3Dir);
Expand Down Expand Up @@ -201,7 +203,7 @@ private string GenerateUnlitVMT(Shader shader)
sb.AppendLine("UnlitGeneric");
sb.AppendLine("{");

AppendShaderParameters(sb, shader);
AppendShaderParameters(sb, shader, false);

sb.AppendLine("}");

Expand All @@ -214,14 +216,14 @@ private string GenerateLitVMT(Shader shader)
sb.AppendLine("LightmappedGeneric");
sb.AppendLine("{");

AppendShaderParameters(sb, shader);
AppendShaderParameters(sb, shader, true);

sb.AppendLine("}");

return sb.ToString();
}

private void AppendShaderParameters(StringBuilder sb, Shader shader)
private void AppendShaderParameters(StringBuilder sb, Shader shader, bool lightmapped)
{
var stages = shader.GetImageStages();
var textureStage = stages.FirstOrDefault(x => x.bundles[0].tcGen != TexCoordGen.TCGEN_ENVIRONMENT_MAPPED && x.bundles[0].tcGen != TexCoordGen.TCGEN_LIGHTMAP);
Expand All @@ -233,8 +235,19 @@ private void AppendShaderParameters(StringBuilder sb, Shader shader)
if (textureStage.rgbGen.HasFlag(ColorGen.CGEN_CONST))
{
var color = textureStage.constantColor;
var colorStr = $"{color[0]} {color[1]} {color[2]}";
sb.AppendLine("\t$color \"{" + colorStr + "}\"");

var r = ColorUtil.GammaToLinear(color[0]); // gamma correct rgb values
var g = ColorUtil.GammaToLinear(color[1]);
var b = ColorUtil.GammaToLinear(color[2]);

var colorStr = lightmapped ? $"{Math.Round(r / smoothShadows, 2)} {Math.Round(g / smoothShadows, 2)} {Math.Round(b / smoothShadows, 2)}" : $"{r} {g} {b}";

sb.AppendLine("\t$color2 \"{" + colorStr + "}\"");
}
else if (lightmapped && smoothShadows > 1)
{
var shadowCorrection = Math.Round(255f / smoothShadows);
sb.AppendLine($$""" $color2 "{ {{shadowCorrection}} {{shadowCorrection}} {{shadowCorrection}} }" """);
}

if (textureStage.alphaGen.HasFlag(AlphaGen.AGEN_CONST))
Expand Down Expand Up @@ -459,12 +472,27 @@ private void CreateDefaultVMT(string texture)

private string GenerateDefaultLitVMT(string texture)
{
return $$"""
if (smoothShadows > 1) // gamma correct textures to match modified lightmap brightness
{
var shadowCorrection = Math.Round(255f / smoothShadows);

return $$"""
LightmappedGeneric
{
$basetexture "{{texture}}"
$color2 "{ {{shadowCorrection}} {{shadowCorrection}} {{shadowCorrection}} }"
}
""";
}
else
{
return $$"""
LightmappedGeneric
{
$basetexture "{{texture}}"
}
""";
}
}
}
}
10 changes: 5 additions & 5 deletions BSPConvert.Lib/Source/Utilities/ColorUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
{
public static class ColorUtil
{
public static ColorRGBExp32 ConvertQ3LightmapToColorRGBExp32(byte r, byte g, byte b)
public static ColorRGBExp32 ConvertQ3LightmapToColorRGBExp32(byte r, byte g, byte b, float brightness)
{
var color = new ColorRGBExp32();

var rf = GammaToLinear(r) * 4f; // Multiply by 4 since Source expects lightmap values in 0-4 range
var gf = GammaToLinear(g) * 4f;
var bf = GammaToLinear(b) * 4f;
var rf = GammaToLinear(r) * brightness;
var gf = GammaToLinear(g) * brightness;
var bf = GammaToLinear(b) * brightness;

var max = Math.Max(rf, Math.Max(gf, bf));
var exp = CalcExponent(max);
Expand All @@ -24,7 +24,7 @@ public static ColorRGBExp32 ConvertQ3LightmapToColorRGBExp32(byte r, byte g, byt
return color;
}

private static float GammaToLinear(byte gamma)
public static float GammaToLinear(byte gamma)
{
return (float)(255.0 * Math.Pow(gamma / 255.0, 2.2));
}
Expand Down