Version 1.5 seems to have a bug when importing a .duf file with self contained geometry data

Issue #200 resolved
Xin created an issue

Create a .duf file (with filepath here “…/myduf.duf”) which contains geometry data, like:

    "geometry_library" : [
        {
            "id" : "MyGeoID",
            "source" : "/data/...", 
            "name" : "MyGeoName",
            "type" : "polygon_mesh",
            "vertices" : {
                "count" : 123123,
                "values" : [...]
            }

If a node in the scene (same .duf) references such geo, like so:

...
{
                "id" : "MySceneObject",
                "url" : "/data/.../some.dsf",
                "name" : "MySceneObjectName",
                "label" : "MySceneObjectLabel",
                "parent" : "#myparent",
                "geometries" : [
                    {
                        "id" : "MyGeoID-1",
                        "url" : "#MyGeoID",
                        "name" : "MyGeoName",
                        "label" : "shape",
                        "type" : "polygon_mesh"
                    }
                ], 
                ...

Then the importer will fail, you will get zero vertices errors, because the parser in asset.py seems to have a bug when parsing urls of the form “#…' in the main .duf file imported. Specifically, the problematic code is in the function Accesor.getAsset() in asset.py:

 def getAsset(self, id, strict=True):
        global theAssets, theOtherAssets

        if isinstance(id, Asset):
            return id

        id = normalizeRef(id)
        if "?" in id:
            # Attribute. Return None
            return None
        ref = getRef(id, self.fileref)
        try:
            return theAssets[ref]
        except KeyError:
            pass

        if id[0] == "#":
            if self.caller:
                ref = getRef(id, self.caller.fileref)
                try:
                    return theAssets[ref]
                except KeyError:
                    pass
            ref = getRef(id, self.fileref)
            try:
                return theAssets[ref]
            except KeyError:
                pass
            try:
                return theOtherAssets[ref]
            except KeyError:
                pass
            msg = ("Missing local asset:\n  '%s'\n" % ref)
            if self.caller:
                msg += ("in file:\n  '%s'\n" % self.caller.fileref)
            if not strict:
                return None
            reportError(msg)
            return None
        else:
            return self.getNewAsset(id, ref, strict)

The relevant call in this situation is in parseUrlAsset():

asset = self.getTypedAsset(struct["url"], type)

The problem is that the url of geo asset MyGeoID-1 will be resolved to “/data/.../some.dsf#MyGeoID” instead of the correct path “…/myduf.duf#MyGeoID”. In getAsset(), ref = getRef(id, self.fileref) will wrongly take priority over the correct one ref = getRef(id, self.caller.fileref), and that ends up being a bug in this particular situation.

I would try to fix it in the code but I’m not sure if I would end up introducing more bugs (I haven’t inspected the entire code), so I am reporting it as an issue. Thanks.

Comments (8)

  1. Thomas Larsson repo owner

    No, it is not a problem with locally defined assets in general. If it were, the problem would arise in any file with a geometry primitive. Can you upload the file so I can have a look.

  2. Xin reporter

    Ok, I looked a little further and I think I found the problem (what I described earlier was simply side stepping the real problem): are you sure this part is ok (in asset.py)?

        def copySource(self, asset):
            for key in dir(asset):
                if hasattr(self, key) and key[0] != "_":
                    attr = getattr(self, key)
                    try:
                        setattr(asset, key, attr)
                    except RuntimeError:
                        pass
    

    This ends up copying the attributes from a yet to be fully initialized geometry asset (“self”) to “asset”, which means a previously fully initialized “asset” ends up with an empty list of vertices, and that ends up failing to import the geometry (the “source” asset “asset” is referenced by a node in the scene later, but now its data is corrupted, it has no vertices).

    To be clear, this structure is what causes the problem (assume this .dsf is called imported_duf.duf). Pay special attention to the “source” field in the self contained geometry and the url fields below:

    ... self contained geometry section:
    "geometry_library" : [
            {
                "id" : "mysourceGEO",
                "source" : "/data/.../mysource.dsf#mysourceGEO", 
                "name" : "MyGeoName",
                "type" : "polygon_mesh",
                "vertices" : {
                    "count" : 123123,
                    "values" : [...]
                }
    ... nodes section:
    {
                    "id" : "MySceneObject",
                    "url" : "/data/.../mysource.dsf#mynode",
                    "name" : "MySceneObjectName",
                    "label" : "MySceneObjectLabel",
                    "parent" : "#myparent",
                    "geometries" : [
                        {
                            "id" : "MyGeoID-1",
                            "url" : "#mysourceGEO",
                            "name" : "MyGeoName",
                            "label" : "shape",
                            "type" : "polygon_mesh"
                        }
                    ], 
    ...
    

    As I pointed out earlier, if the url of MyGeoID-1 resolves to “imported_duf.duf#mysourceGEO” instead of “/data/.../mysource.dsf#mysourceGEO”the bug disappears, but that seems to be another problem, there is no reason why the parsed mysource.dsf should end up corrupted in the first place.

    So I think there is another problem here, on top of the one described with copySource, unless I’m misunderstanding something: why is the url of MyGeoID-1 not resolving to an url in the local file as you would expect since it starts with #? is that ok?

  3. Thomas Larsson repo owner

    I see. The problem is that the geometry asset has a “source” field. I have not yet found an example of such an asset myself, so the code has not really been tested. Do you know how to generate such an asset, or where to find it?

  4. Thomas Larsson repo owner

    This is confusing, but things seem to work now. Basically the plugin just notices that there is a source asset, but does nothing with it.

    You must set Mesh Fitting to DBZ, though. If it is set to one of the unmorphed values, the corners of each face are located at the same point. You can check that the first 40 or so vertices are identical. The dbz file contains the vertices with all morphs applied, and then the faces become visible.

  5. Log in to comment