Notifications
Clear all

[Closed] Help needed on a tool technical design

Hello,

I need the experience of some maxscript long-time programmers on a new tool I have to develop.

Here is the initial pitch:
[ul]
[li]a scene with objects and lights
[/li][li]several lightings configuration in the scene (day, night,…)
[/li][/ul]

What I want to achieve:
# GUI:
[ul]
[li]intuitive creation of lighting presets. User can put the lights in any lighting preset
[/li][li]some ligths may be in several presets
[/li][/ul]
# Technical Requirements:
[ul]
[li]lighting presets have to be saved in the max file
[/li][li]cannot use scripted plugin object to store data (in case we work with external 3d artists who do not have our tool set)
[/li][/ul]

The question is more about the technical part but I found interesting to know the final goal of the tool if somebody comes with a totally new idea.

22 Replies

Here are my ideas:

For the GUI, a TreeView with lighting presets on the first depth level and lights as children of these presets TreeNodes. The user can add/delete lighting presets with contextual items, drag&drop lights form one preset to another, ctrl drag&drop to duplicate,…

For the saving of these lighting presets, I’m stuck. The nicest way would be to store LightmapPresset structs. I wrote many posts in this forum about persistant globals or custom attributes without finding a real solution. Maybe I missed something…

  • Persistant globals seem very dirty to me. Moreover, combining structs and persistant globals need some dirty hacks with preSave and postOpen callbacks to ensure the struct definition. This is a pain if I need to modify struct definition in the future. I am wrong?

  • A nice solution would be to save the presets as custom attributes of the sceneRoot node. But custom attributes can hold at best unidimensional maxObjectTabs where I need either 2-dimensions arrays #(#(presetName,presetlightsList),…) or, even better, unidimensional struct array.

  • As I said before, scripted object is not an option here, unless there are no other options. I thought of creating one scripted object per lighting preset, holding their lights list, name, and other properties. Are there the same limitations in parameters types than in custom attributes?

I’m very impatient to have your feedbacks on that :).
Thanks for reading until there.

It’s not big and it’s not clever, but you can always store data in dummy’s in a hidden and locked layer. Either the data can be stored as a custom attribute, or even just the name of the object. Obviously how you format and then read the data is up to you, but something as simple a format as “[Preset Name],[Light Name],[Light Property 1],[Light Property 2],… [Light Name],[Light Property 1]” etc etc. You could have the “light name” be something like “light=LightName” rather than just the light name itself, so that your script knows that what it’s reading is a new light and not a new parameter of the old light. The reason you store light parameters (colour, intensity etc) is because you mentioned that it might be set up for different times of day, so perhaps the keylight location, intensity and light size might change. Personally, for the sake of simplicity, I’d recommend that these were actually two key lights and not the same one altered, but it’s up to you.

Of course, someone could screw it up by deleting that layer with the dummys. But tell them not to be idiots, I guess.

Thanks for the answer.

It could be a way, but there are two points annoying me with this method:

  • Layers are not a very elegant/transparent way to do things for the end-user
  • Some frequent manipulations will unlock/unhide this layer like Unhide All or Unfreeze All

Is there some way to avoid these downsides?

I am not a maxscript long-time programmer thus sure they are better and cool ways, but I have a similar tool.

I create selections set for each lighting configuration, DayLights, NightLights… with differents lights, or the same if is a common light to them.
I have 2 differents lights for simulate the same light but with different parameters, as DanGrover said.

Artist can add new lights to them adding to the corresponding selection set. Not addional tools needed for that.
I have a tool that turns on/off the corresponding selection sets lights, changes exposure control parameters, renderer quality needed…
I have extra configuration info in a XML file for each lighting configuration, like daylight system properties, because is common between max scenes.

One big problem: using selection sets is not a mergeable info.

SelectionSets have the same downsides than layers about the unhide/unfreeze all actions.
They are not more transparent to the end-user than the layers.
And, as you said, it is not mergeable :).
Moreover, I use them already in another tool and I don’t really want that the preset selectionSets add confusion to this previous tool.

But thanks anyway!
It is always nice to know how others would have done the thing.

It may seem I am overthinking the tool but if I have the same kind of problematic in the future, what will I do ? Adding more and more Layers or SelectionSets to store data ? I’m not very happy with that.
I will do that when I’m sure that it is the only way to go.

But from what I read here and there, I can smell the good flavor of custom attributes with some handy hack allowing to store those data… or at least objects arrays

do i understand you correct:
the LightSet is some structure that has name, list of lights, and list of objects (effected by these lights). plus some specific for LightSet parameters (active, dynamic, whatever you like…)

this is practically all that you need…


   LightSetHolder = attributes "LightSetHolder" attribid:#(0x19670000, 0x4529ab6c) 
   (
   	parameters main 
   	(
   		setname type:#string 
   		active type:#boolean default:on animatable:off
   		lightlist type:#nodetab tabsize:0 tabsizevariable:on
   		nodes type:#nodetab tabsize:0 tabsizevariable:on
   	)
   	fn validNode node = (not iskindof node Light)
   	fn validLight node = (iskindof node Light)
   	
   	fn validateNodes = undo off (nodes = makeuniquearray (for node in nodes where isvalidnode node collect node)) 
   	fn validateLights = undo off (lightlist = makeuniquearray (for node in lightlist where isvalidnode node collect node))
   
   	fn addNode node = if not validNode node then false else
   	(
   		validateNodes()
   		appendifunique nodes node 
   	)
   	fn addLight node = if not validLight node then false else
   	(
   		validateLights()
   		appendifunique lightlist node 
   	)
   	fn removeNode node =
   	(
   		if (k = finditem nodes node) != 0 do deleteitem nodes k
   	)
   	fn removeLight node =
   	(
   		if (k = finditem lightlist node) != 0 do deleteitem lightlist k
   	)
   )
   fn getLightSetHolders target: = 
   (
   	getclassinstances LightSetHolder target:target
   )
   /*
   a = createinstance LightSetHolder setname:"Test Set"
   a.setname
   
   appendifunique rootnode.custattributes a
   getLightSetHolders target:rootnode
   
   a.addnode $
   a.removenode $
   a.nodes
   */
   

as UI i can recommend DevExpress.XtraTreeList.TreeList. It’s a combination of TreeView and ListView with multiselect feature. When the dialog will be open you have to monitor some node events (use node event callback system) to support real-time UI update (node added, node deleted, node renamed, etc.)

that’s kinda it. not too complicated

Awesome! I will redo with that!
Thanks denisT!

Thank you Denis! It seems to be exactly what I was looking for.

Can I ask some details about the code?

You used “createInstance”. Does it allow to have several instances of the same custom attribute on a single object? If yes, That was the piece of puzzle I have missed in my previous thinking!

Does the created instances defintion of the custom attribute will be updated as well if I update the original definition? (I think the answer is yes because what’s what means “instance” but I prefer to ask)

In case of merging, is the rootNode merged, too? How will behave custom attributes hold by the source scene rootNode and the destination scene rootNode? I will figure it out myself in development but it can create a thread with all the needed information.

Page 1 / 2