Hi guys!
I'm trying to create spline outline generator. All is going good, but the resulted spline is invisible for Snapping tool. Even after placing the result directly under the generator (InsertUnder(op)) . It is only working if I'll select the result spline.
Is it something connected to generator cache?
Unsolved Can't snap to Generator output spline
Hello @Madara ,
Welcome to the Plugin Café forum and the Cinema 4D development community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our Forum and Support Guidelines, as they line out details about the Maxon SDK Group support procedures. Of special importance are:
- Support Procedures: Scope of Support: Lines out the things we will do and what we will not do.
- Support Procedures: Confidential Data: Most questions should be accompanied by code but code cannot always be shared publicly. This section explains how to share code confidentially with Maxon.
- Forum Structure and Features: Lines out how the forum works.
- Structure of a Question: Lines out how to ask a good technical question. It is not mandatory to follow this exactly, but you should follow the idea of keeping things short and mentioning your primary question in a clear manner.
About your First Question
Without your code we cannot do much here, I would recommend having a look at our forum guidelines (as explained above). If I had to take a guess, I would say you are probably overwriting ObjectData.GetVirtualObjects
instead of .GetContour
or you are missing the OBJECT_ISSPLINE
flag when calling RegisterObjectPlugin
, causing either your object not being recognized as a spline or having a malformed cache.
When you implement a spline using GetVirtualObjects
, the cache of that object will be a SplineObject
, or in other words the object itself won't be a spline. When you implement it via .GetContour
, the cache will be a LineObject
(which is the correct cache node type for a spline).
If you got a bit confused by this, you could easily test this in the console by calling GetCache()
on an instance of your plugin. In the example below I compare the cache of a Python generator object which returns a SplineObject
(which would be an example for such faux spline implemented using .GetVirtualObjects
) and a SplineObject
. Although they might look identical in the viewport, they are not the same under the hood.
MAXON SDK Specialist
developers.maxon.net
Hi @ferdinand !
Thank you for your response. It has to be the issue then. Is it possible to convert SplineObject to LineObject somehow?
Here's my code so far:
def main():
parent = c4d.BaseObject(c4d.Onull)
distance= op[c4d.ID_USERDATA,10]
custom_distance=op[c4d.ID_USERDATA,1]
link=op[c4d.ID_USERDATA,5]
spline_color=op[c4d.ID_USERDATA,9]
outline_only=op[c4d.ID_USERDATA,2]
hide_input=op[c4d.ID_USERDATA,3]
outline_color=op[c4d.ID_USERDATA,8]
final_distance=5
if distance == 0 :
final_distance=5
elif distance == 1 :
final_distance=8
elif distance==2:
final_distance=custom_distance
link_clone = link.GetClone()
connect_obj = c4d.BaseObject(c4d.Oconnector)
link_clone.InsertUnder(connect_obj)
if link_clone: #Parametric object
pobj = u.SendModelingCommand(
command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
list = [connect_obj],
mode = c4d.MODELINGCOMMANDMODE_ALL,
doc = op.GetMain())
connect_obj = pobj[0]
if outline_only:
bc = c4d.BaseContainer()
settings = c4d.BaseContainer() # Settings
settings[c4d.MDATA_SPLINE_OUTLINE] = final_distance # Distance
settings[c4d.MDATA_SPLINE_OUTLINESEPARATE] = True #Crée un nouvel objet
offspline = u.SendModelingCommand(
c4d.MCOMMAND_SPLINE_CREATEOUTLINE,
[connect_obj],
c4d.MODELINGCOMMANDMODE_ALL,
bc=settings,
doc=doc)
if offspline :
offspline[0].InsertUnder(parent)
offspline[0][c4d.ID_BASEOBJECT_USECOLOR] = 2 # Use Object ColorSpline
offspline[0][c4d.ID_BASELIST_ICON_COLORIZE_MODE]=2
offspline[0][c4d.ID_BASEOBJECT_COLOR] = outline_color # Red Color
# Convert the spline to a line (edges) using a Modeling Command
return offspline[0]
if not outline_only:
#settings[c4d.MDATA_SPLINE_OUTLINESEPARATE] = True #Crée un nouvel objet
#connect_obj = c4d.BaseObject(c4d.Oconnector)
bc = c4d.BaseContainer()
bc.SetData(c4d.MDATA_SPLINE_OUTLINE, final_distance)
offspline = u.SendModelingCommand(
c4d.MCOMMAND_SPLINE_CREATEOUTLINE,
[connect_obj],
c4d.MODELINGCOMMANDMODE_ALL,
bc)
return connect_obj.GetClone()
I'm inputting a null with multiple splines as children, then I put it under Connect object, simplify it, run outline command and get the result.
Hey @Madara,
in short, a Python generator object is not meant to generate splines. You can collapse the cache of your constructed spline and return its LineObject
cache instead of the spline itself. For an example, see [1]. In your case that would be connect_obj
. This will work in the sense that the generator cache will be then like a SplineObject
cache and when you 'Current State to Object' your generator, it will behave like a spline and give you the interpolated editable linear spline and not a spline generator.
However, spline snapping not only inspects caches, but also checks if OBJECT_ISSPLINE
is true. So, you cannot bamboozle it by faking a SplineObject
cache. You will have to implement a proper spline plugin for what you want to do, as you can overwrite there GetContour
Cheers,
Ferdinand
PS: Your code contains multiple elements that can crash Cinema 4D and/or corrupt the loaded document. Specifically, these sections:
if link_clone: #Parametric object
pobj = u.SendModelingCommand(
command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
list = [connect_obj],
mode = c4d.MODELINGCOMMANDMODE_ALL,
doc = op.GetMain())
connect_obj = pobj[0]
...
offspline = u.SendModelingCommand(
c4d.MCOMMAND_SPLINE_CREATEOUTLINE,
[connect_obj],
c4d.MODELINGCOMMANDMODE_ALL,
bc=settings,
doc=doc)
A Python generator's main()
function is subject to the threading restrictions of Cinema 4D because it is just a wrapper for ObjectData.GetVirtualObjects
. Executing SendModelingCommand
in a threaded context is fine, but you cannot do it on the active document (both doc
and op.GetDocument()
are the active document). This is here even worsened by the fact that that the objects in list
are not actually part of the document you pass as doc
.
To circumvent that you must create your own document just as I have in [1] with temp
. Find a more detailed example of that technique in smc_extrude_s26.py.
[1]
import c4d
op: c4d.BaseObject # The Python generator object.
def main() -> c4d.BaseObject:
"""
"""
# A user data Boolean to toggle collapsing the cache of this generator.
collapse: bool = op[c4d.ID_USERDATA, 1]
spline: c4d.BaseObject = c4d.BaseObject(c4d.Osplinecircle)
if not spline:
return c4d.BaseObject(c4d.Onull)
# Just return the circle spline itself when #collapse is false.
if not collapse:
return spline
# Otherwise grab the LineObject cache of the spline and return a copy of it.
temp: c4d.documents.BaseDocument = c4d.documents.BaseDocument()
temp.InsertObject(spline)
temp.ExecutePasses(c4d.threading.GeGetCurrentThread(), False, False, True, c4d.BUILDFLAGS_NONE)
cache: c4d.LineObject | None = spline.GetCache()
if not isinstance(cache, c4d.LineObject):
return c4d.BaseObject(c4d.Onull)
return cache.GetClone(c4d.COPYFLAGS_NONE)
MAXON SDK Specialist
developers.maxon.net