How to set up ERC between Render Settings properties and a scene node?

ParrisParris Posts: 392

Basically I want to send a value from a property in Render Settings to a property of a figure/prop in scene. Ideally each time the property is updated in one place it performs remote control on the other. I'm starting with the Render Settings - Find Property code sample here. With this script example, I understand that I can replace "Image Name" with "Dome Orientation Y" for example and it will give me the label for that property. But how do I get the value of that property?

Post edited by Parris on

Comments

  • The script you link to gets an array of properties - you find the one you want there and manipulate it as desired (with getValue(), setValue( val ) for example).

    However, the Render Settings are not a scene item so I don't think you can literally set up an ERC link - you may need to connect a function in a script to a signal to achieve your aim.

  • ParrisParris Posts: 392

    Thank you, Richard. Just what I needed to get me started. I figured getValue() was a thing, like getLabel(), but I couldn't think of the term for such components so couldn't find a list in the Qt Documentation.

  • ParrisParris Posts: 392

    How would I get the image path?

  • If it's a DzNumericProperty (or derivative) getMapValue() will return a DzTexture, from which you can get teh map name and path with getFilename(). If it's a DzImageProperty then getValue() will return a DzTexture.

  • ParrisParris Posts: 392

    Ok, right. Thank you. Environment Map must be derivative of DzNumericProperty because it works with oProperty.getMapValue().getFilename(). Now I think I need to set up the proper error check with isMappable() and isMapped().

  • ParrisParris Posts: 392
    edited December 2016

    Ok, this is me taking baby steps. But I figured that since you (Richard) got me as far as getting the map and path from Render Settings then the next step would be to see if I could get the script to apply that acquisition to my prop. This snippet added to the bottom of Rob's code example above works thus far. But I suspect this is sloppy and may not have all the error checking it needs. Can anyone give me tips on how to improve it? I know I have much further to go to get formulas working between the dome and my prop. I just want to try to build clean healthy code as I go.

    	/*********************************************************************/	// Find a specific property by name	//Renderer: "DzIrayRenderer", "DzDelightRenderer", "DzScriptedRenderer"	//Element: "General Render", "" = no filter	var oProperty = findRendererProperty( "DzIrayRenderer", "", "Environment Map", false );		// If we found a property	if( oProperty ){		if ( oProperty.isMapped() ){		// Get the path and name of the Environment Map		var currentEnvMap = oProperty.getMapValue().getFilename();		}	}		var oNode = Scene.getPrimarySelection();	// If nothing is selected	if( !oNode ){		// We're done..		return;	} 	var oShape = oNode.getObject().getCurrentShape();	var nMat = oShape.getNumMaterials();	for (var k=0; k < nMat; k++) {		var oMat = oShape.getMaterial(k);			var sName = oMat.getName();			if (sName == "env sphere") {				var oDiffMap = oMat.findProperty( "Diffuse Color" );				oDiffMap.setMap(currentEnvMap);			}	}	// Finalize the function and invoke})();

     

    Post edited by Parris on
  • ParrisParris Posts: 392

     

    However, the Render Settings are not a scene item so I don't think you can literally set up an ERC link - you may need to connect a function in a script to a signal to achieve your aim.

    Hey Richard, I might not have been specific enough about what I'm trying to do. Specifically I want to set up ERC between the Environment Dome and a sphere prop I have in the scene. Isn't the dome in the scene but invisible, and if so would it be possible to make ERC work?

  • No, if you mean the Iray HDRI - that's just a setting, not an actual scene item.

  • Parris said:

    Ok, this is me taking baby steps. But I figured that since you (Richard) got me as far as getting the map and path from Render Settings then the next step would be to see if I could get the script to apply that acquisition to my prop. This snippet added to the bottom of Rob's code example above works thus far. But I suspect this is sloppy and may not have all the error checking it needs. Can anyone give me tips on how to improve it? I know I have much further to go to get formulas working between the dome and my prop. I just want to try to build clean healthy code as I go.

    	/*********************************************************************/	// Find a specific property by name	//Renderer: "DzIrayRenderer", "DzDelightRenderer", "DzScriptedRenderer"	//Element: "General Render", "" = no filter	var oProperty = findRendererProperty( "DzIrayRenderer", "", "Environment Map", false );		// If we found a property	if( oProperty ){		if ( oProperty.isMapped() ){		// Get the path and name of the Environment Map		var currentEnvMap = oProperty.getMapValue().getFilename();		}	}		var oNode = Scene.getPrimarySelection();	// If nothing is selected	if( !oNode ){		// We're done..		return;	} 	var oShape = oNode.getObject().getCurrentShape();	var nMat = oShape.getNumMaterials();	for (var k=0; k < nMat; k++) {		var oMat = oShape.getMaterial(k);			var sName = oMat.getName();			if (sName == "env sphere") {				var oDiffMap = oMat.findProperty( "Diffuse Color" );				oDiffMap.setMap(currentEnvMap);			}	}	// Finalize the function and invoke})();

     

    You don't check that you have a shape - if the primary seelction is a bone, a light, a camera, or a number of other things then it won't have any geometry. Check you have a real geometry before trying to get the shape.

  • ParrisParris Posts: 392

    You don't check that you have a shape - if the primary seelction is a bone, a light, a camera, or a number of other things then it won't have any geometry. Check you have a real geometry before trying to get the shape.

    Ok, will fix. Thank you, Richard. Your help is truely a thoughtful gift! Merry Christmas!

  • ParrisParris Posts: 392
    edited December 2016

    Ok, now with this revision I've got all the properties that I need to link together between Iray Render Settings and my prop (the Iray HDRI, and the x, y, and z rotation). But I know this is just the tip of the iceberg. Now I either need to set up ERC using DzERCLink, or if this is not possible as Richard says, then I need to set up signals for each property. Trouble is I don't know how to do either and am having trouble finding examples or documentation. How should I proceed from here?

    	/*********************************************************************/	// Find a specific property by name	//Renderer: "DzIrayRenderer", "DzDelightRenderer", "DzScriptedRenderer"	//Element: "General Render", "" = no filter	var oProperty = findRendererProperty( "DzIrayRenderer", "", "Environment Map", false );	var oOrientationX = findRendererProperty( "DzIrayRenderer", "", "Dome Orientation X", false );	var oOrientationY = findRendererProperty( "DzIrayRenderer", "", "Dome Orientation Y", false );	var oOrientationZ = findRendererProperty( "DzIrayRenderer", "", "Dome Orientation Z", false );	// If we found a property	if( oProperty ){		if ( oProperty.isMapped() ){		// Get the path and name of the Environment Map		var currentEnvMap = oProperty.getMapValue().getFilename();		}	}	if( oOrientationX ){		// Get the value of Dome Orientation X		var tempOX = oOrientationX.getValue();	}	if( oOrientationY ){		// Get the value of Dome Orientation Y		var tempOY = oOrientationY.getValue();	}	if( oOrientationZ ){		// Get the value of Dome Orientation Z		var tempOZ = oOrientationZ.getValue();	}		var oNode = Scene.getPrimarySelection();	// If nothing is selected	if( !oNode ){		// We're done..		return;	}	var oObject = oNode.getObject(); 	var oShape = oObject.getCurrentShape();	var nMat = oShape.getNumMaterials();	for (var k=0; k < nMat; k++) {		var oMat = oShape.getMaterial(k);			var sName = oMat.getName();			if (sName == "env sphere") {				var oDiffMap = oMat.findProperty( "Diffuse Color" );				oDiffMap.setMap(currentEnvMap);			}	}	var oXRot = oNode.getXRotControl();	oXRot.setValue(tempOX);	var oYRot = oNode.getYRotControl();	oYRot.setValue(tempOY);	var oZRot = oNode.getZRotControl();	oZRot.setValue(tempOZ);// Finalize the function and invoke})();

     

    Post edited by Parris on
  • 	// Create an ERC link - the enumerators are in the DzERCLink docs.	var ERCLink = new DzERCLink( type , multiplier , addend );	// if successful	if ( ERCLink ) {		// Set the property that will drive the link		ERCLink.setProperty( masterProperty );		// and the link to the slave (sub-component) property		slaveProperty.insertController( ERCLink );	}

     

  • ParrisParris Posts: 392
    edited December 2016

    Try ERC? Ok, that seems easiest. I think I understand what I need to feed in as master and slave. And I'm pretty sure I don't need to worry about multipier or addend because I'm not adjusting the values. But type? Do I need to specify that? Because when I do a search for DzERCLink (built in doc search or google) I can't find a list of types. In fact I can't find anything that seems like a "DzERCLInk" document.

    Post edited by Parris on
  • enum  	ERCType {  ERCDeltaAdd = 0, ERCDivideInto, ERCDivideBy, ERCMultiply,  ERCSubtract, ERCAdd}

    From the old DS3 scripting docs - though I'm not sure if ERC even works for image properties, on reflection.

  • ParrisParris Posts: 392
    edited December 2016

    Thank you again. OK, ERC seems to work fine with the Render Setting's rotations as masters and the prop's rotations as slaves but not the other way around. And I kept getting errors when I tried to set up ERC for the image, so I would think you are right about that. So I'm guessing I need to set up a signal to get the image to update?

    Post edited by Parris on
  • Yes, and unfortunately getting a script to stay resident so that it can be triggered by an application event is not something I've done. You'd also need to figure out which event would suit your needs.

  • ParrisParris Posts: 392

    So if I understand you correctly, a loop in the script would need to keep running until the prop is deleted from the scene, or the scene is closed, or DS exited. Within that loop would be a function that copies the image from Render Settings over to the prop whenever the signal that it has changed is triggered. Is that the idea? 

  • No, you need to use the Connect function to link a  function in your script to the signal you want to respond to - then when that function is triggered it gets the filename and assigns the map to the target. The loop is provided by DS. The bit I don't understand well is getting the script to stay resident after it runs (since you obviously want access to the UI) - I do believe it is possible, however.

  • ParrisParris Posts: 392
    edited December 2016

    Ok, so with using the Connect function, keeping the script resident, and choosing the right event in mind I have this little test. Shown snippet is just the bottom section that gets added to Rob's Render Settings - Find Property example and it is a modification of Simtenero's snippet from the How do signals work? thread. The test is just to see if changing the Environment Map in Render Settings will trigger my function using the signal currentValueChanged and  to see if the script will stay resident with a while loop and processEvents().

    This test works well: I get a message box every time I change the HDRI and the script keeps running. However, if I change from a map to none or from none to a map, then the script errors with "Unhandled error while executing script" and "QScriptEngine::popContext() doesn't match with pushContext()" and then the script quits. What might I be doing wrong or how do I get around this error? Any guesses?

     

    	/*********************************************************************/	function hasChanged()	{ 		MessageBox.information( "MyScript finished successfully.", "MyScript", "&OK" );		changeComplete = true;	};		/*********************************************************************/	var oProperty = findRendererProperty( "DzIrayRenderer", "", "Environment Map", false );	connect(oProperty, "currentValueChanged()", hasChanged);	const changeComplete = false;	while (!changeComplete)	{		processEvents();	}

     

    Post edited by Parris on
  • I'm not sure, but I might suspect the issue is that the mapless property is not in fact the same property as the mapped property, so your oProperty may be invalid.

  • ParrisParris Posts: 392

    Right. So I'm trying to write it so connect only gets called if the property is mapped. But somehow I'm not getting it right.

  • Sorry, I don't know - help us, (R)obi-Wan Kenobi, you are our only hope.

  • rbtwhizrbtwhiz Posts: 2,187

    The return type of the findRendererProperty() function in the Render Settings - Find Property sample is DzProperty. If the property returned derives from DzNumericProperty, a DzERCLink object can be created to control it, or be controlled by it. If the property you intend to replicate does not inherit DzNumericProperty, or even if it does, you have the option of creating a property alias (i.e., DzProperty::createAlias()) instead; an alias has it's own name, label and path, but forwards everything else to the property that it is an alias of.

    Links to properties, and/or aliases of properties, on elements that are not objects in the scene, such as the elements that provide render settings, do not save. However, if you take a look the Post-Load Script Data Item sample, you'll see that you can cause a script to execute when an object that can be saved is loaded. This post-load script can be used to create the ERC Link(s) or the property alias(es) when a given object is loaded.

    If you intend to link/alias properties on something that is dynamic (i.e., something that may or may not exist at the time the object is loaded, and thus the post-load script is executed) you may find yourself needing to use DzCallBackMgr and DzCallBack. If you do that, however, you'll need to consider the lifetime of the callback object, the signal you connect to and the impact it will have on performance.

    -Rob

  • Thanks Rob - I think DzCallBackMgr was one of the things that was looming vaguely in my hind-brain.

  • ParrisParris Posts: 392
    edited January 2017

    Yes, thank you Rob. I really appreciate the code samples and that you came in here especially when you are officially off. I'm grateful to both of you for your help, and I don't want to take advantage: Meaning, I'm trying to work out what I can on my own. My trouble though, is that I don't know enough about the vocabulary you guys use to tell for certain whether I've been clear about the specific obtacle I'm trying to get past at this point, or whether you totally do understand and I just don't understand the answer.

    Where I'm at is that I have an object (scene subset) that calls a script when it loads. The script sets up ERC between Dome Orientation X,Y, and Z and the rotation of the scene object just fine. The only thing left to work out (I think) is how to get the Diffuse Color Map property on the scene object to be updated whenever Environment Map is changed in Render Settings. The presumption that I think I share with Richard is that ERC won't work with image properties. At least I couldn't get it to work using DzERCLink the same way I did with the Orientation properties. So then I tried to set up a signal using currentValueChanged() and ProcessEvents() in a while loop. That triggers fine until the user switches from an HDRI to None or vice versa, at which point the script errors out and quits (QScriptEngine::popContext() doesn't match with pushContext) instead of staying active ,which I need it to do for the signal to keep working.

    Rob, it seems like you might be saying that I can use a proprerty alias instead of ERC or a signal. Is that right? If so, is there a code example somewhere? I don't understand if I'm supposed to make the alias for the Environment Map property or the Diffuse Color map property of my prop, or ...Or do I have to use DzCallBackMgr and DzCallBack because Environment Map is dynamic (null when None is chosen)? Sorry, I think I'm grasping at straws here. I don't know. Thanks for your patience.

    Post edited by Parris on
  • ParrisParris Posts: 392
    edited January 2017

    Update: I changed my google search keywords and found this thread which helped me understand how to do an alias: Sharing a property between nodes? . So I created an alias of Environment Map and put it on my prop. Now whenever I change the environment map, the alias changes too. Pretty cool! But of cource the alias it is just a property in the Parameters tab with no purpose at this point, since it doesn't link to Diffuse Color in any way. So I'm not sure I've made any progress with my goal, though I definitely made progress with my understanding of scripting. smiley

    Maybe I need to make it so Diffuse Color is an alias of Environment Map or something. But I'm not sure if you can do that with an existing property rather than making a new one.

    Hey, can anyone tell me what -> means? I searched Qt and Javascript documentation but I can't find the answer. Does it serve the same purpose as a period or is there a difference?

    Post edited by Parris on
  • djigneodjigneo Posts: 283
    Parris said:

    Hey, can anyone tell me what -> means? I searched Qt and Javascript documentation but I can't find the answer. Does it serve the same purpose as a period or is there a difference?

    The "arrow operator" is a C++ operator, which there is quite a bit of documentation out there for. The TL;DR is that the arrow operator is to be used on a pointer to an object, whereas the dot operator should be used on the object directly. Try this to get you started. http://www.cplusplus.com/forum/beginner/139181/

     

  • I thought it was a pointer, but then Googling didn't confirm that. In that case it's an errro in the docs - scripting doesn't distinguish in syntax (the the difference can matter)

  • Parris said:

    Update: I changed my google search keywords and found this thread which helped me understand how to do an alias: Sharing a property between nodes? . So I created an alias of Environment Map and put it on my prop. Now whenever I change the environment map, the alias changes too. Pretty cool! But of cource the alias it is just a property in the Parameters tab with no purpose at this point, since it doesn't link to Diffuse Color in any way. So I'm not sure I've made any progress with my goal, though I definitely made progress with my understanding of scripting. smiley

    Maybe I need to make it so Diffuse Color is an alias of Environment Map or something. But I'm not sure if you can do that with an existing property rather than making a new one.

    The dead-easiest way to do that is to dink around with the shader on it:  open Shader Mixer and import the current shader (this will be in the object's "coat of paint" rather than the mesh of the object itself), then find where the Diffuse Color goes in and attach an Environment Map node to feed into that value.  Of course, if your Environment Map is renamed "Diffuse Color" you and your customer (or other users) will soon enough find yourselves frustrated by trying to use it directly as a Diffuse Color instead of recognizing that it's an Environment Map function.  But that Environment Map function will follow the object and whatever else you apply that shader to.

Sign In or Register to comment.