vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
476 stars 75 forks source link

Having problem to create a GLTF with Punctual Lights #168

Closed leonardomartelli closed 1 year ago

leonardomartelli commented 1 year ago

Hello!

I am having trouble creating a GLTF file from scratch and adding Punctual Light information to it.

I don't understand how to create a light from a ModelRoot object, and after adding the Meshes to it.

Is there any example how to create a GLTF with lights? If not, could it be added?

Thanks!

vpenades commented 1 year ago

It depends on which API from the API you're using.

If you use Schema2 (low level API) you can add a PunctualLight by simply assigning it to Node.PunctualLight property.

If you use SceneBuilder (high level API) you can use SceneBuilder.AddLight method.

If you look int the unit tests, I think there's some examples.

geowarin commented 1 year ago

Hello @vpenades !

I'm running into the same problem. SceneBuilder.AddLight() takes a LightBuilder but there is no way to create a LightBuilder, everything is private/protected/internal.

vpenades commented 1 year ago

LigthBuilder is the base class of LightBuilder.Directional, LightBuilder.Spot and LightBuilder.Point , use those instead.

geowarin commented 1 year ago

Ok I found the problem!

161 adds public constructors and was committed two months ago. (9be25232)

Version 1.0.0-alpha0027 is the latest version available on nuget and was published four months ago.

Is there another way to get the latest version of the code?

vpenades commented 1 year ago

you can clone the repo and link directly to the project with projectreference temporarily, until I release new packages soon.

geowarin commented 1 year ago

fixed in 1.0.0-alpha0028 :smile: Thanks!

geowarin commented 1 year ago

However, I'm not sure how to use this properly.

This code:

var gltf = new SceneBuilder();
var light = new LightBuilder.Point
{
    Color = new Vector3(1, 0, 0),
    Intensity = 3,
    Range = 10,
};
gltf.AddLight(light, AffineTransform.Identity);
gltf.ToGltf2().Save("export/testLight.gltf");

Produces an empty gltf:

{
  "asset": {
    "copyright": "",
    "generator": "SharpGLTF 1.0.0-alpha0028",
    "version": "2.0"
  },
  "scene": 0,
  "scenes": [
    {}
  ]
}
bertt commented 1 year ago

this works with Schema2 (low level API):

var root = ModelRoot.CreateModel();
var scene = root.UseScene("");
scene.CreateNode()
    .PunctualLight = root.CreatePunctualLight(PunctualLightType.Directional)
    .WithColor(Vector3.UnitX, 2);
root.Save("mesh.gltf");
geowarin commented 1 year ago

Yes I know :)

Shouldn't it work with Toolbox as well?

This test works but I could not find one with the higher level API.

Do you recommend I switch to the low level API?

vpenades commented 1 year ago

I had some time to check and it seems the conversion from SceneBuilder to Schema2 is broken, I'll try to fix it ASAP

geowarin commented 1 year ago

Thanks @vpenades. Can't wait to try it!

geowarin commented 1 year ago

Hi @vpenades! I think you have not released the new version on Nugget. Would you mind creating a new release, if it's not too much trouble? Thanks!

vpenades commented 1 year ago

I'm quite busy lately, dunno when I'll be able to upload a new version, probably some time in the next two weeks

ansfspeisse commented 1 year ago

Hello @vpenades ! First of all thank you for your work :)

I'm using the high level API to build a glTF file. When converting a SceneBuilder containing a LightBuilder to a ModelRoot, the Extras property of the LightBuilder seems not to be populated in the resulting PunctualLight contained in the ModelRoot.

I modified the test dedicated to light creation as following:

Test(Description = "Creates a simple cube with a light.")]
public void CreateCubeWithLightScene()
 {
            TestContext.CurrentContext.AttachGltfValidatorLinks();

            var material = MaterialBuilder.CreateDefault();
            var mesh     = new Cube<MaterialBuilder>(material).ToMesh(Matrix4x4.Identity);
            var scene    = new SceneBuilder();
            scene.AddRigidMesh(mesh, Matrix4x4.Identity);

            var       color     = new Vector3(1, 0, 0);
            const int intensity = 3;
            const int range     = 10;
            var extras = JsonContent.CreateFrom(new Dictionary<string, bool>
            {
                {
                    "CastShadows", true
                }
            });

            var lightBuilder = new LightBuilder.Point
            {
                Color     = color,
                Intensity = intensity,
                Range     = range,
                Extras    = extras
            };

            scene.AddLight(lightBuilder, new NodeBuilder("light").WithLocalTranslation(new Vector3(0, 100, 0)));

            var lightInstances = scene.Instances
                                      .Select(item => item.Content.Content)
                                      .OfType<LightContent>()
                                      .ToList();

            Assert.AreEqual(1, lightInstances.Count);

            var gltf = scene.ToGltf2();

            Assert.AreEqual(1, gltf.LogicalPunctualLights.Count);
            var light = gltf.LogicalPunctualLights[0];

            Assert.IsNotNull(light);
            Assert.AreEqual(color, light.Color);
            Assert.AreEqual(intensity, light.Intensity);
            Assert.AreEqual(range, light.Range);
            Assert.IsNotNull(light.Extras.Content); // Fails
            Assert.IsTrue(JsonContent.AreEqualByContent(extras, light.Extras, float.Epsilon));

            gltf.AttachToCurrentTest("cube.glb");
            gltf.AttachToCurrentTest("cube.gltf");
            gltf.AttachToCurrentTest("cube.plotly");
}

Assertion checking Extras property validity is failing here and (when commenting these assertions) produced glTF file does not contain Extras property:

{
  "extensions": {
    "KHR_lights_punctual": {
      "lights": [
        {
          "color": [
            1,
            0,
            0
          ],
          "intensity": 3,
          "range": 10,
          "type": "point"
        }
      ]
    }
  },

  ...

Is this intended (not to use the LightBuilder's Extras property) ?

Thank you for your response.