Skip to content

Commit edb678a

Browse files
committed
initial coding KHR_gaussian_splatting
1 parent 5153478 commit edb678a

8 files changed

Lines changed: 512 additions & 0 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
using SharpGLTF.SchemaReflection;
6+
7+
namespace SharpGLTF
8+
{
9+
class GaussianSplattingExtension : SchemaProcessor
10+
{
11+
private static string SchemaUri => KhronosExtensions.KhronosExtensionPath("KHR_gaussian_splatting", "mesh.primitive.KHR_gaussian_splatting.schema.json");
12+
13+
private const string ExtensionRootClassName = "KHR_gaussian_splatting glTF Mesh Primitive Extension";
14+
15+
public override IEnumerable<(string, SchemaType.Context)> ReadSchema()
16+
{
17+
var ctx = SchemaProcessing.LoadExtensionSchemaContext(SchemaUri);
18+
19+
yield return ("ext.GaussianSplatting.g", ctx);
20+
}
21+
22+
public override void PrepareTypes(CodeGen.CSharpEmitter newEmitter, SchemaType.Context ctx)
23+
{
24+
newEmitter.SetRuntimeName(ExtensionRootClassName, "GaussianSplatting");
25+
}
26+
}
27+
}

build/SharpGLTF.codeGen.Extensions.Khronos/KhronosExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public static IEnumerable<SchemaProcessor> GetExtensionsProcessors()
3030

3131
// gpu mesh instancing
3232
yield return new MeshGpuInstancingExtension();
33+
yield return new GaussianSplattingExtension();
3334

3435
// textures
3536
yield return new TextureTransformExtension();

