Skip to content

Commit

Permalink
Merge branch 'main' into add_multiple_mesh_support
Browse files Browse the repository at this point in the history
  • Loading branch information
bertt authored Oct 23, 2024
2 parents a0cb718 + f32bf57 commit 1cf5e40
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 32 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,14 @@ Only the i3m files should be copied to a production server.
When parameter 'use_external_model' is set to true, only the model name will be stored in the i3dm payload.
In the i3dm header the value 'gltfFormat' is set to 0. In this case, the model should be a valid absolute or relative url to
the binary glTF. The client is responsible for retrieving the binary glTF's. Both the i3dm's and binary glTF's should be copied to a production server.
Option 'use_external_model' is only available when '--use_gpu_instancing' is false.

## Composites

Starting release 2.0, for every tile there will be a composiste tile (cmpt) - even if there is only 1 model available in the tile.
Specs see https://docs.opengeospatial.org/cs/18-053r2/18-053r2.html#249 . The composite tile contains a collection of instanced 3d tiles (i3dm), for each model there is 1 i3dm.
Specs see https://docs.opengeospatial.org/cs/18-053r2/18-053r2.html#249 .
The composite tile contains a collection of instanced 3d tiles (i3dm), for each model there is 1 i3dm.
When option --use_i3dm is set to true, only I3dm's are created. When there are multiple models in a tile only the first one is used.

## Implicit tiling

Expand Down Expand Up @@ -283,7 +286,11 @@ Warning: When the input glTF model has transformations, the model will be transf
cases it's better to remove the transformations from the input model. For example tool 'gltf-tansform' - function clearNodeTransform (https://gltf-transform.dev/modules/functions/functions/clearNodeTransform) can be
used to clear local transformations.

- Known issue: Getting attributes in Cesium does not work when there are multiple input models
Known issues GPU Instancing:

- https://github.com/Geodan/i3dm.export/issues/81: Trees rotation/ z placement wrong

- Getting attributes in Cesium does not work when there are multiple input models
https://community.cesium.com/t/upgrade-3d-tileset-with-composite-cmpt-tile-to-1-1-attribute-data-missing/33177/2

## Developing
Expand All @@ -306,6 +313,8 @@ Press F5 to start debugging.

## History

2024-10-15: release 2.9.0: add tileset version option

2024-08-01: release 2.8.3: fix release

