[Closed] Scripted Geometry – reference problem
Hello everyone,
I am trying to create a scripted geometry which mirrors a selected geometry. I use weak reference because when i just use the node instead, when translating the source-node it behaves awkardly (it translates jagged, very fast, away from mouse). The problem that arises with weak reference is that when i change the source-geometry the mesh does not update. I have to select the object and use the on rollout open event to do so (even then i have to re-evaluate the mirrorBool value [line:27] or else it does not re-builds the mesh). p.s.(it also does not store in memory the pickbutton text)
Is there a way to create a reference to the mesh property of the source-node so as when the source-geometry changes so does the mesh of the plug-in?
plugin simpleObject MirrorObject
name:"Mirror Object"
classID:#(0x14c6b999, 0x6c060ea1)
category:"har1sf0x"
(
parameters mainP rollout:mainR
(
valid type:#boolean default:false
mirrorBool type:#boolean default:true ui:chk_mirror
obj type:#maxObject
on obj set val do this.rebuildMesh()
on mirrorBool set val do this.rebuildMesh()
)
rollout mainR "Parameters"
(
pickbutton pck_obj "Pick mesh" autodisplay:true
checkbox chk_mirror "Mirror" checked:true
on pck_obj picked o do
(
if isValidnode o and superclassof o == GeometryClass do
(
obj = (nodeTransformMonitor node:o forwardTransformChangeMsgs:false)
pck_obj.text = o.name
valid = true
)
)
on mainR open do (if valid and isValidNode obj.node do (pck_obj.text = obj.node.name);mirrorBool = chk_mirror.checked)
)
on buildmesh do this.rebuildMesh()
fn rebuildMesh =
(
proxy = trimesh()
setMesh proxy length:10 width:10
if valid and isValidNode obj.node do
(
proxy = obj.node.mesh
if mirrorBool do proxy = this.mirrorMesh proxy
)
mesh = proxy
)
fn mirrorMesh msh =
(
for f =1 to msh.numFaces do
(
verts = getFace msh f
local tmp = verts.x
verts.x = verts.z
verts.z = tmp
setFace msh f verts
)
for v = 1 to msh.numVerts do
(
setVert msh v ((getVert msh v)*[-1,1,1])
)
update msh
msh
)
tool create
(
on mousePoint click do
(
case click of
(
1: nodeTM.translation = gridPoint
2: #stop
)
)
)
)
Best regards,
har1sf0x
first of all i don’t think that simpleObject is the right type of plugin for this task… more likely it should be a modifier … the simpleMeshMod
but of course we can organize true monitoring of any mesh with simpleObject plugin…
Hello again,
I did it with the modifier (i also did it with function -> reference copy and mirror modifier) but you have to do one or more clicks (that is one of the reasons i went to the geometry, the other is learning references). I finaly made it work but without the weak reference. I would be very interested and much appreciated if someone could give some ideas about how to get notification from a weak referenced node about its mesh changes.
Here is the code of the updated version (the pickbutton .text still is not being stored, even though i used a parameter):
plugin simpleObject MirrorObject
name:"Mirror Object"
classID:#(0x14c6b999, 0x6c060ea1)
category:"har1sf0x"
(
parameters mainP rollout:mainR
(
valid type:#boolean default:false
mirrorBool type:#boolean default:true ui:chk_mirror
obj type:#node--#maxObject
txt type:#string
-- on obj set val do this.rebuildMesh()
-- on mirrorBool set val do this.rebuildMesh()
)
rollout mainR "Parameters"
(
pickbutton pck_obj "Pick mesh" autodisplay:true
checkbox chk_mirror "Mirror" checked:true
on pck_obj picked o do
(
if isValidnode o and superclassof o == GeometryClass do
(
obj = o--(nodeTransformMonitor node:o forwardTransformChangeMsgs:false)
txt = o.name
pck_obj.text = txt
valid = true
)
)
-- on mainR open do (if valid and isValidNode obj do (pck_obj.text = obj.name))--;mirrorBool = chk_mirror.checked)
)
on buildmesh do this.rebuildMesh()
fn rebuildMesh =
(
proxy = trimesh()
setMesh proxy length:10 width:10
if valid and isValidNode obj do--.node do
(
proxy = obj.mesh--.node.mesh
if mirrorBool do proxy = this.mirrorMesh proxy
)
setMesh mesh proxy
)
fn mirrorMesh msh =
(
for f =1 to msh.numFaces do
(
verts = getFace msh f
local tmp = verts.x
verts.x = verts.z
verts.z = tmp
setFace msh f verts
)
for v = 1 to msh.numVerts do
(
setVert msh v ((getVert msh v)*[-1,1,1])
)
update msh
msh
)
tool create
(
on mousePoint click do
(
case click of
(
1: nodeTM.translation = gridPoint
2: #stop
)
)
)
)
Best regards,
har1sf0x
You just have to change two lines in your code:
.
.
txt type:#string default:"Pick mesh"
.
.
pickbutton pck_obj txt autodisplay:true
.
.
But, in fact, I can’t understand how your plugin works (and it works fine). I mean, why the MirrorObject changes when you change the referenced node. I can’t see any handler for this.
It’s a study. Suppose i want to link the referenced mesh to the scripted object. Without the weak reference this is impossible.
#1 try to use nodemonitor instead of nodetransformmonitor
#2 look at referencetargetcontainer
Hello,
I’ve tried both (NodeMonitor, RefTargContainer), even RefTargMonitor. It either has a dependency loop problem or it does not update live. Never both problems are absent:
plugin simpleObject MirrorObject
name:"Mirror Object"
classID:#(0x14c6b999, 0x6c060ea1)
category:"har1sf0x"
(
-- local objCont --with this i can link either way but it does not update live
parameters mainP rollout:mainR
(
valid type:#boolean default:false
mirrorBool type:#boolean default:true ui:chk_mirror
objCont type:#maxObject --with this it does update live but i can link only one way
size type:#float default:20
type type:#integer default:1 ui:rdb_type
txt type:#string default:"Pick mesh" ui:pck_obj
on mirrorBool set val do this.rebuildMesh()
)
rollout mainR "Parameters"
(
pickbutton pck_obj txt autodisplay:true
checkbox chk_mirror "Mirror" checked:true
group "Mirror Axis"
(
radiobuttons rdb_type labels:#("X","Y","Z","XY","XZ","YZ","XYZ") columns:3
)
on pck_obj picked o do
(
if isValidnode o and superclassof o == GeometryClass do
(
objCont.SetItem 1 o
txt = o.name
valid = true
)
)
)
on postCreate do objCont = RefTargContainer holdAsWeakReferences:true
on buildmesh do this.rebuildMesh()
fn rebuildMesh =
(
mesh = trimesh()
if valid and isValidNode (this.objCont.GetItem 1) then
(
mesh = (objCont.GetItem 1).mesh
if mirrorBool do mesh = this.mirrorMesh mesh
) else (setMesh mesh length:size width:size lengthsegs:1 widthsegs:1)
)
fn mirrorMesh msh =
(
scaleVec = #([-1,1,1],[1,-1,1],[1,1,-1],[-1,-1,1],[-1,1,-1],[1,-1,-1],[-1,-1,-1])[type]
for f = 1 to msh.numFaces while type < 4 or type == 7 do
(
local bl = false
if (getEdgeVis msh f 1) and (getEdgeVis msh f 2) and (getEdgeVis msh f 3) do bl = true
blList = #()
for i = 1 to 3 do append blList (getEdgeVis msh f i)
verts = getFace msh f
local tmp = verts.x
verts.x = verts.z
verts.z = tmp
setFace msh f verts
if bl then for i = 1 to 3 do setEdgeVis msh f i true
else
(
if not blList[1] and (mod f 2) == 1 do
(
setEdgeVis msh f 1 false
setEdgeVis msh f 2 false
setEdgeVis msh f 3 true
)
if blList[1] and (mod f 2) == 0 do
(
setEdgeVis msh f 1 true
setEdgeVis msh f 2 true
setEdgeVis msh f 3 false
)
)
)
for v = 1 to msh.numVerts do
(
setVert msh v ((getVert msh v)*scaleVec)
)
update msh
msh
)
tool create
(
on mousePoint click do
(
case click of
(
1: nodeTM.translation = gridPoint
2: #stop
)
)
on mouseMove click do
(
case click of
(
2:
(
size = abs(amax #(gridDist.x,gridDist.y))
)
3: (#stop)
)
)
)
)
see this example that i’ve showed here and on area…
plugin simpleObject Cloner
name:"Cloner"
classID:#(0x00001967, 0x0af62091)
category:"Scripted Primitives"
silentErrors:off
version:1
(
fn validGeometry node = (iskindof node GeometryClass)
-- local mesh
parameters main rollout:main
(
meshTarget type:#node subanim:on ui:pickobject_bt
meshObject type:#MaxObject
)
parameters params rollout:main
(
count type:#integer ui:ui_count
radius type:#worldunits ui:ui_radius
tilt type:#worldunits ui:ui_tilt
)
rollout main "Parameters"
(
group "Mesh Object: "
(
pickbutton pickobject_bt "Pick Mesh Object" autoDisplay:on filter:validGeometry width:144 align:#right offset:[4,0]
)
on pickobject_bt picked obj do
(
meshObject = createinstance Editable_mesh
meshObject.mesh = obj.mesh
)
group "Spacing: "
(
spinner ui_count "Count: " range:[1,512,1] type:#integer fieldwidth:60 align:#right offset:[4,0]
spinner ui_radius "Radius: " range:[0,1e9,0] type:#worldunits fieldwidth:60 align:#right offset:[4,0]
spinner ui_tilt "Tilt: " range:[0,1e9,0] type:#float fieldwidth:60 align:#right offset:[4,0]
)
)
fn _transformMesh mesh tm =
(
list = for v=1 to mesh.numverts collect ((getVert mesh v)*tm)
setmesh mesh vertices:list
)
fn _attachMeshes meshes =
(
n = meshes.count
while (num = n/2) > 0 do for k=1 to num do
(
meshop.attach meshes[k] meshes[n]
n -= 1
)
meshes[1]
)
on buildMesh do
(
setMesh mesh numverts:0 numfaces:0
if meshObject != undefined do
(
m = if isvalidnode meshTarget then (copy meshTarget.mesh) else (copy meshObject.mesh)
tm = transmatrix [radius,0,0]
cc = for k=1 to count collect
(
c = copy m
_transformMesh c tm
tm = prerotateY tm (tilt/count)
tm = rotateZ tm (360.0/count)
c
)
setMesh mesh (_attachMeshes cc)
free m
)
)
tool create
(
on mousePoint click do case click of
(
1:
(
nodeTM.translation = gridPoint
#stop
)
)
on mouseMove click do case click of
(
)
)
)
you can use NodeTransformMonitor instead of node…
also there is another way of to store mesh (using reftargcontainer). you can find posts about it on this forum
Hello and thank you for your concern.
I’ve read your post in the autodesk forum and just tested but it also creates a dependency loop becauce of the meshTarget. That is what makes the mesh update live. If you comment the
ui:pickobject_bt
in line 12 the object will not give a dependency loop but it will also not update live.
I tend to believe that it is not possible to create a ‘live’ reference to an other object without creating a dependency loop. I even tried to create and test an indirect reference (ref.setIndirectReference() getting error all over the place) but as i saw in the help files it cannot be done via maxscript.
p.s. have in mind that your script was crashing in my computer probably because of count=0 on initialization even thougn in the ui was saying 1 (because of the range) and the cc was an empty array. i gave a default to count and worked like a charm.
p.s.1 as i said i tested the other suggestions. i do not want to store the mesh. i want to reference it so as to update live
p.s.2 when you create a reference copy of an object it does not create a dependency loop and updates the mesh live. that is what i am looking for to replicate in my plugin.
yes … my example crashes if the number of cloned instances equals 0. but believe me i don’t care. usually my example codes are very far from my commercial versions. but they show enough…
going to your issue…
i see a fundamental misunderstanding of how the notification system works. because of the difference there are special ways (plugin types) to achieve what you want.
Hello,
you are definitely right, i am totally confused as it seems. From your reply i understand that i am using the wrong plugin type and that it is not possible achieving such behaviour with this plugin type, right? Is there a way to learn more about the notification-reference system of max besides the maxscript manual?
Thanks,
har1sf0x
p.s. i hope you did not misunderstood my comment about your example code. it was just a note in case someone would like to try it and got into the error. I am obliged to you and to all about your concern and the time you spend sharing your experience with me and off-course honestly thankful having the opportunity to take advice from all of you.