[Closed] Merging linked layer references in custom attributes conundrum
I have a bit of a tricky problem here. For my Outliner tool, I’m storing references to layers in a CustomAttribute definition on the layers. To enable nested layers, these references can be a chain of any number of layers. E.g. layerA references layerB, which references layerC, and so on.
When an object from a scene with this CA gets merged everything generally works fine. 3dsmax nicely merges all layer dependencies.
However, there is a catch: if the scene already contains a layer with the name of one of the layers in the chain, 3dsmax crashes. I assume this is because 3dsmax does not allow duplicate layer names and does not consider this way of using layers when merging objects.
The CA definition I use is very simple:
outlinerNestedLayerData = attributes outlinerNestedLayerData version:1 attribID:#(0x7f85134a, 0x2ec90557)
(
parameters main
(
outliner_parentLayer type:#MaxObject;
--and a couple boolean fields.
)
)
One ‘solution’ I have found was what I would consider a hack: using the premerge callback to rename all layers in the scene to a something temporary. Then in the postmerge callback I would check for clashing names and combine those layers into one:
old_layer_names = #();
function preMerge = (
old_layer_names = #();
--Skip layer 0.
for i = 1 to layermanager.count - 1 do
(
local layer = ILayerManager.getLayerObject i;
old_layer_names[i] = #();
old_layer_names[i][1] = layer;
old_layer_names[i][2] = layer.name;
layer.setName ("__outliner_pre_merge__" + layer.name);
)
)
function combineLayers layerA layerB = (
local nodes = refs.dependentNodes layerB.layerAsRefTarg;
format "Combine % and %
" layerA.name layerB.name;
for n in nodes do
(
format "--%
" n.name;
layerA.addNode n;
)
LayerManager.deleteLayerByName layerB.name;
)
function postMerge = (
for i in old_layer_names do
(
local mergedLayer = layerManager.getLayerFromName i[2];
if (mergedLayer != undefined) do
combineLayers i[1] mergedLayer;
i[1].setName i[2];
)
old_layer_names = undefined;
)
callbacks.removeScripts id:#outliner_test;
callbacks.addScript #filePreMerge "preMerge()" id:#outliner_test;
callbacks.addScript #filePostMerge "postMerge()" id:#outliner_test;
This works, but it is far from pretty. And it requires everyone who wants to merge a scene that happens to have the ‘wrong’ CA’s has to have this bit of script running.
I’ve been pondering the issue and how to solve it for a long time, but haven’t found a good solution. So it’d be great if you guys could shed your light on it! Also, if you have an idea on how the references could be handled differently/better, feel free to suggest it!
what do you store in outliner_parentLayer property?
that’s the same as i do in my tools when i need to know what layers come with merged file. it’s absolutely right solution.
Here’s the complete source file, if you’re interested in picking it apart :wip:
http://code.google.com/p/outliner/source/browse/trunk/maxscript/script/nestedlayers.ms
The actual adding happens in the function addLayerData, line 63.
(yes, I could have used some comments here and there, hehe)
That would contain a reference to another layer. A layer which in turn may also contain these custom attributes. For example:
layerA.parentLayer = layerB
layerB.parentLayer = layerC
layerC would then be considered a ‘root layer’ if it doesn’t have the CA.
Just to clarify, here’s the simplest situation where it will crash 3dsmax:
-Create a scene with a layer setup as described above.
-Create a single object assigned to layerA.
-Merge the object into a new scene.
-Delete the object.
-Merge it again. => crash.
that’s the same as i do in my tools when i need to know what layers come with merged file. it’s absolutely right solution.
The reason why I don’t think it’s a complete solution is that it requires anyone who wants to merge a file containing this CA to have this bit of script running. There is no way I can assure that this is the case. And because of this the tool can create scenes that will break not directly related features for others. And that’s something nobody likes of course.
And in addition to that it is more of a workaround. It will always rename all layers and restore the names, even if it is totally unnecessary.
i see that your CA is global. So you can add callbacks on CA create event. All people who want to use your tool have to have the CA. Creating CA they automatically get the callbacks. It makes sense for me
i have my own nested layer tool. i remember i had a similar problem with CA and Layers. I had crash when I xreffed scenes.
so i changed my CA from storing layer itself to storing layer’s name and it’s nodes. that solved my problem.
i suggest you not storing layer or its reference target as maxobject in CA. max rebuilds layers in many situations. it deletes some layers and recreates them again.
the code is real PRO. nothing is wrong there.
as i said, there is the problem in the way how MAX handles layers. max’s doing it bad, and we can’t change the reality. the only way is to find a workaround.
XRef is indeed giving similar problems, I suspect for the same or similar reason.
I had considered storing layer names too. But then the question beckons: if you merge an object that is on a nested layer, you will only have the name of its direct parent, not the parents parent. And when merging you don’t know which scene it comes from (or do you?). So unless you store the entire layer names hierarchy up to the root on each child, how do you rebuild the same hierarchy in a new scene?
Pier,
sorry for asking… you tool is at least a couple years in business. why does the problem sound new for you? was it not reported?
Yeah, it’s a bit embarrassing… The nested layers has been a feature since 2.0, which has was released around April 2010.
I somehow never managed to catch it during my own testing, and it has actually taken some time before the specifics about the issue were reported. Since it crashes 3dsmax, and not just the Outliner, I had to rely on reports made by users only, instead of a detailed crash report generated by the Outliner itself. That inevitably means that the problem description will be a bit vague. E.g. “merging nested layers sometimes crashes 3dsmax”. That is of course difficult to track down. A few months ago someone took the time to dig in to the issue and find out the exact steps to reproduce the issue, allowing me to look for a cause and try to fix it.
And better late than never, right?
As i never intend to make such kind of tool,
please excuse me in advance for any possible no sense words
I have many questions in my head,
but the design idea of such tools is the most major one.
What i not get it is why the custom layer-system should rely on maxobject layers?
What’s wrong in fully independent system based on arrays?
Not at all! I appreciate the input and a good discussion.
What i not get it is why the custom layer-system should rely on maxobject layers?
What’s wrong in fully independent system based on arrays?
For me, “backwards compatibility” is the most important consideration. Since the Outliner that I am writing this for is a public tool, it is very well possible that one artist in a company uses it, while another doesn’t. They should both be able to work with the same scenes.
With the current implementation, the only thing that might look somewhat odd to those who use the standard layer manager is possible empty layers that were used as a parent for other layers.
Basing it on the max layer system is clever and has the advantage that it also provides compatibility with other tools that built up on it. For example psd-manager (PSD export) can create selections for each Max layer. In combination with Outliner that is pretty useful. And this works out of the box without Outliner specific code.
A comment regarding the references:
Another approach that avoids true references is to assign unique numbers to each max layer and use that as the basis for your layer references. Before the file is saved you could back up the complete hierarchy as strings as you said to have that information available upon merge.
Or combine some approaches and just convert your max object layer references before saving and then back again after scene load.
Daniel
Thanks to both for your replies!
I see Daniel got my question very well.
Yes, I’ve not doubts about max layer system benefits.
Managing max layers from custom tool is good as well,
if it come by user or batch interaction, but…
that “background wire” still bother me (:
Thanks!