Skip to content

Textures & Serialization

Texture2D stores the source path and dimensions for an image. It does not load full pixel data into the core mesh library.

var texture = Texture2D.LoadFromFile("character.png");
Console.WriteLine(texture.Path);
Console.WriteLine(texture.Name);
Console.WriteLine(texture.Width);
Console.WriteLine(texture.Height);

LoadFromFile() opens the file, reads its dimensions, and returns a Texture2D.

The dimension reader supports these formats without third-party dependencies:

Format Notes
PNG Reads dimensions from the PNG header.
JPEG Scans JPEG markers until it finds a start-of-frame marker.
BMP Reads width and height from the BMP header and normalizes negative height.
GIF Reads logical screen width and height.

Unsupported formats throw NotSupportedException. File read problems surface from File.OpenRead() or the underlying stream.

Use pixel coordinates when editing meshes and UVs when passing data to a renderer.

var pixel = new Vector2(128, 64);
var uv = texture.PixelToUV(pixel);
var backToPixel = texture.UVToPixel(uv);

PixelToUV() returns Vector2.Zero when width or height is zero.

Mesh2D.GenerateUVsFromPositions() uses the bound texture:

mesh.SetTexture(texture);
mesh.GenerateUVsFromPositions(flipY: false);

Pass flipY: true when your graphics API or texture loader treats UV Y as inverted.

Mesh2DSerializer.ToJson() exports:

  • Version
  • TexturePath
  • vertex position and UV values
  • face indices
var json = Mesh2DSerializer.ToJson(mesh);
var compactJson = Mesh2DSerializer.ToJson(mesh, new Mesh2DSerializationOptions
{
WriteIndented = false
});

The default JSON is indented and uses System.Text.Json.

Use file helpers when a mesh document lives beside its texture assets:

Mesh2DSerializer.SaveToFile(mesh, "meshes/character.mesh.json");
var loaded = Mesh2DSerializer.LoadFromFile("meshes/character.mesh.json");

LoadFromFile() uses the mesh file directory as the default TextureBaseDirectory when no base directory is provided.

var loaded = Mesh2DSerializer.FromJson(json);

Import recreates vertices first, then faces, then tries to load TexturePath if it exists. Older serialized files without Version still load because missing JSON members keep their default values.

Texture restore intentionally ignores common texture-path failures by default:

  • IOException
  • NotSupportedException
  • ArgumentException
  • UnauthorizedAccessException

That means a mesh can still load even if the original texture path is missing, unreadable, invalid, or uses an unsupported format. In that case, loaded.Texture remains null.

Mesh2DSerializationOptions controls JSON formatting and texture restore behavior.

Option Purpose
WriteIndented Writes readable formatted JSON. Defaults to true.
LoadTexture Attempts to restore TexturePath during import. Defaults to true.
ThrowOnTextureLoadFailure Re-throws texture load failures instead of ignoring them.
TextureBaseDirectory Resolves relative texture paths from a known directory.
TextureLoader Replaces Texture2D.LoadFromFile() with an app-provided loader.
var loaded = Mesh2DSerializer.LoadFromFile("meshes/character.mesh.json", new Mesh2DSerializationOptions
{
TextureBaseDirectory = "assets",
ThrowOnTextureLoadFailure = true,
TextureLoader = path => Texture2D.LoadFromFile(path)
});

Set LoadTexture = false when the app owns texture lookup separately from mesh loading.

  • Keep texture paths stable if serialized meshes need to reopen their texture later.
  • Use ThrowOnTextureLoadFailure = true in import tools when missing textures should block the import.
  • Validate imported meshes with mesh.Validate() before accepting untrusted JSON.
  • Regenerate UVs after changing vertex positions when UVs should continue matching texture pixel positions.