Hey @baca,
- I didn't shared whole code here, but in GVO I'm also caching the spline as self._spline property and in GetSpline method I'm returning self._spline.GetClone()
When dealing with child input object GetAndCheckHierarchyClone has no alternatives except weird combination of CSTO + Touch()
Hm, that is sometimes true, but at least from your example code this was not obvious. And I would make if this is really the only way to go. There come penalties with implementing a spline in this manner, the major one being, that you will always have another layer of caches, which in turn will impact other things. A node which implements a spline via GetVirtualObjects
will return a SplineObject
as its cache (or part of its cache). This SplineObject
will then a have a LineObject
cache. A node which implements a spline via GetContour
, will return a LineObject
directly.
- So, the solution might be to draw tiny polygons with gradient in vertex colors? Any suggestion for draw pass in that case - DRAWPASS_OBJECT or DRAWPASS_HANDLER?
Current issue is that my object is drawn automatically, and I have no idea if I can prevent automatic drawing. I can render custom color only in the case my object is not selected.
Yes, sort of. I was thinking more of line segments than polygons, but that is the general idea. I would also not draw in object space, but in screen space, to be as efficient and smooth as possible. When you draw in object space, and you choose the spacing to wide, the gradient will be visibly segmented when projected to pixel screen space. When you choose the spacing to tightly in object space, you will end up with many unnecessary drawing operations which are not going to be visible in screen space anyways.
The drawpass in which you should be drawing depends on what you want to do, but usually DRAWPASS_OBJECT
is the one to go. The more important information is here the z-depth for drawing the line segments, which should be 4
or greater, so that the line segments are drawn over shaded polygons and other stuff.
But I would here point again that Python is not a good match for this task due to performance restrictions. If your splines are simple and drawing a gradient for them just means <= 10,000 draw calls in screen space, you will be fine in Python. But when your splines are complex, and drawing a gradient for them means drawing 100,000s of pixels (i.e., draw calls), Python will bottleneck you hard. The old viewport API is not the fastest even in C++, so such complex tasks should really be done there. I would suggest drawing only the vertices in Python and expressing the direction of the spline by colouring the vertices.
PointObject::DisplayPoints
is only available under C++? Didn't found any references in both Py and Cpp documentation
As I said, this method is non-public. Some of the public interfaces/types have non-public methods. I simply pointed out that we use this method internally, and that it does a lot of things regarding displaying vertices in the viewport. So, when you implement a OBJECT_POINTOBJECT
ObjectData
plugin, it is somewhat intended from the internal perspective that you use then ::DisplayPoints
. I was simply informing you that the inaccessibility of DisplayPoints
is one of the obstacles you must overcome.
- Yeah, thanks for suggestion to not store source line, as it's not reflecting further deformer changes. But I found that Draw is called so frequent, and converting spline to line takes sufficient time, so it becomes uncomfortable to work with.
When you implement your spline in GetContour
this will be more straight forward, as the cache will then be directly the line-object, but you can do more or less the same withGetVirtuaalObjects
, you only must deal with a slightly more complex cache then. But it should beat storing and retrieving the data manually in any case.
- I wanted to render vertices and spline direction not for manipulation, but for visual check.
And thought to implement point selection feature for selection tag creating, maybe.
I have provided a very simple pattern for that at the end. I did not implement the selecting, creating, and moving vertices stuff, as this would be quite a bit of work. I also went the route of shading the vertices and not the line segments, as this is much simpler to do :)
Cheers,
Ferdinand
The result:

The code:
import c4d
class EditableSplineData(c4d.plugins.ObjectData):
def Draw(self, op, drawpass, bd, bh):
"""
"""
if drawpass != c4d.DRAWPASS_OBJECT:
super().Draw(op, drawpass, bd, bh)
# Only display the vertices when the object is selected.
if (not op.GetBit(c4d.BIT_ACTIVE)):
return c4d.DRAWRESULT_OK
cache = op.GetCache()
if not isinstance(cache, c4d.LineObject):
return c4d.DRAWRESULT_OK
# Draw in object space with a zoffset of 4 over most things Cinema 4D will draw as polygons,
# edges, and vertices.
bd.SetMatrix_Matrix(op, op.GetMg(), zoffset=4)
# Now we simply will draw a dot for each vertex in the LineObject, with a gradient going
# from the first vertex to the last vertex. Note that we are drawing the vertices of the
# LineObject, not the ones of the SplineObject. I.e., we are not drawing the control
# vertices of the spline, but the actual vertices which have been interpolated between the
# control vertices. In this case we will draw 3 * 64 vertices, since we define 4 control
# points of a non-closed spline (i.e., 3 segments between them) and a uniform interpolation
# of 64.
count = cache.GetPointCount()
cStart = c4d.Vector(1, 0, 0)
cEnd = c4d.Vector(0, 0, 1)
colors = []
# We are going to use a single draw call for doing this, DrawPoints, which also allows for
# drawing each point in a different color. But it expects the colors in a bit annoying
# format as an array of floats: [r, g, b, r, g, b, r, g, b, ...].
for i in range(count):
ci = c4d.utils.MixVec(cStart, cEnd, i / count)
colors += [ci.x, ci.y, ci.z]
# Draw all points in one go, this is very performant.
bd.SetPointSize(4)
bd.DrawPoints(vp=cache.GetAllPoints(), vc=colors, colcnt=3)
return super().Draw(op, drawpass, bd, bh)
def GetContour(self, op, doc, lod, bt):
"""
"""
# I am not going to comment the geometry construction I am doing here. For details on
# polygon and spline generation, see https://bit.ly/3lxBBlt
node = c4d.SplineObject(4, c4d.SPLINETYPE_LINEAR)
size = 100.0
node.SetAllPoints([c4d.Vector(0, 0, 0),
c4d.Vector(size, 0, 0),
c4d.Vector(size, size, 0),
c4d.Vector(0, size, 0)])
node.Message(c4d.MSG_UPDATE)
# I am just going to be lazy and not tie all the interpolation parameters in and instead
# set them manually here.
node[c4d.SPLINEOBJECT_INTERPOLATION] = c4d.SPLINEOBJECT_INTERPOLATION_UNIFORM
node[c4d.SPLINEOBJECT_SUB] = 64
return node
if __name__ == "__main__":
c4d.plugins.RegisterObjectPlugin(
id = 1000001,
str = 'Editable Spline',
g = EditableSplineData,
description = "oeditspline",
icon = None,
info = c4d.OBJECT_GENERATOR | c4d.OBJECT_ISSPLINE)