Editor/PbrMaterialExporter.cs
using System;
using System.IO;
using System.Text;
using Editor;
public static class PbrMaterialExporter
{
public static PbrMaterialExportResult Export( string vmatPath, PbrExportedMapPaths mapPaths, bool overwriteExisting )
{
var result = new PbrMaterialExportResult();
try
{
if ( mapPaths == null || string.IsNullOrWhiteSpace( mapPaths.AlbedoPath ) )
{
result.Error = "Albedo map was not exported, so the material could not be created.";
return result;
}
if ( File.Exists( vmatPath ) && !overwriteExisting )
{
result.Error = "Material file already exists.";
return result;
}
var outputFolder = Path.GetDirectoryName( vmatPath );
if ( !string.IsNullOrWhiteSpace( outputFolder ) )
Directory.CreateDirectory( outputFolder );
var content = GenerateVmatContent( mapPaths, warning => AddWarning( result, warning ) );
File.WriteAllText( vmatPath, content );
try
{
var asset = AssetSystem.RegisterFile( vmatPath );
if ( asset == null )
AddWarning( result, "The .vmat was written, but S&box did not return a registered material asset." );
}
catch ( Exception ex )
{
AddWarning( result, $"The .vmat was written, but S&box asset registration skipped it: {ex.Message}" );
}
result.Success = true;
result.VmatPath = vmatPath;
}
catch ( Exception ex )
{
result.Error = ex.Message;
}
return result;
}
private static string GenerateVmatContent( PbrExportedMapPaths mapPaths, Action<string> addWarning )
{
var albedo = GetReferencePathOrDefault( mapPaths.AlbedoPath, "materials/default/default_color.tga", addWarning );
var normal = GetReferencePathOrDefault( mapPaths.NormalPath, "materials/default/default_normal.tga", addWarning );
var roughness = GetReferencePathOrDefault( mapPaths.RoughnessPath, "materials/default/default_rough.tga", addWarning );
var ao = GetReferencePathOrDefault( mapPaths.AoPath, "materials/default/default_ao.tga", addWarning );
var metallic = GetReferencePathOrDefault( mapPaths.MetallicPath, null, addWarning );
var sb = new StringBuilder();
sb.AppendLine( "// THIS FILE IS AUTO-GENERATED" );
sb.AppendLine( "// Generated by Seam-Less PBR Map Generator" );
sb.AppendLine();
sb.AppendLine( "Layer0" );
sb.AppendLine( "{" );
sb.AppendLine( "\tshader \"shaders/complex.shader\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- PBR ----" );
sb.AppendLine( "\tF_SPECULAR 1" );
sb.AppendLine();
sb.AppendLine( "\t//---- Ambient Occlusion ----" );
sb.AppendLine( "\tg_flAmbientOcclusionDirectDiffuse \"0.000\"" );
sb.AppendLine( "\tg_flAmbientOcclusionDirectSpecular \"0.000\"" );
sb.AppendLine( $"\tTextureAmbientOcclusion \"{ao}\"" );
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 \"{albedo}\"" );
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 ----" );
if ( !string.IsNullOrWhiteSpace( metallic ) )
sb.AppendLine( $"\tTextureMetalness \"{metallic}\"" );
else
sb.AppendLine( "\tg_flMetalness \"0.000\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Normal ----" );
sb.AppendLine( $"\tTextureNormal \"{normal}\"" );
sb.AppendLine();
sb.AppendLine( "\t//---- Roughness ----" );
sb.AppendLine( "\tg_flRoughnessScaleFactor \"1.000\"" );
sb.AppendLine( $"\tTextureRoughness \"{roughness}\"" );
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();
}
private static string GetReferencePathOrDefault( string texturePath, string fallback, Action<string> addWarning )
{
if ( string.IsNullOrWhiteSpace( texturePath ) || !File.Exists( texturePath ) )
return fallback;
return SeamlessSuiteImageUtility.GetTextureReferencePath( texturePath, addWarning ).Replace( "\"", "" );
}
private static void AddWarning( PbrMaterialExportResult result, string warning )
{
if ( string.IsNullOrWhiteSpace( warning ) )
return;
if ( string.IsNullOrWhiteSpace( result.Warning ) )
{
result.Warning = warning;
return;
}
result.Warning += $" {warning}";
}
}
public sealed class PbrExportedMapPaths
{
public string AlbedoPath { get; set; }
public string HeightPath { get; set; }
public string NormalPath { get; set; }
public string RoughnessPath { get; set; }
public string AoPath { get; set; }
public string MetallicPath { get; set; }
public string OrmPath { get; set; }
}
public sealed class PbrMaterialExportResult
{
public bool Success { get; set; }
public string VmatPath { get; set; }
public string Warning { get; set; }
public string Error { get; set; }
}