2024-08-01: release 2.8.2: fix for I3dm using rtc_center for high precision positions
Expand Down
43 changes: 24 additions & 19 deletions src/GPUTileHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,30 @@ public static byte[] GetGPUTile(List<Instance> instances, bool UseScaleNonUnifor
settings.GpuMeshInstancingMinCount = 0;
var model = sceneBuilder.ToGltf2(settings);

var schema = AddMetadataSchema(model);
if (instances.Any(s => s.Tags != null))
{

var distinctModels = instances.Select(s => s.Model).Distinct();
var schema = AddMetadataSchema(model);

var i = 0;
var distinctModels = instances.Select(s => s.Model).Distinct();

foreach (var distinctModel in distinctModels)
{
var modelInstances = instances.Where(s => s.Model.Equals(distinctModel)).ToList();
var featureIdBuilder = GetFeatureIdBuilder(schema, modelInstances);
var node = model.LogicalNodes[i];
node.AddInstanceFeatureIds(featureIdBuilder);
i++;

var i = 0;

foreach (var distinctModel in distinctModels)
{
var modelInstances = instances.Where(s => s.Model.Equals(distinctModel)).ToList();
var featureIdBuilder = GetFeatureIdBuilder(schema, modelInstances);
var node = model.LogicalNodes[i];
node.AddInstanceFeatureIds(featureIdBuilder);
i++;
}
}

foreach (var node in model.LogicalNodes)
{
node.LocalTransform *= Matrix4x4.CreateTranslation(translation);
var tra = new Vector3((float)translation.X, (float)translation.Y, (float)translation.Z);
node.LocalTransform *= Matrix4x4.CreateTranslation(tra);
}

var bytes = model.WriteGLB().Array;
Expand All @@ -69,7 +75,7 @@ private static StructuralMetadataClass AddMetadataSchema(ModelRoot gltf)
return schemaClass;
}

private static SceneBuilder AddModels(IEnumerable<Instance> instances, Vector3 translation, bool UseScaleNonUniform)
private static SceneBuilder AddModels(IEnumerable<Instance> instances, Point translation, bool UseScaleNonUniform)
{
var sceneBuilder = new SceneBuilder();

Expand All @@ -84,8 +90,7 @@ private static SceneBuilder AddModels(IEnumerable<Instance> instances, Vector3 t
return sceneBuilder;
}


private static void AddModelInstancesToScene(SceneBuilder sceneBuilder, IEnumerable<Instance> instances, bool UseScaleNonUniform, Vector3 translation, string model)
private static void AddModelInstancesToScene(SceneBuilder sceneBuilder, IEnumerable<Instance> instances, bool UseScaleNonUniform, Point translation, string model)
{
var modelInstances = instances.Where(s => s.Model.Equals(model)).ToList();
var modelRoot = ModelRoot.Load(model);
Expand All @@ -110,7 +115,7 @@ private static void AddModelInstancesToScene(SceneBuilder sceneBuilder, IEnumera
}
}

private static SceneBuilder GetSceneBuilder(IMeshBuilder<MaterialBuilder> meshBuilder, Instance instance, bool UseScaleNonUniform, Vector3 translation, int pointId)
private static SceneBuilder GetSceneBuilder(IMeshBuilder<MaterialBuilder> meshBuilder, Instance instance, bool UseScaleNonUniform, Point translation, int pointId)
{
var transformation = GetInstanceTransform(instance, UseScaleNonUniform, translation);
var json = "{\"_FEATURE_ID_0\":" + pointId + "}";
Expand All @@ -119,7 +124,7 @@ private static SceneBuilder GetSceneBuilder(IMeshBuilder<MaterialBuilder> meshBu
return sceneBuilder;
}

private static AffineTransform GetInstanceTransform(Instance instance, bool UseScaleNonUniform, Vector3 translation)
private static AffineTransform GetInstanceTransform(Instance instance, bool UseScaleNonUniform, Point translation)
{
var point = (Point)instance.Position;

Expand All @@ -133,7 +138,7 @@ private static AffineTransform GetInstanceTransform(Instance instance, bool UseS
var instanceQuaternion = Quaternion.CreateFromYawPitchRoll((float)instance.Yaw, (float)instance.Pitch, (float)instance.Roll);
var res = Quaternion.CreateFromRotationMatrix(m4);

var position2 = position - translation;
var position2 = new Vector3((float)(position.X - translation.X), (float)(position.Y - translation.Y), (float)(position.Z - translation.Z));

var scale = UseScaleNonUniform ?
new Vector3((float)instance.ScaleNonUniform[0], (float)instance.ScaleNonUniform[1], (float)instance.ScaleNonUniform[2]) :
Expand Down Expand Up @@ -206,8 +211,8 @@ private static Matrix4x4 GetTransformationMatrix((Vector3 East, Vector3 North, V
m4.M33 = forward.Z;
return m4;
}
private static Vector3 ToYUp(Point position)
private static Point ToYUp(Point position)
{
return new Vector3((float)position.X, (float)position.Z, (float)position.Y * -1);
return new Point((double)position.X, (double)position.Z, (double)position.Y * -1);
}
}
4 changes: 4 additions & 0 deletions src/Instance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ namespace i3dm.export;

public class Instance
{
public Instance()
{
Scale = 1;
}
public Geometry Position { get; set; }

public double Scale { get; set; }
Expand Down
6 changes: 3 additions & 3 deletions src/i3dm.export.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<TargetFramework>net8.0</TargetFramework>
<ToolCommandName>i3dm.export</ToolCommandName>
<PackageOutputPath>./nupkg</PackageOutputPath>
<Version>2.8.3</Version>
<AssemblyVersion>2.8.3</AssemblyVersion>
<FileVersion>2.8.3</FileVersion>
<Version>2.9.0</Version>
<AssemblyVersion>2.9.0</AssemblyVersion>
<FileVersion>2.9.0</FileVersion>
<PackageProjectUrl>https://github.com/geodan/i3dm.export</PackageProjectUrl>
<RepositoryUrl>https://github.com/geodan/i3dm.export</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand Down
44 changes: 38 additions & 6 deletions tests/TileHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,35 @@ namespace i3dm.export.tests;

public class TileHandlerTests
{
[Test]
public void GetGpuTileWithoutTagsTest()
{
Tiles3DExtensions.RegisterExtensions();

// arrange
var instances = new List<Instance>();
var instance = new Instance();
instance.Position = new Wkx.Point(1, 2, 0);
instance.Scale = 1;
instance.Model = "./testfixtures/Box.glb";
instances.Add(instance);

// act
var tile = GPUTileHandler.GetGPUTile(instances, UseScaleNonUniform: false);

var fileName = Path.Combine(TestContext.CurrentContext.WorkDirectory, "instancing_tile_without_tags.glb");
File.WriteAllBytes(fileName, tile);

var model = ModelRoot.Load(fileName);

// assert
// Model only contains the EXT_mesh_gpu_instancing extension, no other extensions
Assert.That(model.ExtensionsUsed.Count() == 1);
Assert.That(model.ExtensionsUsed.First() == "EXT_mesh_gpu_instancing");

Assert.That(tile.Length > 0);
}

[Test]
public void GetGpuTileTest()
{
Expand All @@ -23,7 +52,7 @@ public void GetGpuTileTest()
var instance = new Instance();
instance.Position = new Wkx.Point(1, 2, 0);
instance.Scale = 1;
instance.Model = "Box.glb";
instance.Model = "./testfixtures/Box.glb";
instance.Tags = JArray.Parse("[{'id':123},{'name': 'test'}]");
instances.Add(instance);

Expand All @@ -34,6 +63,8 @@ public void GetGpuTileTest()
File.WriteAllBytes(fileName, tile);

var model = ModelRoot.Load(fileName);
Assert.That(model.ExtensionsUsed.Count() == 3);

var extInstanceFeaturesExtension = model.LogicalNodes[0].GetExtension<MeshExtInstanceFeatures>();

var extStructuralMetadataExtension = model.GetExtension<EXTStructuralMetadataRoot>();
Expand All @@ -56,7 +87,7 @@ public void GetTileTest()
var instance = new Instance();
instance.Position = new Wkx.Point(1, 2);
instance.Scale = 1;
instance.Model = "Box.glb";
instance.Model = "./testfixtures/Box.glb";
instances.Add(instance);

// act
Expand All @@ -75,6 +106,7 @@ public void GetTileTest()
[Test]
public void GetCompositeTileTest()
{

// arrange
var instances = new List<Instance>();
var instance = new Instance();
Expand Down Expand Up @@ -122,7 +154,7 @@ public void GetTileWithScaleNonUniformTest()
var instance = new Instance();
instance.Position = new Wkx.Point(1, 2);
instance.ScaleNonUniform = scaleNonuniform;
instance.Model = "Box.glb";
instance.Model = "./testfixtures/Box.glb";
instances.Add(instance);

// act
Expand Down Expand Up @@ -166,12 +198,12 @@ public void GetTileWithRtcCenterTest()
var instances = new List<Instance>();
var instance = new Instance();
instance.Position = new Wkx.Point(1, 2);
instance.Model = "Box.glb";
instance.Model = "./testfixtures/Box.glb";
instances.Add(instance);

var instance1 = new Instance();
instance1.Position = new Wkx.Point(10, 20);
instance1.Model = "Box.glb";
instance1.Model = "./testfixtures/Box.glb";
instances.Add(instance1);

// act
Expand All @@ -193,7 +225,7 @@ public void GetTileWithTagsTest()
var instances = new List<Instance>();
var instance = new Instance();
instance.Position = new Wkx.Point(1, 2);
instance.Model = "Box.glb";
instance.Model = "./testfixtures/Box.glb";
var tags = JArray.Parse("[{'id':123},{'name': 'test'}]");
instance.Tags = tags;
instances.Add(instance);
Expand Down
7 changes: 5 additions & 2 deletions tests/i3dm.export.tests.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -17,7 +17,10 @@
</ItemGroup>

<ItemGroup>
<None Update="Box.glb">
<None Update="testfixtures\Box.glb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testfixtures\tree.glb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Expand Down
File renamed without changes.
Binary file added tests/testfixtures/tree.glb
Binary file not shown.

0 comments on commit 1cf5e40

Please sign in to comment.