src/SharpGLTF.Core/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ It also handles the way a mesh is brought from its local space to world space, i
5050
- [x] [KHR_lights_punctual](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
5151
- [x] [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_mesh_quantization)
5252
- [x] [EXT_mesh_gpu_instancing](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing)
53+
- [x] [KHR_gaussian_splatting](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_gaussian_splatting)
54+
55+
#### KHR_gaussian_splatting quick usage
56+
57+
```c#
58+
var primitive = mesh.CreatePrimitive().WithIndicesAutomatic(PrimitiveType.POINTS);
59+
primitive.WithVertexAccessor("POSITION", positions);
60+
primitive.WithVertexAccessor(GaussianSplatting.AttributeRotation, rotations);
61+
primitive.WithVertexAccessor(GaussianSplatting.AttributeScale, scales);
62+
primitive.WithVertexAccessor(GaussianSplatting.AttributeOpacity, opacities);
63+
primitive.WithVertexAccessor(GaussianSplatting.AttributeSHDegree0Coef0, shDegree0);
64+
65+
var gaussian = primitive.UseGaussianSplatting();
66+
gaussian.Kernel = GaussianSplatting.KernelEllipse;
67+
gaussian.ColorSpace = GaussianSplatting.ColorSpaceSrgbRec709Display;
68+
```
5369

5470
- [x] [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness)
5571
- This extension has been declared _obsolete_ by Khronos, in favour of KHR_materials_specular + KHR_materials_IOR
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// <auto-generated/>
2+
3+
//------------------------------------------------------------------------------------------------
4+
// This file has been programatically generated; DON´T EDIT!
5+
//------------------------------------------------------------------------------------------------
6+
7+
#pragma warning disable SA1001
8+
#pragma warning disable SA1027
9+
#pragma warning disable SA1028
10+
#pragma warning disable SA1121
11+
#pragma warning disable SA1205
12+
#pragma warning disable SA1309
13+
#pragma warning disable SA1402
14+
#pragma warning disable SA1505
15+
#pragma warning disable SA1507
16+
#pragma warning disable SA1508
17+
#pragma warning disable SA1652
18+
19+
using System;
20+
using System.Collections.Generic;
21+
using System.Linq;
22+
using System.Text;
23+
using System.Numerics;
24+
using System.Text.Json;
25+
26+
using JSONREADER = System.Text.Json.Utf8JsonReader;
27+
using JSONWRITER = System.Text.Json.Utf8JsonWriter;
28+
using FIELDINFO = SharpGLTF.Reflection.FieldInfo;
29+
30+
31+
namespace SharpGLTF.Schema2
32+
{
33+
using Collections;
34+
35+
/// <summary>
36+
/// Data defining a 3D Gaussian Splat primitive.
37+
/// </summary>
38+
#if NET6_0_OR_GREATER
39+
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
40+
#endif
41+
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("SharpGLTF.CodeGen", "1.0.0.0")]
42+
partial class GaussianSplatting : ExtraProperties
43+
{
44+
45+
#region reflection
46+
47+
public new const string SCHEMANAME = "KHR_gaussian_splatting";
48+
protected override string GetSchemaName() => SCHEMANAME;
49+
50+
protected override IEnumerable<string> ReflectFieldsNames()
51+
{
52+
yield return "colorSpace";
53+
yield return "kernel";
54+
yield return "projection";
55+
yield return "sortingMethod";
56+
foreach(var f in base.ReflectFieldsNames()) yield return f;
57+
}
58+
protected override bool TryReflectField(string name, out FIELDINFO value)
59+
{
60+
switch(name)
61+
{
62+
case "colorSpace": value = FIELDINFO.From("colorSpace",this, instance => instance._colorSpace); return true;
63+
case "kernel": value = FIELDINFO.From("kernel",this, instance => instance._kernel); return true;
64+
case "projection": value = FIELDINFO.From("projection",this, instance => instance._projection ?? "perspective"); return true;
65+
case "sortingMethod": value = FIELDINFO.From("sortingMethod",this, instance => instance._sortingMethod ?? "cameraDistance"); return true;
66+
default: return base.TryReflectField(name, out value);
67+
}
68+
}
69+
70+
#endregion
71+
72+
#region data
73+
74+
private String _colorSpace;
75+
76+
private String _kernel;
77+
78+
private const String _projectionDefault = "perspective";
79+
private String _projection;
80+
81+
private const String _sortingMethodDefault = "cameraDistance";
82+
private String _sortingMethod;
83+
84+
#endregion
85+
86+
#region serialization
87+
88+
protected override void SerializeProperties(JSONWRITER writer)
89+
{
90+
base.SerializeProperties(writer);
91+
SerializeProperty(writer, "colorSpace", _colorSpace);
92+
SerializeProperty(writer, "kernel", _kernel);
93+
SerializeProperty(writer, "projection", _projection);
94+
SerializeProperty(writer, "sortingMethod", _sortingMethod);
95+
}
96+
97+
protected override void DeserializeProperty(string jsonPropertyName, ref JSONREADER reader)
98+
{
99+
switch (jsonPropertyName)
100+
{
101+
case "colorSpace": DeserializePropertyValue<GaussianSplatting, String>(ref reader, this, out _colorSpace); break;
102+
case "kernel": DeserializePropertyValue<GaussianSplatting, String>(ref reader, this, out _kernel); break;
103+
case "projection": DeserializePropertyValue<GaussianSplatting, String>(ref reader, this, out _projection); break;
104+
case "sortingMethod": DeserializePropertyValue<GaussianSplatting, String>(ref reader, this, out _sortingMethod); break;
105+
default: base.DeserializeProperty(jsonPropertyName,ref reader); break;
106+
}
107+
}
108+
109+
#endregion
110+
111+
}
112+
113+
}

src/SharpGLTF.Core/Schema2/gltf.ExtensionsFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static ExtensionsFactory()
3838
RegisterExtension<Node, _NodePunctualLight>("KHR_lights_punctual", p=> new _NodePunctualLight(p));
3939
RegisterExtension<Node, MeshGpuInstancing>("EXT_mesh_gpu_instancing", p=> new MeshGpuInstancing(p));
4040
RegisterExtension<Node, _NodeVisibility>(_NodeVisibility.SCHEMANAME, p => new _NodeVisibility(p));
41+
RegisterExtension<MeshPrimitive, GaussianSplatting>(GaussianSplatting.SCHEMANAME, p => new GaussianSplatting(p));
4142

