If you want a specific file/asset type to have a custom Thumbnail/Inspector Preview, you can simply create an AssetPreview. An AssetPreview initializes a SceneWorld and SceneCamera, rendering the Camera to the Preview output, so all you need to do is populate it and/or position the Camera to your liking.

The Thumbnails/Videos generated by an AssetPreview are also used when uploading Assets to sbox.game

Model Example

// AssetPreview for .char files (CharacterResource)
[AssetPreview( "char" )]
class PreviewCharacter : AssetPreview
{
    // The speed at which the model rotates. The length of a cycle in seconds is 1 / CycleSpeed
    public override float PreviewWidgetCycleSpeed => 0.2f;

    // This will evaluate each frame and pick the one with the least alpha and most luminance
	public override bool UsePixelEvaluatorForThumbs => true;

	public PreviewCharacter( Asset asset ) : base( asset )
    {
    }

    public override async Task InitializeAsset()
    {
        await Task.Yield();

        // Get the CharacterResource from the Asset
        var character = Asset.LoadResource<CharacterResource>();
        // Get the Model from the CharacterResource
        var model = character.Model;
        if ( model is null )
            return;

        // Create the SceneObject, and position the Camera to fit its bounds
        PrimarySceneObject = new SceneObject( World, model, Transform.Zero );
        SceneSize = model.RenderBounds.Size;
        SceneCenter = model.RenderBounds.Center;
    }
}

Texture Example

// AssetPreview for .item files (ItemResource)
[AssetPreview( "item" )]
class PreviewItem : AssetPreview
{
    SceneDynamicObject so;
    internal Texture texture;

    // We're just rendering a still image, so we don't need to render video thumbnails
    public override bool IsAnimatedPreview => false;

    public PreviewItem( Asset asset ) : base( asset )
    {
        // Get the ItemResouce from the Asset
        var item = asset.LoadResource<ItemResource>();
        // Get the texture path from the ItemResource and load the texture
        var texturePath = item.Icon;
        texture = Texture.Load( Sandbox.FileSystem.Mounted, texturePath );
    }

    public override Task InitializeAsset()
    {
        // Create a new object that we will use to render the texture
        so = new SceneDynamicObject( World );
        so.Transform = Transform.Zero;
        so.Material = Material.FromShader( "shaders/sprite.shader" );
        so.Flags.CastShadows = false;
        so.Attributes.Set( "BaseTexture", texture );

        // Set the primary scene object so the Camera keeps it in view
        PrimarySceneObject = so;

        return Task.CompletedTask;
    }

    public override void UpdateScene( float cycle, float timeStep )
    {
        Draw();
        Camera.Rotation = Rotation.Identity;
        FrameScene();
    }

    void Draw()
    {
        // Write to the SceneObject
        using ( so.Write( Graphics.PrimitiveType.Points, 1, 0 ) )
        {
            var v = new Vertex();

            v.TexCoord0 = new Vector4( 1, 1, 0, 0 );
            v.TexCoord1 = Color.White;
            v.Position = Vector3.Zero;
            v.Normal = Vector3.Zero;
            v.Tangent = Vector4.Zero;

            so.AddVertex( v );
        }

        SceneCenter = 0;
        SceneSize = 0.6f;
    }

}

How the Thumbnail and Preview appear






Created 10 Oct 2024
Updated 10 Oct 2024