Setting a DzImageProperty value to a new DzTexture [SOLVED]
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?
Comments
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.
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
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.
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.
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......
I don't want to talk about it any more....
This works.
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......
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.
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.....
Subtley different....and confusingly so.
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.
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!