Setting a DzImageProperty value to a new DzTexture [SOLVED]

hphoenixhphoenix Posts: 1,323

Well, I'm stumped.

My script is attempting to change the image used by a DzImageProperty (it's a DzBrickMaterial, I iterate through the property list and find the matching property name.)

So I've got a reference to DzApp::DzImageMgr, and I'm calling getImage(newtexturefilename) to get the new DzTexture.  That seems to work....then I call setValue() on the DzImageProperty.

No errors, but it doesn't change in the scene.  The image list doesn't show the new image in it either.  The property doesn't change.  I've tried debugging it, but with the debugger stepping through, the new DzTexture from the DzImageMgr gets deleted before I can do anything.

 

Here are the two significant parts of the script:  First, the main part where I then call a second part....

					// newfn now has the name of the texture to switch to
					// and filename has the current filename
					var newfninfo = new DzFileInfo(newfn);
					if(newfninfo.exists)
					{
						var ImgMgr = App.getImageMgr();
						var checkImage = ImgMgr.findImage(newfn);
						if(checkImage)
						{
							// the image is already loaded.  Set the current Material
							SetMaterialTextureByType(mat,type,checkImage);
						}
						else
						{
							// the image isn't loaded.
							var newTex = ImgMgr.getImage(newfn);
							SetMaterialTextureByType(mat,type,newTex);
						}
						print("Set " + mat.name + " " + GetTextureTypeStr(type) + " to " + newfn);
					}

 

And here is the pertinent part of SetMaterialTextureByType(m, type, tex)

		case textype.brick:
			for(var i = 0; i < m.getNumProperties(); i++)
			{
				var bp = m.getProperty(i);
				if(bp.inherits("DzImageProperty"))
				{
					var bpv = bp.getValue();
					if(bpv.inherits("DzTexture"))
					{
						var tn = tex.name;  print("Texture name: " + tn);
						if(tex.isNull) { print("Texture deleted before it could be set!"); break; }

						if(bpv.name == tex.name)
						{
							bp.setValue(tex);
							break; //i = m.getNumProperties();
						}
					}
				}
			}
			break;

 

I should add that for when it's not a brick, SetMaterialTextureByType() goes through the types it has from DzDefaultMaterial, and calls the various 'set' members.....but that doesn't appear to work EITHER.  (i.e., the image was a "base color" image map, so it is set using materialObj.setColorMap(newTex);

So what am I either missing, or getting wrong?

 

Post edited by hphoenix on

Comments

  • EsemwyEsemwy Posts: 556
    edited June 2016

    Just a thought here. I notice you say 'newfninfo.exists' rather than 'newfninfo.exists()'. The way you have it will not do what you expect.

    Haven't tried it myself, but it looks like the you're doing it the correct way.

    var im = App.getImageMgr();
    var bp = m.getProperty(i);
    var tx = im.findFile(filename);
    
    bp.setValue(tx);

    I usually start at the materials rather than the properties though. If you use DzMaterial.setColorMap(tx), I know I've successfully done that before.

    Edit: forgot to get the DzImageMgr

    Post edited by Esemwy on
  • EsemwyEsemwy Posts: 556
    edited June 2016

    Ah. I found it. DzImageMgr.findImage only works on a currently loaded image.

    I'm at a loss. I've managed to do it with layered textures. This should be easier. DzImageMgr.loadImage() seems to work, but doesn't make the image available.

    Post edited by Esemwy on
  • hphoenixhphoenix Posts: 1,323
    edited June 2016

    This is why it's been driving me nuts.  I've tried a bunch of different variations.  I found several examples using layered images, but nothing about simply loading a new image and setting a material property to use it.

    And what's worse, in the debugger, after the call to getImage(pathToImageFile) if I'm stepping through, the result is quickly destroyed.  Not that it comes back as NULL, but succeeds, then the object gets deleted.  sad

    // example snippet
    // mapProp is assumed to be a material property at this point
    
    var ImgMgr = App.getImageMgr();
    var newImg = ImgMgr.getImage("path/to/some/filename.png");
    
    // if stepping through in the debugger, newImg will be destroyed by the time
    // it executes this next statement.  Doesn't happen if just running through.
    
    if(mapProp.inherits("DzNumericProperty"))
    {
        if(mapProp.isMapped())
        {
            mapProp.setMapValue(newImg);
        }
    }
    

    Evidently, if DzTexture object is in the DzImageMgr list, and isn't in use by anything, it gets deleted?  That doesn't happen when I do it through the UI.  If I change a map to use a different image, the old image is still in the list, even if nothing uses it......

    And you may be right about exists.....but some methods that return a member variable from the object will also return the value instead of the function object.  I think it has to do if the return value is an intrinsic type or not.  I'll double check after my latest render completes......

     

    Post edited by hphoenix on
  • EsemwyEsemwy Posts: 556
    bp.setMap(filename);

    I don't want to talk about it any more....crying

  • EsemwyEsemwy Posts: 556

    This works.

    var oNode = Scene.getPrimarySelection();
    var oObj = oNode.getObject();
    var oShape = oObj.getCurrentShape();
    var oMat = oShape.getMaterial(0);
    var oProp = oMat.findPropertyByLabel("Base Color");
    oProp.setMap("/Users/esemwy/Desktop/yard.jpg");
    

     

  • hphoenixhphoenix Posts: 1,323

    Hmm....The only difference I see is that you are using DzProperty::setMap() and that you are using DzMaterial::findPropertyByLabel().

    And those may not always be correct (as I found out, multiple kinds of Properties, multiple kinds of materials.  DzDefaultMaterial, DzBrickMaterial, DzIrayUberMaterial.....) so I need a more general solution...

    Soon as this render finishes (currently at 67.5% convergence after 2:47:00, almost 1000 iterations), I'll pile back into the IDE and see if I can just manually make the correct property change with what you posted, then see about back-tracking it to find out a more general solution......

     

     

  • EsemwyEsemwy Posts: 556

    Yeah, the DzMaterial::findPropertyByLabel() is just a quick hack to get a mappable property. It's the DzProperty::setMap() that needs to replace your setValue() above. No need to fuss around with the image manager.  

  • hphoenixhphoenix Posts: 1,323
    edited June 2016

    Partially right.  I've got it working.

    The problem is that there are at least TWO inheritable classes to test on, and slightly different things to use depending on which one it is.

    if the property inherits DzNumericProperty, then you test for IsMapable() and IsMapped() on the property.  If both are true, you have a map. And the filename of the map is in prop.getMapValue().getFilename()

    if the property inherits DzImageProperty, then you know it has to be mapped (that class is ALWAYS an image map.)  And the filename is in prop.getValue().getFilename(), IF getValue() is not null (it can be not using a map.)

     

    Now that you know if your current property is mapped, and what it's inherited class is, and you know the current maps filename, you can set it to a new filename.....

    if the property inherits DzNumericProperty, then you simply call prop.setMap(newFilename)

    if the property inherits DzImageProperty, then you simply call prop.setValue(newFilename)

     

    These work with shaders with maps, 3Delight materials, Iray mats, etc. (at least everything I've tried so far!)

     

    SO, a snippet in code form so it's a little more comprehensible.....

    // assume node contains the node we want to use
    // and proplbl is the label of the property we want to change the map of
    // and matidx is the index of the material we want
    // (we could use a find or other method, just assume we can get mat
    
    var obj = node.getObject();
    var shp = obj.getCurrentShape();
    var mat = shp.getMaterial(matidx);
    var prop = mat.findPropertyByLabel(proplbl);
    
    var dnp = prop.inherits("DzNumericProperty");
    var dip = prop.inherits("DzImageProperty");
    var mapped = false;
    
    if(dnp)
    {
        // some DzNumericProperties disallow maps, some allow but don't have them.
        // check both!
        if(prop.isMappable() && prop.isMapped()) mapped = true;
    }
    else if(dip)
    {
        mapped = true;  // always true for DzImageProperty!
    }
    
    if(mapped)
    {
        var curfilename;
        if(dnp)
        {
            curfilename = prop.getMapValue().getFilename();
        }
        else if(dip)
        {
            if(prop.getValue())
            {
                curfilename = prop.getValue().getFilename();
            }
            else
            {
                print("If we got here, it's a DzImageProperty that is not mapped or not mappable!");
                return;
            }
        }
    
        // check here to make sure your file exists, etc.
    
        // the new filename could be built from the old, pulled from another place, etc.
        var newfilename = "SomeOtherFileWithFullPath.png";
        
        // check here to make sure your new file exists, etc. also!
    
        if(dnp) prop.setMap(newfilename);
        else if(dip) prop.setValue(newfilename);
    }

    Subtley different....and confusingly so.

     

    Post edited by hphoenix on
  • EsemwyEsemwy Posts: 556

    Well, ain't that special. Gotta love conststent APIs. 

    Thanks for following up. You might want to mark the topic "solved." 

    I'm going to keep this one in my snippets folder for sure. 

  • TotteTotte Posts: 10,576
    edited September 17

    prop.setMap()!
    Thanks for that one! Been tearing my hair out, dforce way, why it worked when I had a map assigned but not when I didn't have a map alreaady assigned. Gonna leave credit to this thread!

    Post edited by Totte on
Sign In or Register to comment.