Skip to content

Commit b2ca141

Browse files
committed
Preserve presentation common material assets
1 parent bdad30d commit b2ca141

5 files changed

Lines changed: 113 additions & 13 deletions

File tree

src/PlateauResoniteLink/Targets/Resonite/NonDemPreservedMaterialGrouping.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ internal static class NonDemPreservedMaterialGrouping
1414
public static NonDemPreservedMaterialGroupingKey CreateKey(ResoniteMaterialBinding material)
1515
{
1616
ResoniteMaterialBinding normalizedMaterial = NormalizeMaterial(material);
17-
if (normalizedMaterial.CommonMaterial is not null)
17+
if (normalizedMaterial.AssetBinding.IsSharedCommon
18+
&& normalizedMaterial.CommonMaterial is not null)
1819
{
1920
return new NonDemPreservedMaterialGroupingKey(
2021
normalizedMaterial.CommonMaterial,
@@ -27,14 +28,14 @@ public static NonDemPreservedMaterialGroupingKey CreateKey(ResoniteMaterialBindi
2728
default,
2829
default,
2930
default,
30-
default,
31+
normalizedMaterial.AssetScope,
3132
default,
3233
default,
3334
normalizedMaterial.TerrainMeshCode);
3435
}
3536

3637
return new NonDemPreservedMaterialGroupingKey(
37-
null,
38+
normalizedMaterial.CommonMaterial,
3839
normalizedMaterial.BaseColor,
3940
normalizedMaterial.MaterialType,
4041
normalizedMaterial.TexturePayload,
@@ -65,9 +66,13 @@ public bool Equals(NonDemPreservedMaterialGroupingKey x, NonDemPreservedMaterial
6566
return false;
6667
}
6768

68-
if (x.CommonMaterial is not null)
69+
bool xIsSharedCommon = IsSharedCommonMaterialKey(x);
70+
bool yIsSharedCommon = IsSharedCommonMaterialKey(y);
71+
if (xIsSharedCommon || yIsSharedCommon)
6972
{
70-
return ResoniteTexturePayloadReferenceComparer.Instance.Equals(x.TexturePayload, y.TexturePayload)
73+
return xIsSharedCommon
74+
&& yIsSharedCommon
75+
&& ResoniteTexturePayloadReferenceComparer.Instance.Equals(x.TexturePayload, y.TexturePayload)
7176
&& x.TextureSourceKind == y.TextureSourceKind
7277
&& EqualityComparer<TerrainTextureOverlay?>.Default.Equals(x.TerrainOverlay, y.TerrainOverlay)
7378
&& string.Equals(x.TerrainMeshCode, y.TerrainMeshCode, StringComparison.Ordinal);
@@ -92,7 +97,7 @@ public int GetHashCode(NonDemPreservedMaterialGroupingKey obj)
9297
{
9398
HashCode hash = new();
9499
hash.Add(obj.CommonMaterial);
95-
if (obj.CommonMaterial is not null)
100+
if (IsSharedCommonMaterialKey(obj))
96101
{
97102
AddTexturePayloadHash(ref hash, obj.TexturePayload);
98103
hash.Add(obj.TextureSourceKind);
@@ -117,6 +122,12 @@ public int GetHashCode(NonDemPreservedMaterialGroupingKey obj)
117122
return hash.ToHashCode();
118123
}
119124

125+
private static bool IsSharedCommonMaterialKey(NonDemPreservedMaterialGroupingKey key)
126+
{
127+
return key.CommonMaterial is not null
128+
&& key.AssetScope == ResoniteMaterialAssetScope.Common;
129+
}
130+
120131
private static void AddTexturePayloadHash(ref HashCode hash, ResoniteTexturePayload? texturePayload)
121132
{
122133
hash.Add(texturePayload is null

src/PlateauResoniteLink/Targets/Resonite/ResoniteDynamicMaterialUvNormalizer.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public static bool ShouldNormalizeTextureTransform(ResoniteMaterialBinding mater
1414

1515
return material.MaterialType == ResoniteMaterialType.Standard
1616
&& material.Projection == ResoniteMaterialProjection.Uv
17-
&& material.AssetScope != ResoniteMaterialAssetScope.Common
17+
&& (material.AssetScope != ResoniteMaterialAssetScope.Common
18+
|| material.TextureSourceKind == ResoniteTextureSourceKind.Dataset)
1819
&& HasNormalizableTextureTransform(material);
1920
}
2021

@@ -55,7 +56,7 @@ public static ResoniteConstructionCityObject Normalize(ResoniteConstructionCityO
5556
{
5657
Geometry = new ResoniteTriangleMeshGeometry(new ResoniteImportedMesh(normalizedVertices, normalizedSubmeshes)),
5758
Materials = cityObject.Materials
58-
.Select(NormalizeMaterialBinding)
59+
.Select(NormalizeMaterialBindingAfterMeshUvNormalization)
5960
.ToArray(),
6061
};
6162
}
@@ -79,6 +80,28 @@ public static ResoniteMaterialBinding NormalizeMaterialBinding(ResoniteMaterialB
7980
};
8081
}
8182

83+
if (material.AssetScope == ResoniteMaterialAssetScope.Common)
84+
{
85+
return material;
86+
}
87+
88+
return ShouldNormalizeTextureTransform(material)
89+
? material with
90+
{
91+
TextureScale = null,
92+
TextureOffset = null,
93+
}
94+
: material;
95+
}
96+
97+
private static ResoniteMaterialBinding NormalizeMaterialBindingAfterMeshUvNormalization(ResoniteMaterialBinding material)
98+
{
99+
ResoniteMaterialBinding normalizedMaterial = NormalizeMaterialBinding(material);
100+
if (normalizedMaterial != material)
101+
{
102+
return normalizedMaterial;
103+
}
104+
82105
return ShouldNormalizeTextureTransform(material)
83106
? material with
84107
{

src/PlateauResoniteLink/Targets/Resonite/ResoniteSceneMaterialPlanComposer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public async Task<PlannedSceneMaterialPlan> ComposeAsync(
5252
cityObject,
5353
cityObject.Materials[materialIndex]);
5454
reportMaterialStep($"Creating material {materialIndex + 1}/{cityObject.Materials.Count}.");
55-
if (material.CommonMaterial is { } commonMaterial)
55+
if (material.AssetBinding.IsSharedCommon
56+
&& material.CommonMaterial is { } commonMaterial)
5657
{
5758
materialPlanTasks[materialIndex] = PlanSharedCommonRendererMaterialAsync(
5859
state,

tests/PlateauResoniteLink.Tests/Targets/NonDemPreservedMaterialGroupingTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using PlateauResoniteLink.Application.Importing;
12
using PlateauResoniteLink.Targets.Resonite;
23

34
namespace PlateauResoniteLink.Tests.Targets;
@@ -57,6 +58,26 @@ public void CreateKeyKeepsDedicatedMaterialTintDistinct()
5758
Assert.False(NonDemPreservedMaterialGrouping.KeyComparer.Equals(red, blue));
5859
}
5960

61+
[Fact]
62+
public void CreateKeyKeepsPresentationCommonMaterialTintDistinct()
63+
{
64+
ResoniteMaterialBinding presentationCommonMaterial = CreateTexturelessMaterial() with
65+
{
66+
AssetBinding = ResoniteMaterialAssetBinding.PresentationCommon(CommonMaterialCatalog.Create().Generic.Uv),
67+
};
68+
69+
NonDemPreservedMaterialGroupingKey red = NonDemPreservedMaterialGrouping.CreateKey(presentationCommonMaterial with
70+
{
71+
BaseColor = new ResoniteColor(1.0, 0.0, 0.0, 1.0),
72+
});
73+
NonDemPreservedMaterialGroupingKey blue = NonDemPreservedMaterialGrouping.CreateKey(presentationCommonMaterial with
74+
{
75+
BaseColor = new ResoniteColor(0.0, 0.0, 1.0, 1.0),
76+
});
77+
78+
Assert.False(NonDemPreservedMaterialGrouping.KeyComparer.Equals(red, blue));
79+
}
80+
6081
private static ResoniteMaterialBinding CreateTexturelessMaterial()
6182
{
6283
return new ResoniteMaterialBinding(

tests/PlateauResoniteLink.Tests/Targets/ResoniteLiveSceneImportTargetAssetReuseTests.cs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,50 @@ await ResoniteLiveSceneImportTargetTestSupport.ExecuteSceneAsync(
157157
Assert.Contains(ImportedRgba32Textures(client), static texture => IsSolidColorTexture(texture, 0, 255, 0));
158158
}
159159

160+
[Fact]
161+
public async Task ExecuteAsyncKeepsPresentationCommonPayloadMaterialDedicated()
162+
{
163+
using TemporaryDirectory datasetDirectory = new();
164+
ImportedSceneMetadata metadata = CreateMetadata(datasetDirectory.Path);
165+
using SceneSinkRecordingClient client = new();
166+
ResoniteConstructionCityObject cityObject = CreatePayloadTriangleCityObject(
167+
"presentation-common-payload",
168+
ResoniteLiveSceneImportTargetTestSupport.CreateSolidColorPayload(255, 0, 0, "textures/presentation-common.png")) with
169+
{
170+
Materials =
171+
[
172+
CreatePayloadTriangleCityObject(
173+
"presentation-common-payload-source",
174+
ResoniteLiveSceneImportTargetTestSupport.CreateSolidColorPayload(255, 0, 0, "textures/presentation-common.png"))
175+
.Materials[0] with
176+
{
177+
BaseColor = new ResoniteColor(0.8, 0.7, 0.6, 1.0),
178+
AssetBinding = ResoniteMaterialAssetBinding.PresentationCommon(CommonMaterialCatalog.Create().Generic.Uv),
179+
},
180+
],
181+
};
182+
183+
await ResoniteLiveSceneImportTargetTestSupport.ExecuteSceneAsync(
184+
metadata,
185+
[cityObject],
186+
client,
187+
enableMeshBake: false);
188+
189+
string materialId = GetRendererMaterialReferenceTarget(client, "CityObject presentation-common-payload");
190+
AddComponent materialComponent = Assert.Single(
191+
client.AddedComponents,
192+
request => string.Equals(request.Data.ID, materialId, StringComparison.Ordinal));
193+
194+
Assert.DoesNotContain(
195+
"PLATEAU Shared Assets/Common Materials/",
196+
client.SlotPaths[materialComponent.ContainerSlotId],
197+
StringComparison.Ordinal);
198+
Field_colorX albedo = Assert.IsType<Field_colorX>(materialComponent.Data.Members["AlbedoColor"]);
199+
Assert.Equal(0.8f, albedo.Value.r, 6);
200+
Assert.Equal(0.7f, albedo.Value.g, 6);
201+
Assert.Equal(0.6f, albedo.Value.b, 6);
202+
}
203+
160204
[Fact]
161205
public async Task ExecuteAsyncReusesSharedCommonMaterialForPayloadAlbedoOverridesWithExplicitNoOpTransform()
162206
{
@@ -1542,7 +1586,7 @@ private static ResoniteConstructionCityObject CreatePayloadTriangleCityObject(
15421586
TextureScale: textureScale,
15431587
Family: null,
15441588
TextureOffset: textureOffset,
1545-
AssetBinding: ResoniteMaterialAssetBinding.PresentationCommon(CommonMaterialCatalog.Create().Generic.Uv)),
1589+
AssetBinding: ResoniteMaterialAssetBinding.SharedCommon(CommonMaterialCatalog.Create().Generic.Uv)),
15461590
],
15471591
SourceFileRelativePath: sourceFileRelativePath);
15481592
}
@@ -1572,7 +1616,7 @@ private static ResoniteConstructionCityObject CreateSameKeyPayloadOverrideCityOb
15721616
DepthOffset: null,
15731617
SubmeshIndices: [0],
15741618
Family: null,
1575-
AssetBinding: ResoniteMaterialAssetBinding.PresentationCommon(CommonMaterialCatalog.Create().Generic.Uv)),
1619+
AssetBinding: ResoniteMaterialAssetBinding.SharedCommon(CommonMaterialCatalog.Create().Generic.Uv)),
15761620
new ResoniteMaterialBinding(
15771621
BaseColor: new ResoniteColor(1.0, 1.0, 1.0, 1.0),
15781622
MaterialType: ResoniteMaterialType.Standard,
@@ -1582,7 +1626,7 @@ private static ResoniteConstructionCityObject CreateSameKeyPayloadOverrideCityOb
15821626
DepthOffset: null,
15831627
SubmeshIndices: [1],
15841628
Family: null,
1585-
AssetBinding: ResoniteMaterialAssetBinding.PresentationCommon(CommonMaterialCatalog.Create().Generic.Uv)),
1629+
AssetBinding: ResoniteMaterialAssetBinding.SharedCommon(CommonMaterialCatalog.Create().Generic.Uv)),
15861630
],
15871631
SourceFileRelativePath: sourceFileRelativePath);
15881632
}
@@ -1684,7 +1728,7 @@ private static ResoniteConstructionCityObject CreateMixedMaterialCityObject(
16841728
DepthOffset: null,
16851729
SubmeshIndices: [1],
16861730
Family: null,
1687-
AssetBinding: ResoniteMaterialAssetBinding.PresentationCommon(CommonMaterialCatalog.Create().Generic.Uv)),
1731+
AssetBinding: ResoniteMaterialAssetBinding.SharedCommon(CommonMaterialCatalog.Create().Generic.Uv)),
16881732
],
16891733
SourceFileRelativePath: sourceFileRelativePath);
16901734
}

0 commit comments

Comments
 (0)