@ferdinand You are correct, there was no further question, I was just closing the loop in case someone else ran into something similar. Thanks for the additional suggestions.
-v
Best posts made by vhardy
-
RE: Apparently incorrect matrices in Python effector when subject to deformer
Latest posts made by vhardy
-
RE: Apparently incorrect matrices in Python effector when subject to deformer
@ferdinand You are correct, there was no further question, I was just closing the loop in case someone else ran into something similar. Thanks for the additional suggestions.
-v -
RE: Apparently incorrect matrices in Python effector when subject to deformer
@ferdinand Hello,
My question was whether or not I was doing something incorrect in my effector code, and after reading your message, I understand that what I did not account for was the processing order of the generators, effectors and deformers. The effector being called before deformers apply, I could not expect to get the result I wanted. Thanks for making that clear to me.I worked on the example you sent because I wanted to make sure my effector worked generally, i.e., with any geometry that has its normal along the positive z axis, and avoid having to special-case my effector to a particular cloner it applies to. I illustrated this in normal-effector-axis-test-v1.c4d:
The effector you sent and the original one are applied to simple geometry. On the left is the original effector (working with z-axis), on the right in the effector in the example you sent which compensated for a rotation in the cloner (which uses the negative x-axis).I modified the example so I can use the original effector working with the regular surface normal (on Z) with the technique your sent for generating geometry that let's me control the normals as I need them. This is the attached normal-effector-axis-test-v2.c4d
On the left is the geometry you sent with my effector, just modifying the cloner to not apply a 90 degree rotation on H. The colors are the opposite because I have yellow for light and red for dark and yours has the opposite as you explained in your message.
@ferdinand said in Apparently incorrect matrices in Python effector when subject to deformer:
You do not take the position of the light source into account, , which does not make that much sense to me for a directed not-infinitely-distant light source as you use there, but maybe I am misunderstanding your goals.
Yes, that is correct, I am using an infinite light in my project, so that is why I keep my effector using the direction of the light (also an infinite light in my project / test file).
Thanks for the explanations, examples and pointers. The examples on ray tracing are of particular interest as I have a poor man's version of that in the full version of my effector which works as I was hoping, but can probably be improved in many ways. So that will be helpful. I have also not gotten into Scene Nodes effectors, so that will be a good opportunity to dig into a new area. Lots to learn!
Kind regards,
-vnormal-effector-axis-test-v1.c4d
normal-effector-axis-test-v2.c4d -
Apparently incorrect matrices in Python effector when subject to deformer
Hello,
Please find attached a file which illustrates how (I think) I am getting incorrect matrices in a Python deformer. I have created a test file to illustrate the issue (attached below at the very end).
My Python effector (Python Direction Effector) computes the 'lighting' at a given clone based on the clone's normal and the infinite light's direction.
Here is the code for the Python Effector, also in the attached c4d file. It scales and colors the clone (from 0 to 1 and red to yellow) depending on the product of the clone's normal and the light. So a scale of 1 and yellow for full light, and a scale of 0 and red for no light.import c4d import typing from c4d.utils import Neighbor import math op: c4d.BaseObject # The Python Effector object containing this code. gen: c4d.BaseObject # The MoGraph Generator executing `op`. doc: c4d.documents.BaseDocument # The document `op` and `gen` are contained in. def main() -> bool: data: c4d.modules.mograph.RMoData = c4d.modules.mograph.GeGetMoData(op) if data is None: return False light = op[c4d.ID_USERDATA, 1] if light is None: print("No light found in the effector's first user data field") return False mg_light: c4d.Matrix = light.GetMg() light_direction_global = -mg_light.v3.GetNormalized() # The Effector's MoData has a matrix per clone. Each clone therefore has its # position and orientation in that matrix. The clone's normal is the # orientation (v3) matrices: list = data.GetArray(c4d.MODATA_MATRIX) strength = op[c4d.ID_MG_BASEEFFECTOR_STRENGTH] n_clones = len(matrices) # Initialize color array colors = [c4d.Vector(0.0, 0.0, 0.0) for _ in range(n_clones)] for i in range(n_clones): normal_global = matrices[i].v3.GetNormalized() w = max(0.0, normal_global.Dot(light_direction_global)) # Interpolate color from red to yellow based on illumination colors[i] = c4d.Vector(1, w, 0) # Red to Yellow matrices[i].Scale(1 - strength + strength * w) # Set the color array to the MoData data.SetArray(c4d.MODATA_COLOR, colors, op[c4d.FIELDS].HasContent()) data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent()) return True
This Python Effector works in a lot of cases I tested. However, in some circumstances, it seems the matrices I get in the Effector (which seem incorrect) do not match the actual final placement of clones (which seem correct).
The attached test file stems from my efforts to have clones along a cylinder that have a nice helix distribution. To achieve that, I have a first set up (under 'vertical capsule':- A first single helix cloner. This clones simple small spheres. To have the normal I need on these, the cloner has a step effect which rotates the clones so that the normal is perpendicular to the helix center axis.
- A second cloner, which simply replicates the single helix cloner vertically, so that I have the density I am looking for.
So far so good. If I apply my effector to that set up as is, I get the expected result. In the attached image, you can see that under 'vertical capsule', I have the right lighting for my spheres, congruent with my normals.
Now, I want to deform my top cloner with a Spline Wrap. To do that, I insert the deformer as a sibling of my "multiple helixes' cloner. To make sure that I can visualize my normals on the clones, I have a little blue arrow in my cloner which is aligned along the z-axis. What I see:- Correct normals in both deformed and non deformed situations.
- Correct lighting from the effector in non deformed situations. I conclude my effector is using the right clone matrices.
- Incorrect light from the effector in deformed situation. I conclude my effector is not using the right clone matrices.
- Display issue in the viewport.
I have attached the test file as well as screen captures which illustrate my issue.
My question is: is there something I should be doing in the Python Effector code that I am missing to get the proper normals. The cloner is displaying the right normals, so I suspect the issue is in what the effector does or accesses. I have noticed that in some cases, the MoData can be queried from both the effector and the cloner, but I am not sure what the difference is and did not find information about that. My test showed that in an Effector, the proper method seems to access MoData through the effector (in c4d.modules.mograph.GeGetMoData(op) above).
I hope my questions is formulated well enough. If not, please shoot and I'll improve / correct.
Thanks in advance for your help.Image 1 Note: the image below illustrates that the normals are correct in the cloners (even deformed). However, the Effector does not produce the right result (under 'snake issue').
Image 2 Note: under 'snake issue', the viewport rendering does not structurally match the image viewer rendering.
normal-effector-deformer-debug-v2.c4d -
RE: Best strategy for VS Code debugging of Python Effectors (or other non-script Python) +
@ferdinand
Thanks for welcoming me and pointing me to the forum protocol and resources, I bookmarked it.
I feel a little bummed I cannot debug my code in the expression editor as I do for scripts, but I am hopeful because you say it is not currently supported, so I hope it may be on the roadmap, and I posted a feature request referring to this question, in case that helps moving it along.Thanks for the response about presets also.
Cheers. -
Best strategy for VS Code debugging of Python Effectors (or other non-script Python) +
Hello,
I have been trying to figure out the best way for me to debug a Python Effector I am working on. So far, I have not found a way to connect my Python Effector code to VS Code like I do for Python scripts.
So the best I came up with so far is to try and run the Python Effect as a script by using the following structure:import c4d op: c4d.BaseObject # The Python Effector object containing this code. gen: c4d.BaseObject # The MoGraph Generator executing `op`. doc: c4d.documents.BaseDocument # The document `op` and `gen`are contained in. # ...... def main() -> bool: """ Regular Python effector code """ # The following is to run the effector as a script for debugging purposes. # This simply calls the if __name__ == '__main__': # This is used when we execute the script directly, not as a Python Effector op = doc.SearchObject("Python Effector to debug") gen = doc.SearchObject("Generator with active Python Effector to debug") main()
This seems like a convoluted way to go about debugging the Python Effector, but it is the best I have come up with so far. While it does allow me to step and debug the code, it does not allow me to see the effect, I assume because on the next scene renders, it seems the effect of my script is overridden by the regular generator execution.
My questions are:
- Is there a better way to debug Python Effector code? I have been trying to follow the documentation but I do not see anything about Python Effectors or Python Field Debugging.
- What is the best way to package a Python Effector for reuse across documents? I have not found a way to make it a plugin.
I appologise if I did not get deep enough in the documentation or if I am missing the obvious. I am fairly new to Python in Cinema 4D and this is my first question.
Thanks in advance for any help you can offer.