Controlar múltiples luces V-Ray con spinners en MaxScript
Hola. Llevo un rato intentando hacer un script y me he quedado estancado, quizá tenga la solución justo delante y no la vea de ahí mi mensaje. A ver si me podéis ayudar, aunque sea conceptualmente.
Estoy tratando de controlar mediante spinner las subdivisiones del sampling de una serie de luces Vray. Para ello recorro las luces que tengo seleccionadas y género dinámicamente tantos spinner como luces tenga en selección. A su vez al value de cada spinner le asigno el valor actual del parámetro de subdivisiones que tiene cada luz Vray. El problema lo tengo a la hora del feedback, porque cuando modifico los valores con los spinner sólo me afecta a la última luz seleccionada y encima todos los spiners afectan a la última luz que haya seleccionado, mientras que al resto de luces no.
El esquema sería (para 2 luces, e).
Primero selecciono las 2 luces con lo que mi selección actual sería.
Vraylight00, vraylight01.
Ahora género mis spinner:
Spin_1 con su valor.
Spin_2 con su valor.
Cuando modifico ambos spinner sólo se me afectada la luz vraylight01 por ser la última luz en la pila o array de selección.
Mi duda es: ¿cómo puedo hacer que un handler sepa que spinner estoy afectando? Y así poder modificar el parámetro de la luz correspondiente.
Aquí pongo el código de esta sección:
Código:
For obj in sel_actual do ( mat_sel = append mat_sel obj ) - Del for samp = utcreator sampling sampling height:400 samp, begin() t - Colocamos justo encima el nombre de subdivisiones local nomlabel = (label_) as name samp, addcontrol #label nomlabel nombre subdivisiones paramstr offset:[95,0] width:300 height:15) t - Espacio local nomlabel = (espacio_) as name samp, addcontrol #label nomlabel - Paramstr offset:[90,-5] width:300 height:15) t - Bucle que genera los spinner necesarios en función de las luces seleccionadas for i = 1 todo mat_sel, count do (t - Variables de control de parámetros de los spiners nomspin = (spin_+ (i as string)) as name nomluz = (mat_sel[i].name + : ) as name valspin =(mat_sel[i].subdivisiones) as string nomobj = mat_sel[i] t samp, addcontrol #spinner nomspin nomluz paramstr type:#integer range:[0,100, + valspin + ] fieldwidth:40 align:#center)\ t samp, addhandler nomspin #changed valspin filter:on \ codestr nomobj.subdivisiones= valspin)\ t ) - Del for t samp, end() addsubrollout vrayluces.child sampling.
Muchas gracias por anticipado.
Vray spinners solo modifican una luz en MaxScript
Cuando queremos crear un panel dinámico en MaxScript que controle propiedades específicas, como las subdivisiones de las luces V-Ray usando spinners, el reto más común aparece en el manejo de eventos. En tu caso, el script crea bien los spinners y les asigna el valor de subdivisiones correspondiente a cada luz seleccionada, pero todos terminan afectando solo a la última luz. Y sí, es más común de lo que parece.
¿Por qué todos los spinners modifican la misma luz?
El problema tiene que ver con cómo MaxScript gestiona el scope o alcance de las variables dentro de los handlers (como on spinner changed). Si dentro del bucle estás creando múltiples spinners, pero les asignas el mismo handler o variable que referencia la luz actual, esa variable ya cambió cuando el evento se dispara. O sea: el evento guarda la referencia, no una copia.
¿Cómo se puede solucionar esto?
La clave está en usar una estructura como un array o diccionario que relacione cada spinner con su luz correspondiente, o encapsular el comportamiento en una función local. Una forma común es usar funciones anidadas (closures) o pasar explícitamente el índice al evento.
Podría ser algo así:
Código:
myLights = selection as array
rollout luzControl "Luz Control"
(
local spinnersArray = #()
for i = 1 to myLights.count do
(
local luz = myLights[i]
local spinnerName = "subdivsSpinner_" + i as string
addcontrol luzControl (spinner spinnerName "Subdivs" range:[1,100, luz.subdivs]) -- suponiendo que subdivs es el parámetro
append spinnersArray luz
local idx = i -- capturamos el índice
fn makeHandler luzObj =
(
fn handler val = (luzObj.subdivs = val)
)
on luzControl.controls[idx] changed val do
(
makeHandler(spinnersArray[idx]) val
)
)
createDialog luzControl
)
Este código es solo una base, porque depende de cómo estés generando los spinners, pero el concepto es: no uses directamente la variable del bucle dentro del handler, porque esa variable cambia y termina apuntando siempre a la última luz.
Programar interfaces en MaxScript es como organizar cables detrás del escritorio, todo parece estar en su sitio… hasta que mueves uno y se cae el router. Así que si ves que todos tus spinners afectan solo a una luz, no es que el script se haya roto, es que MaxScript tiene su propia manera de hacerte sentir humilde.