Skip to content

Commit

Permalink
Implement animations for skinned mesh preview (#134)
Browse files Browse the repository at this point in the history
* working animations

* animation load toggle
  • Loading branch information
Crauzer authored Mar 7, 2023
1 parent 6d1202b commit 3569f51
Show file tree
Hide file tree
Showing 11 changed files with 521 additions and 135 deletions.
13 changes: 12 additions & 1 deletion Obsidian/Data/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public bool SyncHashtables
Save();
}
}
private bool _syncHashtables;
private bool _syncHashtables = true;

public bool SyncBinHashtables
{
Expand All @@ -70,6 +70,17 @@ public bool SyncBinHashtables
}
private bool _syncBinHashtables;

public bool LoadSkinnedMeshAnimations
{
get => this._loadSkinnedMeshAnimations;
set
{
this._loadSkinnedMeshAnimations = value;
Save();
}
}
private bool _loadSkinnedMeshAnimations = false;

private const string CONFIG_FILE = "config.json";

public Config() { }
Expand Down
49 changes: 37 additions & 12 deletions Obsidian/Pages/ExplorerPage.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,20 +326,45 @@ private async Task PreviewSkinPackage(Stream stream)
// Make sure viewport is created
await SetCurrentPreviewType(WadFilePreviewType.Viewport);

await Three.CreateSkinnedMesh(
this.JsRuntime,
this.ActiveTab.GetViewportContainerId(),
skinnedMesh,
skeleton,
await SkinnedMeshUtils.CreateTextureImages(
if (this.Config.LoadSkinnedMeshAnimations)
{
await Three.RenderSkinnedMeshFromGltf(
this.JsRuntime,
this.ActiveTab.GetViewportContainerId(),
skinnedMesh,
meshData,
skinPackage,
this.ActiveTab.Wad,
metaEnvironment
)
);
skeleton,
SkinnedMeshUtils.CollectMaterialTextures(
skinnedMesh,
meshData,
skinPackage,
this.ActiveTab.Wad,
metaEnvironment
),
SkinnedMeshUtils.LoadAnimationAssets(
skinData,
skinPackage,
this.ActiveTab.Wad,
metaEnvironment
)
);
}
else
{
await Three.CreateSkinnedMesh(
this.JsRuntime,
this.ActiveTab.GetViewportContainerId(),
skinnedMesh,
skeleton,
await SkinnedMeshUtils.CreateTextureImages(
this.JsRuntime,
skinnedMesh,
meshData,
skinPackage,
this.ActiveTab.Wad,
metaEnvironment
)
);
}
}

private async Task PreviewImage(Image<Rgba32> image)
Expand Down
7 changes: 7 additions & 0 deletions Obsidian/Shared/SettingsDialog.razor
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@
Color="Color.Primary" />
</MudTooltip>
</MudItem>
<MudItem xs="12">
<MudTooltip Arrow Text="Whether to load animations for skinned meshes from skin packages"
Color="Color.Dark">
<MudCheckBox Label="Load Skinned Mesh Animations" @bind-Checked="Config.LoadSkinnedMeshAnimations"
Color="Color.Primary" />
</MudTooltip>
</MudItem>
</MudGrid>
</MudContainer>
</DialogContent>
Expand Down
1 change: 1 addition & 0 deletions Obsidian/Shared/WadFileViewport.razor
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
position: absolute;
top: 0px;
right: 0px;
max-height: calc(100vh - 123px);
}
.wad-file-render-canvas-content {
Expand Down
108 changes: 1 addition & 107 deletions Obsidian/Shared/WadFileViewport.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private ModelRoot CreateGltfFromSkinPackage(Stream stream)

return skinnedMesh.ToGltf(
skeleton,
CollectMaterialTextures(
SkinnedMeshUtils.CollectMaterialTextures(
skinnedMesh,
meshData,
skinPackage,
Expand All @@ -123,112 +123,6 @@ private ModelRoot CreateGltfFromSkinPackage(Stream stream)
);
}

private List<(string, Stream)> CollectMaterialTextures(
SkinnedMesh skinnedMesh,
SkinMeshDataProperties meshData,
BinTree skinPackage,
WadFile wad,
MetaEnvironment metaEnvironment
)
{
string defaultTexture = ResolveMaterialTexturePath(
meshData.Material,
meshData.Texture,
skinPackage,
metaEnvironment
);
List<(string, Stream)> textures = new();

foreach (SkinnedMeshRange primitive in skinnedMesh.Ranges)
{
SkinMeshDataProperties_MaterialOverride materialOverride =
meshData.MaterialOverride.FirstOrDefault(
x => x.Value.Submesh == primitive.Material
);

textures.Add(
(materialOverride is null) switch
{
true => (primitive.Material, CreateTextureImage(defaultTexture, wad)),
false
=> (
primitive.Material,
CreateMaterialTextureImage(
materialOverride.Material,
materialOverride.Texture,
skinPackage,
wad,
metaEnvironment
)
)
}
);
}

return textures;
}

private static Stream CreateMaterialTextureImage(
MetaObjectLink materialLink,
string fallbackTexturePath,
BinTree skinPackage,
WadFile wad,
MetaEnvironment metaEnvironment
)
{
BinTreeObject materialDefObject = skinPackage.Objects.GetValueOrDefault(materialLink);
if (materialDefObject is null)
return CreateTextureImage(fallbackTexturePath, wad);

var materialDef = MetaSerializer.Deserialize<StaticMaterialDef>(
metaEnvironment,
materialDefObject
);
StaticMaterialShaderSamplerDef diffuseSamplerDef = materialDef.SamplerValues.FirstOrDefault(
x => DIFFUSE_SAMPLERS.Contains(x.Value.SamplerName)
);
diffuseSamplerDef ??= new();

return string.IsNullOrEmpty(diffuseSamplerDef.TextureName) switch
{
true => CreateTextureImage(fallbackTexturePath, wad),
false => CreateTextureImage(diffuseSamplerDef.TextureName, wad),
};
}

private static string ResolveMaterialTexturePath(
MetaObjectLink materialLink,
string fallbackTexturePath,
BinTree skinPackage,
MetaEnvironment metaEnvironment
)
{
BinTreeObject materialDefObject = skinPackage.Objects.GetValueOrDefault(materialLink);
if (materialDefObject is null)
return fallbackTexturePath;

var materialDef = MetaSerializer.Deserialize<StaticMaterialDef>(
metaEnvironment,
materialDefObject
);
StaticMaterialShaderSamplerDef diffuseSamplerDef = materialDef.SamplerValues.FirstOrDefault(
x => DIFFUSE_SAMPLERS.Contains(x.Value.SamplerName)
);
diffuseSamplerDef ??= new();

return string.IsNullOrEmpty(diffuseSamplerDef.TextureName) switch
{
true => fallbackTexturePath,
false => diffuseSamplerDef.TextureName,
};
}

private static Stream CreateTextureImage(string path, WadFile wad)
{
using Stream fallbackTextureStream = wad.LoadChunkDecompressed(path).AsStream();
return ImageUtils.ConvertTextureToPng(Texture.Load(fallbackTextureStream));
}

private void ToggleIsSavingAsGltf(bool value)
{
this._isSavingAsGltf = value;
Expand Down
Loading

0 comments on commit 3569f51

Please sign in to comment.