SOLVED Colors on a generator

Hi,

my generator object returns geometry (a PolygonObject) from ObjectData::GetVirtualObjects(). Pretty standard. Now I want to color the object, so it doesn't look just grey by default.

The most obvious answer to this would probably be vertex colors. Therefore, I am attaching a VertexColorTag to the geometry and fill its data.

Sadly, the vertex colors are not visible. If I convert my generator with "c", and then select the VertexColorTag on the resulting PolygonObject, the colors are displayed fine. But is there a way to show them, while the PolygonObject and its VertexColorTag are still in my generator's cache?

And if that's not possible, is there any other way to have default colors on an object that I return from a generator?

Thanks in advance & greetings,
Frank

Actually, after playing with this a little, I decided not to use Vertex Colors, because the Vertex Colors display does no shading.

So, let me rephrase my question:

How would I achieve colouring my plugin object on a per-vertex basis, and display it in the viewport with shading?

Thanks in advance,
Frank

hi,

This is the same issue than this thread
are you using c++ or python ? With c++ you could use CustomDataTag to store your information and use them in your own shader.

Cheers,
Manuel

Sorry, forgot about the tags. Added now.
It's C++.

So, as I see from that other thread, my options are pretty limited.

For my purpose, drawing must be fast (millions and millions of polygons), and it should not require the user to create and attach a material to the object. I guess it's not possible to have a hidden material in the document and attach a hidden TextureTag to the object, right?

Cheers,
Frank

There is a way to have an invisible material in the document... The "Active Object Dialog" example plugin from cinema4dsdk reveals that there's an invisible Sky Material in the document when a Physical Sky Object is created 🙂 Can I do that with a standard material, too?

Cheers,
Frank

hi,

sorry i read too fast, you want to color your objects so you can use OBJECT_USECACHECOLOR when you register your generator. So you will be able to define a color for each object.

Cheers,
Manuel

Unfortunately, that's not enough. I need arbitrary colors on the object's surface. Vertex colors would've been ideal, but they don't appear if the Vertex Color Tag is inside my generator's cache. Or would OBJECT_USECACHECOLOR allow me to have the vertex colors appear in the viewport?

Anyway, doesn't really make a difference. Vertex colors are only drawn without shading. Therefore, I would very much prefer the SkyObject-like solution with the hidden material.

Edit:
I just realise, it should be possible to hide material and texture tag with GeListNode::ChangeNBit(OHIDE). Maybe that already solves my problem 🙂 Will try tomorrow.

Thanks,
Frank

Hello Frank,

we will answer this more thoroughly tomorrow, but the trick when providing a vertex color map in a cache, is to select it, as this is the condition for Cinema to draw it. For your "moved goal posts" of having a shader/material, this can become tricky, because as providing materials is not an intended functionality for generator caches. But you probably know that.

The common workaround is then to assign the material to the generator and not the cache and hide the material as you already said yourself. But when you are going to rely on vertex colors, you are going to have a problem, I think. The problem is that you cannot assign the vertex color tag to the generator, as this won't work. Vertex color tags seem to be unable to reach into caches, I just tried. So, you will have to keep the vertex color tag on the cache. You can then still create just your material with a vertex map shader in it to do all your fancy shading and assign it to the generator (and hide it). The problem is: The vertex color shader would then have to reach/link into the cache to get the tag from there. Which I think should work in principal, have not tried myself though, but is obviously the definition of "dicey".

Cheers,
Ferdinand

PS: This is a "private" answer of mine, just because I thought it is an interesting problem ^^

e554a78d-262c-47ea-a1b6-d6dffaa63ffd-image.png

import c4d
import random

def CreateVertexColors(node):
    """
    """
    # Pretty straight forward per vertex definition of vertex colors.
    count = node.GetPointCount()
    tag = c4d.VertexColorTag(count)
    tag.SetPerPointMode(True)
    data = tag.GetDataAddressW()

    for pid in range(count):
        color = c4d.Vector4d(random.uniform(0., 1.),
                             random.uniform(0., 1.),
                             random.uniform(0., 1.), 1.)
        c4d.VertexColorTag.SetPoint(data, None, None, pid, color)

    # Add the tag and the magic bit, quite literately, select it.
    node.InsertTag(tag)
    tag.SetBit(c4d.BIT_ACTIVE)

def main():
    """
    """
    # Get our cache source, cause I was to lazy to come up with some geom. :)
    source = op[c4d.ID_USERDATA, 1]
    if not isinstance(source, c4d.PolygonObject):
        return c4d.BaseObject(c4d.Onull)

    # Clone the cache source and create a vertex color map for it.
    cache = source.GetClone(0)
    cache.SetMg(c4d.Matrix())
    CreateVertexColors(cache)

    return cache

Thank you, Ferdinand!

Since the Sky Object is using the trick with the hidden material, I think it is an adequate method of solving this. The material just needs to be created when the object is created, kept track of and updated with changed parameters, and then removed when the object is removed. I'll see to that and will be back if more questions arise.

Cheers,
Frank

Hi Frank,

okay 🙂 And in retrospective I also see me misunderstanding something here in my answer on the weekend. I thought vertex colors were a requirement, but they were actually just one way you did consider for providing color information, right? If this is the case, then writing a custom shader and hiding the material it is attached to, should work fine.

Cheers,
Ferdinand

Hi Ferdinand,

thanks for your answer! What would the standard way of maintaining such a hidden material look like?

Something like this, I guess:

  • When plugin object is created:
    • Create material
    • Hide material (NBIT_OHIDE)
    • Create texture tag on plugin object and link material
    • Hide texture tag
    • Store a BaseLink to the material as object class member
  • If anything changes in the plugin object:
    • Get pointer to material from BaseLink
    • Update material with new data
  • When plugin object is removed:
    • Remove and free material

But when is the right moment for creating and freeing the material? Doing it in ObjectData::Init() does not work, because a) that function is called quite often, and b) when Init() is called on object creation, the node pointer is NULL.
I also tried MSG_DOCUMENTINFO with type MSG_DOCUMENTINFO_TYPE_OBJECT_INSERT, but it's not called when the object is added to the document.

How does the Sky Object solve this?

Cheers,
Frank

Hi,

Well, the sky object Have a special command. The object itself and the material are hidden. The command does create the skyobject and insert it in the document. It also creates the Material. The Material Object does in its Init function set the Bit Ohide. and the SkyObject does Alloc a BaseLink in its InitFunction.
The command than retrieve the ObjectData using GetNodeData and set the baselink to the material.

The material is never deleted.

The hierarchy and the material tag should be created inside GetVirtualObject.
I would try to make the material visible if you make the object Editable. You can check the message MSG_EDITABLE_END.

You may also need MSG_MULTI_MARKMATERIALS MSG_DESCRIPTION_INITUNDO if you want to add an undo to the material stack if you change it after your object have been update.

Hope you have enough to solve your problem 🙂

Cheers,
Manuel.

Thank you, Manuel! I'll try that!

Cheers,
Frank

Hello @fwilleke80,

without further questions or postings, we will consider this topic as solved by Wednesday and flag it accordingly.

Thank you for your understanding,
Ferdinand