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.
// 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;
}
}
// 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;
}
}