Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gpu instancing metadata #49

Merged
merged 2 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# i3dm.export

Console tool for exporting Instanced 3D Models (i3dm's), i3dm composites (cmpt) and tileset.json from PostGIS table.
Console tool for exporting Instanced 3D Models (i3dm's or glb), i3dm composites (cmpt) and tileset.json from PostGIS table.

The input table contains instance information like location (epsg:4326), binary glTF model (glb), scale, rotation and instance attributes.

The 3D tiles created by this tool are tested in Cesium JS.


MapBox GL JS (using https://github.com/Geodan/mapbox-3dtiles) is NOT supported at the moment.

Sample of trees in Cesium viewer using instanced 3D Tiles in Lyon:
Expand Down Expand Up @@ -202,7 +201,15 @@ There is an experimental option to create 3D Tiles 1.1 using GPU instancing: --u

This option is currently in development.

The following features should work: Positioning, Rotation (roll, pitch, yaw) and Scaling of instances.
Live demo trees in Grenoble with GPU instancing and metadata:

https://bertt.github.io/cesium_3dtiles_samples/samples/1.1/grenoble_trees/

The following features should work:

- Attribute information from tags using EXT_structural_metadata, EXT_mesh_gpu_instancing and EXT_instance_features.

- Positioning, Rotation (roll, pitch, yaw) and Scaling of instances.

To use this option, the input table should contain columns 'roll', 'pitch' and 'yaw' (column 'rotation' is not used).

Expand All @@ -217,9 +224,9 @@ alter table instances drop column rotation

The columns should be filled with radian angles (0 - 2PI).

The following features are not yet supported when using use_gpu_instancing:
Known limits:

- batch information (EXT_Mesh_Features/EXT_Structural_Metadata)
- When using GPU instancing, the column type 'string' is used (so no support for other types yet).

- composite tiles (formerly known as cmpt). When there are multiple models in the input table only the first one is used.

Expand Down Expand Up @@ -253,6 +260,8 @@ To Visualize in CesiumJS, add references to:

## History

2023-03-28: release 2.7.0: add support for EXT_structural_metadata

2023-11-08: release 2.6.0: Add support for GPU instancing (experimental), removed option -r RTC_CENTER

2023-10-18: release 2.5.0: Improved root bounding volume calculation, improved batch table handling
Expand Down
2 changes: 2 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using i3dm.export.Cesium;
using i3dm.export.extensions;
using Npgsql;
using SharpGLTF.Schema2;
using ShellProgressBar;
using subtree;
using System;
Expand Down Expand Up @@ -97,6 +98,7 @@ static void Main(string[] args)
if ((bool)o.UseGpuInstancing)
{
translate = new Vector3((float)center_wgs84.X, (float)center_wgs84.Y, (float)center_wgs84.Z);
Tiles3DExtensions.RegisterExtensions();
}

var options = new ProgressBarOptions
Expand Down
57 changes: 50 additions & 7 deletions src/TileHandler.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using Cmpt.Tile;
using i3dm.export.Cesium;
using I3dm.Tile;
using Newtonsoft.Json.Linq;
using SharpGLTF.Geometry.VertexTypes;
using SharpGLTF.Geometry;
using SharpGLTF.Scenes;
using SharpGLTF.Schema2;
using SharpGLTF.Transforms;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using Wkx;
using System.Text.Json.Nodes;
using SharpGLTF.Schema2.Tiles3D;

namespace i3dm.export;

Expand Down Expand Up @@ -46,7 +44,12 @@ public static byte[] GetTile(List<Instance> instances, Format format, Vector3 tr

if (useGpuInstancing)
{
var bytesGlb = GetGpuGlb(model, modelInstances, translate, UseScaleNonUniform);
foreach (var instance in instances)
{
tags.Add(instance.Tags);
}

var bytesGlb = GetGpuGlb(model, modelInstances, translate, UseScaleNonUniform, tags);
tiles.Add(bytesGlb);
}
else
Expand Down Expand Up @@ -94,13 +97,15 @@ private static Vector3 GetPosition(Point p, Vector3 translate)
return vec;
}

private static byte[] GetGpuGlb(object model, List<Instance> positions, Vector3 translate, bool UseScaleNonUniform)
private static byte[] GetGpuGlb(object model, List<Instance> positions, Vector3 translate, bool UseScaleNonUniform, List<JArray> tags)
{
var modelRoot = ModelRoot.Load((string)model);
var meshBuilder = modelRoot.LogicalMeshes.First().ToMeshBuilder();

var sceneBuilder = new SceneBuilder();

var pointId = 0;

foreach (var p in positions)
{
var point = (Point)p.Position;
Expand All @@ -124,12 +129,50 @@ private static byte[] GetGpuGlb(object model, List<Instance> positions, Vector3
scale,
quaternion,
translation);
sceneBuilder.AddRigidMesh(meshBuilder, transformation);
var json = "{\"_FEATURE_ID_0\":" + pointId + "}";
sceneBuilder.AddRigidMesh(meshBuilder, transformation).WithExtras(JsonNode.Parse(json));
pointId++;
}

var settings = SceneBuilderSchema2Settings.WithGpuInstancing;
settings.GpuMeshInstancingMinCount = 0;
var gltf = sceneBuilder.ToGltf2(settings);

var rootMetadata = gltf.UseStructuralMetadata();
var schema = rootMetadata.UseEmbeddedSchema("schema");
var schemaClass = schema.UseClassMetadata("propertyTable");

if(tags.Count > 0)
{
var propertyTable = schemaClass.AddPropertyTable(positions.Count);

if (tags[0] != null)
{
var properties = TinyJson.GetProperties(tags[0]);
foreach(var property in properties)
{
var values = TinyJson.GetValues(tags, property);

var nameProperty = schemaClass
.UseProperty(property)
.WithStringType();

// todo: use other types than string
var strings = values.Select(s => s.ToString()).ToArray();

propertyTable
.UseProperty(nameProperty)
.SetValues(strings);
}
}


var featureId0 = new FeatureIDBuilder(positions.Count, 0, propertyTable);
gltf.LogicalNodes[0].AddInstanceFeatureIds(featureId0);

}


var bytes = gltf.WriteGLB().Array;
return bytes;
}
Expand Down
2 changes: 1 addition & 1 deletion src/TinyJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static string ToJson(List<JArray> tags, List<string> properties)
return resres;
}

private static List<object> GetValues(List<JArray> tags, string prop)
public static List<object> GetValues(List<JArray> tags, string prop)
{
var res = new List<Object>();
foreach (var tag in tags)
Expand Down
8 changes: 4 additions & 4 deletions src/i3dm.export.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
<TargetFramework>net6.0</TargetFramework>
<ToolCommandName>i3dm.export</ToolCommandName>
<PackageOutputPath>./nupkg</PackageOutputPath>
<Version>2.6.0</Version>
<AssemblyVersion>2.6.0</AssemblyVersion>
<FileVersion>2.6.0</FileVersion>
<Version>2.7.0</Version>
<AssemblyVersion>2.7.0</AssemblyVersion>
<FileVersion>2.7.0</FileVersion>
<PackageProjectUrl>https://github.com/geodan/i3dm.export</PackageProjectUrl>
<RepositoryUrl>https://github.com/geodan/i3dm.export</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>i3dm 3dtiles mapbox</PackageTags>
<PackageReleaseNotes>add cesium support</PackageReleaseNotes>
<Description>Console tool for exporting instanced 3D Tiles (i3dm's) and tileset.json from PostGIS table.</Description>
<Description>Console tool for exporting instanced 3D Tiles (glb or i3dm's) and tileset.json from PostGIS table.</Description>
<Company>Geodan</Company>
<Authors>Bert Temme</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
23 changes: 17 additions & 6 deletions tests/TileHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using I3dm.Tile;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using SharpGLTF.Schema2;
using SharpGLTF.Schema2.Tiles3D;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -14,29 +16,38 @@ public class TileHandlerTests
[Test]
public void GetGpuTileTest()
{
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 = "Box.glb";
instance.Tags = JArray.Parse("[{'id':123},{'name': 'test'}]");
instances.Add(instance);

// act
var tile = TileHandler.GetTile(instances, Format.Cesium, Vector3.Zero,useGpuInstancing:true);
var tile = TileHandler.GetTile(instances, Format.Cesium, Vector3.Zero, useGpuInstancing: true);

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

var model = SharpGLTF.Schema2.ModelRoot.Load(fileName);

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

var extStructuralMetadataExtension = model.GetExtension<EXTStructuralMetadataRoot>();
Assert.That(extStructuralMetadataExtension != null);

var fid0 = extInstanceFeaturesExtension.FeatureIds[0];
Assert.That(fid0.FeatureCount == 1);


// assert
// todo: can we read the instance positions from the glb?
Assert.That(tile.Length > 0);
}



[Test]
public void GetTileTest()
{
Expand Down Expand Up @@ -164,7 +175,7 @@ public void GetTileWithRtcCenterTest()
instances.Add(instance1);

// act
var tile = TileHandler.GetTile(instances, Format.Mapbox,translate: new Vector3(5, 5, 0));
var tile = TileHandler.GetTile(instances, Format.Mapbox, translate: new Vector3(5, 5, 0));
var cmpt = CmptReader.Read(new MemoryStream(tile));
var i3dm = I3dmReader.Read(new MemoryStream(cmpt.Tiles.First()));

Expand Down
Loading