View Full Version : Info panel for 11.5

03-05-2013, 01:36 PM
This Lightwave 11.5 python script was inspired by the Info panel found in trueSpace. I wanted a more convenient way to rename things. It's a Master plugin script with a non-modal dialog. All the samples I could find were for modal dialogs so this may not be the best way to do it. A bounding box input was one other thing I wanted to add to it, but the bounds always returns (0,0,0) for the min and max values of the box. Hopefully the code can be of some use someone.

The code was too long to show here so here's a link to page that has the script:


Here is the section for bounding box that gave me trouble. The numPoints function seems to work and it gives no errors when returning the min and max values. If anyone has any ideas let me know.

#obj_info = lwsdk.LWObjectInfo()
#min, max = obj_info.bounds(self._item_ID)
#print min
#print max
#numpoints = obj_info.numPoints(self._item_ID)
#print numpoints

03-25-2013, 08:03 AM
... but the bounds always returns (0,0,0) for the min and max values of the box ...

After hitting F9, it works the way its expected to. Every time you change the position and need to evaluate this, F9 or ...

Anyway, thanks for your code and examples, it really helps me testing things.

Thanks !!!

03-26-2013, 07:49 AM
I'm developing a plugin that requires the extraction of vertex positions, the code below iterates over the vertex of a mesh and stores its positions. It does not require that F9 thing ...
Maybe comparing all values and extracting min and max for each axis could gave you "bounding box - like" info.

Hope it can help you ...

By the way, sorry about my english, it's still in development too :D

import lwsdk
count = 0
posiciones = []
item_info = lwsdk.LWItemInfo()
object_info = lwsdk.LWObjectInfo()
# gets selection
sel = lwsdk.LWInterfaceInfo().selected_items()[0]
# create iterator over mesh
meshinfo = object_info.meshInfo( sel, True )
iterator = meshinfo.createMeshIterator( lwsdk.LWMESHITER_POINT )
numPoints = object_info.numPoints( sel )
# iterate over vertex in selection
while count != int( numPoints ):
# only evaluate 10% of vertex
if not count % 10:
count += 1
vertexID = meshinfo.iterateMesh( iterator )
pointPos = meshinfo.pntOtherPos( vertexID )
pointPos = str( pointPos )
pointPos = pointPos.split( ' ' )
posiciones.append( pointPos )
count += 1
meshinfo.destroyMeshIterator( iterator )

03-26-2013, 03:02 PM
Thanks for the tips and tricks. I think I'll see if I can work the F9 in somehow.

03-26-2013, 06:53 PM
This is cool. Thanks guys!

04-09-2013, 07:08 PM
Thanks for the help. I went with pedromm's suggestion except I used pntBasePos instead of pntOtherPos to get the vertex positions. I added a bounding box entry to the ui for setting the scale of a mesh by specifying the size. First I tried using F9 and it did work and worked even better with vpr active, but I needed the untransformed bounding box values not affected by rotation values. I suspect the Layout bounding box value is used for culling/cropping in rendering process. The pntOtherPos was also returning transformed values.

def getBB(self):
interface_info = lwsdk.LWInterfaceInfo()
selected_items = interface_info.selected_items()
minX = minY = minZ = 9999999
maxX = maxY = maxZ = -9999999
obj_info = lwsdk.LWObjectInfo()
sel = selected_items[0]
numpoints = obj_info.numPoints(sel)
if numpoints == 0:
return False
meshinfo = obj_info.meshInfo( sel, True )
iterator = meshinfo.createMeshIterator( lwsdk.LWMESHITER_POINT )

# iterate over vertex in selection
vertexID = meshinfo.iterateMesh( iterator )
while vertexID:
#pointPos = meshinfo.pntOtherPos( vertexID )
pointPos = meshinfo.pntBasePos( vertexID )

if pointPos[0] < minX:
minX = pointPos[0]
if pointPos[0] > maxX:
maxX = pointPos[0]
if pointPos[1] < minY:
minY = pointPos[1]
if pointPos[1] > maxY:
maxY = pointPos[1]
if pointPos[2] < minZ:
minZ = pointPos[2]
if pointPos[2] > maxZ:
maxZ = pointPos[2]

vertexID = meshinfo.iterateMesh( iterator )

meshinfo.destroyMeshIterator( iterator )

self._minX = minX
self._minY = minY
self._minZ = minZ
self._maxX = maxX
self._maxY = maxY
self._maxZ = maxZ

return True

04-11-2013, 01:44 AM
Glad to see you made it. I'm a Maya guy, so your plugin make me feel a little more comfortable within LW.
About pntOtherPos you're right, but in my case I need the positions of vertex cache animated meshes, so pntBasePos was not working for me.

04-20-2013, 09:54 PM
I updated the script so it would be able to rename mesh objects, but it crashes Layout.
The full script can be found here:

Here's the "crashy" section

if ChangeAllMeshes:
lwsdk.command("SaveObject %s" % newfullpath)
#only works once - second time causes crash
#if only one instance of mesh crashes on first attempt
print newfullpath
lwsdk.command("SaveObjectCopy %s" % newfullpath)
#lwo is saved so the next command causes the crash
if os.path.exists(newfullpath):
lwsdk.command("ReplaceWithObject %s" % newfullpath)

The first case works without any problems. A new lwo file is created and all the meshes get renamed.

The problem seems to be with the ReplaceWithObject command, because the new lwo file gets written by the SaveObjectCopy then I get a crash.
If there are several copies of the mesh in the scene it will work one time. The second time it will crash.
If there is only one copy of the mesh in the scene it will crash on the first attempt.

Anyone have any ideas?

04-24-2013, 11:19 AM
I never found the reason for the crash. I put the command in a generic script and it worked without crashing. After several random tests I found a workaround that requires one more user click.

For the case where the "Change all mesh instances when renaming" is unchecked only one selected mesh gets renamed. It does a SaveObjectCopy and writes the ReplaceWithObject command to a global variable and applies a check to a checkbox. The user presses the checkbox and the ReplaceWithObject command is run without crashing Lightwave.

ChangeAllMeshes = (self._ctrl_MeshScope.get_int() == 1)
if ChangeAllMeshes:
lwsdk.command("SaveObject %s" % newfullpath)
#save old object to trigger event - nope event lost/ignored
#lwsdk.command("SaveObject %s" % fullpath)
lwsdk.command("SaveObjectCopy %s" % newfullpath)

if os.path.exists(newfullpath):
#command works but causes CRASH here
#lwsdk.command("ReplaceWithObject %s" % newfullpath)
cmdstring = "ReplaceWithObject %s" % newfullpath
doreplace = True
self._ctrl_ReplaceObject.set_int(1 if doreplace else 0)
#save old object to trigger event - nope = CRASH
#lwsdk.command("SaveObject %s" % fullpath)

ignorechange = True

callback to run the second half of the rename:

def replaceobject_event(self, control, userdata):
global cmdstring
if cmdstring == '':
doreplace = False
self._ctrl_ReplaceObject.set_int(1 if doreplace else 0)

cmdstring = ''
doreplace = False
self._ctrl_ReplaceObject.set_int(1 if doreplace else 0)

02-18-2014, 02:12 PM
Just updated the script to version 1.8, this adds pivot information to the panel.

Does anyone know of a method to press a button or activate a shortcut from script? I would like to have the "record pivot rotation" added to the panel. LScriptCommander shows a bunch of commands running when you use it, so I don't think I can use that.