I don't know about the code of my helper plugin. Never coded a scripted plugin before and it took me some time to figure out how not to create the mesh all the time. It was slow as hell before, now feels ok for me. But still, I think the line "meshop.autoEdge effectorMesh #All 0.1" could be replaced with something faster. Although maybe it's not needed since the mesh is created only at specific cases. Either way any feedback is very welcome. Here it is:
plugin helper falloff_gizmo name:"Falloff Gizmo" category: "Eugenio's Helpers" classID: #(0xa71e203, 0x4ee2cb80) extends:dummy replaceUI:true ( local effectorMesh, mVerts parameters gizmoP rollout:gizmoR (Segments type:#integer ui:ui_segs default:30 animatable:false) parameters paramsP rollout:paramsR ( size type:#float ui:ui_size default:10.0 animatable:true 'falloff' type:#float ui:ui_falloff default:0.0 animatable:true inside type:#float ui:ui_inside1 animatable:true default:0.0 outside type:#float ui:ui_outside1 animatable:true default:1.0 ) fn setEffectorSize = ( for i=1 to (j = mVerts.count) do ( ns = normalize mverts[i]*size nf = ns*(1-('falloff'/100)) setVert effectorMesh i ns setVert effectorMesh (j+i) nf ) ) fn createMesh = ( effectorMesh = triMesh() v1 = for i=1 to Segments collect [cos (i*(360.0/Segments))*size, sin (i*(360.0/Segments))*size, 0] f1 = for i=1 to v1.count-2 collect [1,i+1,i+2] setMesh effectorMesh verts:v1 faces:f1 meshop.autoEdge effectorMesh #All 0.1 m2 = copy effectorMesh.mesh rotate m2 (eulerAngles 90 0 0) m3 = copy effectorMesh.mesh rotate m3 (eulerAngles 0 90 00) meshop.attach effectorMesh m2 meshop.attach effectorMesh m3 nv = effectorMesh.numVerts mVerts = for v=1 to nv collect getVert effectorMesh v meshop.attach effectorMesh (copy effectorMesh) ) on getDisplayMesh do ( if effectorMesh == undefined then createMesh() else setEffectorSize() effectorMesh.mesh ) rollout gizmoR "Gizmo Display" ( group "Gizmo Resolution" ( spinner ui_segs "Segments:" type:#integer range: [4,100,30] ) on ui_segs changed val do createMesh() ) rollout paramsR "Falloff Gizmo" ( group "Parameters" ( spinner ui_size "Size:" range:[0,1e9,0] spinner ui_falloff "Falloff:" range:[0,100,0] ) group "Ranges" ( spinner ui_inside1 "In:" range:[-1e9,1e9,0] align:#left width:59 spinner ui_outside1 "Out:" range:[-1e9,1e9,0] align:#right width:59 offset:[0,-20] ) ) tool create ( on mousePoint click do case click of ( 1: ( nodeTM.translation = gridPoint size=0 ) ) on mouseMove click do case click of ( 2: ( size = length gridDist createMesh() ) 3: 'falloff' = if (d = length gridDist) > 100 then 100 else if d < 0 then 0 else d 4: #stop ) ) )
1: As my main concern here is speed, THIS topic was really interesting. Unfortunately soon the talk got too "deep" and I could not follow it anymore. However, as shown in there, script controllers seem to be a bottleneck speed and memory wise. But I don't know how to achieve the same I'm doing without them. I was planning to make some functions (like different falloff modes maybe) inside the falloff object and call them from the script controllers, but I can't do that with expression or wire. Does weak references help speeding things up here?
Well, I don't know if it's possible through maxscript only, but I wanted to be able to have a workable feedback (8-10fps?!) with at least 1k objects. Am I asking too much from a scripted solution?
Test scene (must run the scripted plugin above first!):
( delete objects fn setScript effector obj = ( ss = float_script() ss.addConstant "inside" effector.baseobject[#inside] ss.addConstant "outside" effector.baseobject[#outside] ss.addNode "obj" obj ss.addNode "effector" effector ss.addTarget "size" effector.baseObject[#size] ss.addTarget "falloff" effector.baseObject[#falloff] script = "" as stringStream format "rIn = size - (size * (falloff/100)) dist = distance effector.pos obj.pos x = (dist-rIn)/(size - rIn) scale = (1-x)*inside + x*outside scl = if dist <= size then if dist >= rIn then scale else inside else outside" to:script ss.script = script as string ss ) sp = sphere radius:10 pos:[80,0,0] wirecolor:brown obj = falloff_gizmo size:100 falloff:60 inside:10 outside:2 wirecolor:orange sp.radius.controller = setScript obj sp gc() t1 = timestamp() mem = heapfree count = 10000 for i=1 to count do sp.radius format "Time: % Mem: %\n" (timestamp() - t1) (mem - heapfree) )
3: How to access the node itself from inside the scripted plugin? I tried using "this" with no luck. Can't find anything in maxscript help. This is a problem for me since I'm adding the custom attribute to the node by using the "$" which is fine if the user explicitly creates the object. But if I try to create it via script it of course fails.
4: As the affected objects hold a script controller, deleting the effector will make a mess. I was thinking in storing the affected controllers in the effector node. So I can revert them before deleting the effector. Does the #maxObjectTab support controller values? The best way for dealing with this is with a #nodePreDelete callback, right?
Forgive me if some questions are too noob, but my coding skills are waaaaayyyy outdated. So I'm completely opened to any tip, suggestion or anything to improve.