Solved Python Effector as Deformer w/ Fields shows in viewport but does not render

As soon as I add a field to a Python Effector with deform mode enabled, the poly object will no longer be affected by the deform when rendered. However, it renders in the viewport just fine?

Am I missing something obvious?

Thanks for the help!

c4d version 2023.2.1

rnd_PyEffDeformerWithField_NotShownInRender.c4d


edited by @ferdinand:

Code:

import c4d

op: c4d.BaseObject # The python effector
gen: c4d.BaseObject # The MoGraph Generator executing the effector
doc: c4d.documents.BaseDocument # The document evaluating this effector
thread: c4d.threading.BaseThread # The thread executing this effector

def main() -> bool:
    # Called when the effector is executed to set MoGraph data. Similar to EffectorData::ModifyObject in C++.
    moData = c4d.modules.mograph.GeGetMoData(op)
    if moData is None:
        return False

    cnt = moData.GetCount()
    marr = moData.GetArray(c4d.MODATA_MATRIX)

    hasField = op[c4d.FIELDS].HasContent()
    fall = moData.GetFalloffs()

    for i in range(0, cnt) :
        if hasField:
            if i%4 == 0:
                marr[i].off = marr[i].off + fall[i] * 1.0
        else:
            if i%4 == 0:
                marr[i].off = marr[i].off + 1.0

    moData.SetArray(c4d.MODATA_MATRIX, marr, hasField)
    return True

@jenandesign said:

uh oh, maybe this still hasn't been fixed?

Feb 2020: https://plugincafe.maxon.net/topic/12325/python-effector-full-control-has-no-effect-during-render

Nov 2020: https://plugincafe.maxon.net/topic/13006/python-effector-not-working-with-fields

The workaround described in another report about this is to use the MoGraph Cache object. Sadly, that only works for MoGraph objects and not deformed polygon objects. Hopefully, a fix is around the corner crosses fingers

Hello @jenandesign,

Thank you for reaching out to us. Please make sure to consolidate updates to an initial question into a single posting in the future. It makes it much easier for others to explore a topic. And while providing a scene file is much appreciated, we must insist on code also being shared in the thread, so that others can evaluate a topic quickly. I have done it here for you.

About your Question

You are right, this is indeed related to the bug you mentioned. Unfortunately, the bug has not been fixed. I gave the ticket a little bump and marked this thread as to_fix, so that we can track the issue more closely.

In the meantime, you could put the effector in Parameter Control mode where this problem does not occur. One is here limited to adjusting the transform which has been defined under Paramater of the effector, but adjusting a fixed transform by the index of a clone is entirely possible.

a74eb64a-7820-439e-9684-17a20f9d395f-image.png

Cheers,
Ferdinand

File: rnd_modulo.c4d
Code:

"""Demonstrates how to only transform particles at a certain index with a Python Effector in 
Parameter Control mode.
"""
import c4d
import math

op: c4d.BaseObject # The Python Effector

def Hash11(x: float, seed: float = 1234., magic: tuple[float]=(1234.5678, 98765.4321)) -> float:
    """Returns for #x a pseudo random float hash in the interval [-1, 1].

    We could also use random of Python for that, but we would have to initialize the hash table for 
    each call with random.seed(particleIndex) to ensure a persistent result, which would be VERY 
    slow.
    """
    return math.modf(math.sin((x + seed) * magic[0]) * magic[1])[0]

def Hash13(x: float, seed: float = 1234., magic: tuple[float]=(1234.5678, 98765.4321)) -> c4d.Vector:
    """Returns for #x a pseudo random vector hash in the interval [(-1, -1, -1), (1, 1, 1)].
    """
    xc: float = Hash11(x)
    yc: float = Hash11(x + xc)
    zc: float = Hash11(x + yc)
    return c4d.Vector(xc, yc, zc)

def main() -> c4d.Vector | float | int:
    """Runs the example.
    """
    # Get the MoGraph data for the effector. 
    moData: c4d.modules.mograph.MoData | None = c4d.modules.mograph.GeGetMoData(op)
    if moData is None:
        return 1.0

    # For all particles in the position array ...
    if moData.GetBlendID() == c4d.ID_MG_BASEEFFECTOR_POSITION:
        # apply only the transform to each 4th particle in the array. We also do some randomness,
        # as your file name seemed to imply that this was your goal.
        pi: int = moData.GetCurrentIndex()
        return Hash13(pi) if (pi % 4 == 0) else c4d.Vector(0)

    return 1.0

MAXON SDK Specialist
developers.maxon.net

Hello @jenandesign,

Thank you for reaching out to us. Please make sure to consolidate updates to an initial question into a single posting in the future. It makes it much easier for others to explore a topic. And while providing a scene file is much appreciated, we must insist on code also being shared in the thread, so that others can evaluate a topic quickly. I have done it here for you.

About your Question

You are right, this is indeed related to the bug you mentioned. Unfortunately, the bug has not been fixed. I gave the ticket a little bump and marked this thread as to_fix, so that we can track the issue more closely.

In the meantime, you could put the effector in Parameter Control mode where this problem does not occur. One is here limited to adjusting the transform which has been defined under Paramater of the effector, but adjusting a fixed transform by the index of a clone is entirely possible.

a74eb64a-7820-439e-9684-17a20f9d395f-image.png

Cheers,
Ferdinand

File: rnd_modulo.c4d
Code:

"""Demonstrates how to only transform particles at a certain index with a Python Effector in 
Parameter Control mode.
"""
import c4d
import math

op: c4d.BaseObject # The Python Effector

def Hash11(x: float, seed: float = 1234., magic: tuple[float]=(1234.5678, 98765.4321)) -> float:
    """Returns for #x a pseudo random float hash in the interval [-1, 1].

    We could also use random of Python for that, but we would have to initialize the hash table for 
    each call with random.seed(particleIndex) to ensure a persistent result, which would be VERY 
    slow.
    """
    return math.modf(math.sin((x + seed) * magic[0]) * magic[1])[0]

def Hash13(x: float, seed: float = 1234., magic: tuple[float]=(1234.5678, 98765.4321)) -> c4d.Vector:
    """Returns for #x a pseudo random vector hash in the interval [(-1, -1, -1), (1, 1, 1)].
    """
    xc: float = Hash11(x)
    yc: float = Hash11(x + xc)
    zc: float = Hash11(x + yc)
    return c4d.Vector(xc, yc, zc)

def main() -> c4d.Vector | float | int:
    """Runs the example.
    """
    # Get the MoGraph data for the effector. 
    moData: c4d.modules.mograph.MoData | None = c4d.modules.mograph.GeGetMoData(op)
    if moData is None:
        return 1.0

    # For all particles in the position array ...
    if moData.GetBlendID() == c4d.ID_MG_BASEEFFECTOR_POSITION:
        # apply only the transform to each 4th particle in the array. We also do some randomness,
        # as your file name seemed to imply that this was your goal.
        pi: int = moData.GetCurrentIndex()
        return Hash13(pi) if (pi % 4 == 0) else c4d.Vector(0)

    return 1.0

MAXON SDK Specialist
developers.maxon.net

Hello @jenandesign ,

without further questions or postings, we will consider this topic as solved by Friday, the 11th of august 2023 and flag it accordingly.

Thank you for your understanding,
Maxon SDK Group