Writer for .vmat material files used by the editor. It builds a string representing a VMAT with supplied texture paths and PBR parameters, and can write it to disk with UTF-8 no BOM.
using System.IO;
using System.Text;
namespace GmodAssetImporter;
public sealed class VmatWriteRequest
{
public string ColorTextureAssetPath; // materials/.../name_color.png
public string NormalTextureAssetPath;
public string SelfIllumTextureAssetPath;
public bool Translucent;
public bool AlphaTest;
public float Metalness = 0f;
public float Roughness = 0.5f;
}
public static class VmatWriter
{
static readonly Encoding Utf8NoBom = new UTF8Encoding( encoderShouldEmitUTF8Identifier: false );
public static string Build( VmatWriteRequest req )
{
var color = Escape( req.ColorTextureAssetPath ?? "materials/default/default_color.tga" );
var normal = Escape( req.NormalTextureAssetPath ?? "materials/default/default_normal.tga" );
var roughDefault = "materials/default/default_rough.tga";
var aoDefault = "materials/default/default_ao.tga";
var sb = new StringBuilder();
sb.AppendLine( "// THIS FILE IS AUTO-GENERATED" );
sb.AppendLine();
sb.AppendLine( "Layer0" );
sb.AppendLine( "{" );
sb.AppendLine( "\tshader \"shaders/complex.shader\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- PBR ----" );
sb.AppendLine( "\tF_SPECULAR 1" );
if ( req.Translucent )
sb.AppendLine( "\tF_TRANSLUCENT 1" );
if ( req.AlphaTest )
sb.AppendLine( "\tF_ALPHA_TEST 1" );
sb.AppendLine();
sb.AppendLine( "\t//---- Ambient Occlusion ----" );
sb.AppendLine( "\tg_flAmbientOcclusionDirectDiffuse \"0.000\"" );
sb.AppendLine( "\tg_flAmbientOcclusionDirectSpecular \"0.000\"" );
sb.AppendLine( $"\tTextureAmbientOcclusion \"{aoDefault}\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Color ----" );
sb.AppendLine( "\tg_flModelTintAmount \"1.000\"" );
sb.AppendLine( "\tg_vColorTint \"[1.000000 1.000000 1.000000 0.000000]\"" );
sb.AppendLine( $"\tTextureColor \"{color}\"" );
sb.AppendLine( $"\tTextureNormal \"{normal}\"" );
sb.AppendLine( $"\tTextureRoughness \"{roughDefault}\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Fade ----" );
sb.AppendLine( "\tg_flFadeExponent \"1.000\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Fog ----" );
sb.AppendLine( "\tg_bFogEnabled \"1\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Metalness ----" );
sb.AppendLine( $"\tg_flMetalness \"{req.Metalness:0.000}\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Roughness ----" );
sb.AppendLine( $"\tg_flRoughnessScaleFactor \"{req.Roughness:0.000}\"" );
if ( !string.IsNullOrWhiteSpace( req.SelfIllumTextureAssetPath ) )
{
sb.AppendLine();
sb.AppendLine( "\t//---- Self Illum ----" );
sb.AppendLine( "\tF_SELF_ILLUM 1" );
sb.AppendLine( $"\tTextureSelfIllumMask \"{Escape( req.SelfIllumTextureAssetPath )}\"" );
}
sb.AppendLine();
sb.AppendLine( "\t//---- Texture Coordinates ----" );
sb.AppendLine( "\tg_vTexCoordOffset \"[0.000 0.000]\"" );
sb.AppendLine( "\tg_vTexCoordScale \"[1.000 1.000]\"" );
sb.AppendLine( "\tg_vTexCoordScrollSpeed \"[0.000 0.000]\"" );
sb.AppendLine( "}" );
return sb.ToString();
}
public static void Write( string absolutePath, VmatWriteRequest req )
{
Directory.CreateDirectory( Path.GetDirectoryName( absolutePath )! );
File.WriteAllText( absolutePath, Build( req ), Utf8NoBom );
}
static string Escape( string path ) => PathResolve.NormalizeSlashes( path ?? "" );
}