On 22/11/2016 at 15:32, xxxxxxxx wrote:
Hi,
1. How do I hide my child input objects? I'm using Touch() in GetContour() but it only works when I'm editing the child-objects.
2. How do I ensure that grandchildren don't reappear when nested in another generator?
I've created a simplified example plugin demonstrating my issues:
BitBucket Snippet of ScaleSplineObject.pyp
And, while harder to read, here's the full source embedded:
"""Scale Spline Object
Takes a child-spline as input and scaled it's point's down by 50%. Tangents are unaffected.
v0.0.1
by Donovan Keith <[email protected]>
Usage Instructions
------------------
1. Save in a file called ScaleSplineObject.pyp
2. Place in C4D Plugins director
3. Restart C4D
4. Plugins > Scale Spline Object
5. Add an NSide spline
6. Make the NSide spline a child of the Scale Spline Object.
Outstanding Issues
-------------------
- [ ] Nested child objects aren't properly hidden. To recreate:
ScaleSpline
|
-- Scale Spline
|
-- NSide
- [ ] GetDirty() probably needs to be reimplemented.
"""
# =====================================================================================================================#
# Imports
# =====================================================================================================================#
import c4d
# =====================================================================================================================#
# Class Definitions
# =====================================================================================================================#
class ScaleSplineObject(c4d.plugins.ObjectData) :
PLUGIN_ID = 1038342 # TODO: Replace with your own ID from PluginCafe.com
def __init__(self) :
self.last_child = None
def Init(self, op) :
return True
def ConversionCommand(self, op, command_id) :
"""Allows you to easily perform a MakeEditable or CSTO on an object.
reference: https://plugincafe.maxon.net/topic/5237/5232_python-make-object-editable
Returns early if op is a Spline
"""
if op is None:
return
op_clone = op.GetClone()
if op_clone is None:
return
# Is it a spline? No need to convert.
if op_clone.CheckType(c4d.Ospline) :
return op_clone
# Perform the MakeEditable or CSTO in temporary document
temp_doc = c4d.documents.BaseDocument()
if not temp_doc:
return
temp_doc.InsertObject(op_clone)
result_list = c4d.utils.SendModelingCommand(command=command_id,
list=[op_clone],
doc=temp_doc)
# Did anything go wrong? Bail
if not result_list:
return
# Return the first object in the result list
return result_list[0]
def MakeEditable(self, op) :
"""Returns a clone of `op` that's been made editable. Can return None."""
return self.ConversionCommand(op, command_id=c4d.MCOMMAND_MAKEEDITABLE)
def CurrentStateToObject(self, op) :
"""Returns a clone of the current state of `op`. Can return None."""
return self.ConversionCommand(op, command_id=c4d.MCOMMAND_CURRENTSTATETOOBJECT)
def GetAsSpline(self, op) :
"""Clones object as a c4d.Ospline - using the following priority
* Object if Spline
* Object Made Editable, if Spline
* Current State to Object, if Spline
Note: MakeEditable won't account for deformed splines, however, it will give you a spline
with fewer points which is preferable to CSTO for a lot of modeling operations.
"""
if op is None:
return
# Return op if it's a spline
if op.CheckType(c4d.Ospline) :
return op.GetClone()
# Make it editable if it is.
made_editable = self.MakeEditable(op)
if made_editable is not None:
if made_editable.CheckType(c4d.Ospline) :
return made_editable
# Peform a CSTO if need be
# TODO: See if this ever actually executes, probably doesn't
current_state = self.CurrentStateToObject(op)
if current_state is not None:
if current_state.CheckType(c4d.Ospline) :
return current_state
def LocalizeSpline(self, op, spline) :
"""Converts all of `spline`'s point to local space for `op`
This is necessary because GetContour assumes the spline is in the same
location as the object itself.
"""
# Verify Inputs
if (op is None) or (spline is None) :
return
# Get points
spline_points = spline.GetAllPoints()
if not spline_points:
return
has_tangents = (spline.GetTangentCount() > 0)
spline_tangents = []
# Retrieve matrices for conversion math
spline_mg = spline.GetMg()
if not spline_mg:
return
op_mg = op.GetMg()
if not op_mg:
return
inverse_op_mg = ~op_mg
# Localize all points
for i, spline_point in enumerate(spline_points) :
global_point = spline_point * spline_mg
local_point = global_point * inverse_op_mg
spline_points[i] = local_point
# Calculate new tangent positions
if has_tangents:
# Get tangents for point
tangent = spline.GetTangent(i)
vl = tangent["vl"]
vr = tangent["vr"]
# Transform tangents into their global locales
global_vl = (spline_point + vl) * spline_mg
global_vr = (spline_point + vr) * spline_mg
# Transform tangents from global points to point-local vectors.
vl = (global_vl * inverse_op_mg) - local_point
vr = (global_vr * inverse_op_mg) - local_point
# Store the updated points & tangents.
spline_tangents.append((vl, vr))
spline.SetTangent(i, vl, vr)
# Neutralize spline's Matrix
spline.SetMg(op_mg)
# Restore spline to previous positions
spline.SetAllPoints(spline_points)
# Update tangent positions as well
for i, tangent in enumerate(spline_tangents) :
vl, vr = tangent
spline.SetTangent(i, vl, vr)
def CheckDirty(self, op, doc) :
"""Marks the object as dirty if it's child object has been modified."""
if not op:
return
# Is there a new or missing child object?
child = op.GetDown()
if child != self.last_child:
# Dirty!
self.last_child = child
op.SetDirty(c4d.DIRTY_DATA)
return
# Can't do anythng without a child object.
if child is None:
return
# Has the child ben modified?
if child.IsDirty(c4d.DIRTYFLAGS_MATRIX |
c4d.DIRTYFLAGS_DATA |
c4d.DIRTYFLAGS_CHILDREN) :
# Dirty!
op.SetDirty(c4d.DIRTYFLAGS_DATA)
def ModifySpline(self, spline) :
"""Scales all spline points down by 50%"""
point_scaling_factor = 0.5
if spline is None:
return
spline_points = spline.GetAllPoints()
if spline_points is None:
return
for i, spline_point in enumerate(spline_points) :
spline_points[i] = spline_point * point_scaling_factor
spline.SetAllPoints(spline_points)
def GetContour(self, op, doc, lod, bt) :
"""Return the result of the generator spline."""
# Create an Empty Spline
if not op:
return
# Retrieve the child input object
child = op.GetDown()
if child is None:
return
# Tell C4D the child is a generator input object and should be hidden.
child.Touch()
# Get the child input object as a spline clone we can modify.
result_spline = self.GetAsSpline(child)
if result_spline is None:
return
# Scale down the spline points.
self.ModifySpline(result_spline)
# Ensure the spline points are localized to this generator's PSR.
self.LocalizeSpline(op, result_spline)
return result_spline
# =====================================================================================================================#
# Registration
# =====================================================================================================================#
if __name__ == "__main__":
c4d.plugins.RegisterObjectPlugin(id=ScaleSplineObject.PLUGIN_ID,
str="ScaleSplineObject",
g=ScaleSplineObject,
description=None,
icon=None,
info=c4d.OBJECT_GENERATOR | c4d.OBJECT_INPUT | c4d.OBJECT_ISSPLINE)
Thanks!