4243
RegisterExtension<Material, MaterialUnlit>("KHR_materials_unlit", p => new MaterialUnlit(p));
4344
RegisterExtension<Material, MaterialSheen>("KHR_materials_sheen", p => new MaterialSheen(p));
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
using System;
2+
3+
namespace SharpGLTF.Schema2
4+
{
5+
public partial class GaussianSplatting
6+
{
7+
#region lifecycle
8+
9+
internal GaussianSplatting(MeshPrimitive primitive)
10+
{
11+
_Owner = primitive;
12+
}
13+
14+
#endregion
15+
16+
#region constants
17+
18+
public const string KernelEllipse = "ellipse";
19+
20+
public const string ColorSpaceSrgbRec709Display = "srgb_rec709_display";
21+
public const string ColorSpaceLinRec709Display = "lin_rec709_display";
22+
23+
public const string ProjectionPerspective = "perspective";
24+
public const string SortingMethodCameraDistance = "cameraDistance";
25+
26+
public const string AttributeRotation = "KHR_gaussian_splatting:ROTATION";
27+
public const string AttributeScale = "KHR_gaussian_splatting:SCALE";
28+
public const string AttributeOpacity = "KHR_gaussian_splatting:OPACITY";
29+
public const string AttributeSHDegree0Coef0 = "KHR_gaussian_splatting:SH_DEGREE_0_COEF_0";
30+
31+
#endregion
32+
33+
#region data (not serializable)
34+
35+
private readonly MeshPrimitive _Owner;
36+
37+
#endregion
38+
39+
#region properties
40+
41+
public MeshPrimitive LogicalParent => _Owner;
42+
43+
public string Kernel
44+
{
45+
get => _kernel;
46+
set
47+
{
48+
Guard.NotNullOrEmpty(value, nameof(value));
49+
_kernel = value;
50+
}
51+
}
52+
53+
public string ColorSpace
54+
{
55+
get => _colorSpace;
56+
set
57+
{
58+
Guard.NotNullOrEmpty(value, nameof(value));
59+
_colorSpace = value;
60+
}
61+
}
62+
63+
public string Projection
64+
{
65+
get => _projection ?? _projectionDefault;
66+
set
67+
{
68+
value = value.AsEmptyNullable();
69+
_projection = value == _projectionDefault ? null : value;
70+
}
71+
}
72+
73+
public string SortingMethod
74+
{
75+
get => _sortingMethod ?? _sortingMethodDefault;
76+
set
77+
{
78+
value = value.AsEmptyNullable();
79+
_sortingMethod = value == _sortingMethodDefault ? null : value;
80+
}
81+
}
82+
83+
#endregion
84+
85+
#region API
86+
87+
public static string GetSphericalHarmonicsAttribute(int degree, int coefficient)
88+
{
89+
Guard.MustBeBetweenOrEqualTo(degree, 0, 3, nameof(degree));
90+
91+
var coefficientCount = 2 * degree + 1;
92+
Guard.MustBeBetweenOrEqualTo(coefficient, 0, coefficientCount - 1, nameof(coefficient));
93+
94+
return $"KHR_gaussian_splatting:SH_DEGREE_{degree}_COEF_{coefficient}";
95+
}
96+
97+
#endregion
98+
}
99+
100+
public sealed partial class MeshPrimitive
101+
{
102+
private static readonly string[] _GaussianRequiredAttributes =
103+
{
104+
GaussianSplatting.AttributeRotation,
105+
GaussianSplatting.AttributeScale,
106+
GaussianSplatting.AttributeOpacity,
107+
GaussianSplatting.AttributeSHDegree0Coef0
108+
};
109+
110+
public GaussianSplatting GetGaussianSplatting()
111+
{
112+
return this.GetExtension<GaussianSplatting>();
113+
}
114+
115+
public GaussianSplatting UseGaussianSplatting()
116+
{
117+
var ext = GetGaussianSplatting();
118+
if (ext == null)
119+
{
120+
ext = new GaussianSplatting(this);
121+
this.SetExtension(ext);
122+
}
123+
124+
return ext;
125+
}
126+
127+
public void RemoveGaussianSplatting()
128+
{
129+
this.RemoveExtensions<GaussianSplatting>();
130+
}
131+
132+
private void _ValidateGaussianSplatting(Validation.ValidationContext validate)
133+
{
134+
var gaussian = GetGaussianSplatting();
135+
if (gaussian == null) return;
136+
137+
validate.EnumsAreEqual(nameof(DrawPrimitiveType), DrawPrimitiveType, PrimitiveType.POINTS);
138+
validate.IsDefined("Attributes.POSITION", GetVertexAccessor("POSITION"));
139+
140+
foreach (var semantic in _GaussianRequiredAttributes)
141+
{
142+
validate.IsDefined($"Attributes.{semantic}", GetVertexAccessor(semantic));
143+
}
144+
145+
var rotation = GetVertexAccessor(GaussianSplatting.AttributeRotation);
146+
if (rotation != null)
147+
{
148+
validate.IsAnyOf
149+
(
150+
$"Attributes.{GaussianSplatting.AttributeRotation}.Format",
151+
rotation.Format,
152+
(DimensionType.VEC4, EncodingType.FLOAT),
153+
(DimensionType.VEC4, EncodingType.BYTE, true),
154+
(DimensionType.VEC4, EncodingType.SHORT, true)
155+
);
156+
}
157+
158+
var scale = GetVertexAccessor(GaussianSplatting.AttributeScale);
159+
if (scale != null)
160+
{
161+
validate.IsAnyOf
162+
(
163+
$"Attributes.{GaussianSplatting.AttributeScale}.Format",
164+
scale.Format,
165+
(DimensionType.VEC3, EncodingType.FLOAT),
166+
(DimensionType.VEC3, EncodingType.BYTE),
167+
(DimensionType.VEC3, EncodingType.BYTE, true),
168+
(DimensionType.VEC3, EncodingType.SHORT),
169+
(DimensionType.VEC3, EncodingType.SHORT, true)
170+
);
171+
}
172+
173+
var opacity = GetVertexAccessor(GaussianSplatting.AttributeOpacity);
174+
if (opacity != null)
175+
{
176+
validate.IsAnyOf
177+
(
178+
$"Attributes.{GaussianSplatting.AttributeOpacity}.Format",
179+
opacity.Format,
180+
(DimensionType.SCALAR, EncodingType.FLOAT),
181+
(DimensionType.SCALAR, EncodingType.UNSIGNED_BYTE, true),
182+
(DimensionType.SCALAR, EncodingType.UNSIGNED_SHORT, true)
183+
);
184+
}
185+
186+
var sh0 = GetVertexAccessor(GaussianSplatting.AttributeSHDegree0Coef0);
187+
if (sh0 != null)
188+
{
189+
validate.IsAnyOf
190+
(
191+
$"Attributes.{GaussianSplatting.AttributeSHDegree0Coef0}.Format",
192+
sh0.Format,
193+
(DimensionType.VEC3, EncodingType.FLOAT)
194+
);
195+
}
196+
197+
validate.IsTrue(nameof(gaussian.Kernel), !string.IsNullOrWhiteSpace(gaussian.Kernel), "must be defined.");
198+
validate.IsTrue(nameof(gaussian.ColorSpace), !string.IsNullOrWhiteSpace(gaussian.ColorSpace), "must be defined.");
199+
}
200+
}
201+
}

src/SharpGLTF.Core/Schema2/gltf.MeshPrimitive.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ protected override void OnValidateContent(Validation.ValidationContext validate)
332332
{
333333
base.OnValidateContent(validate);
334334

335+
_ValidateGaussianSplatting(validate);
336+
335337
// all vertices must have the same vertex count
336338

337339
int vertexCount = -1;

0 commit comments

Comments
 (0)