Here you go: https://github.com/NiklasRosenstein/py-localimport
That helper is also available as a minified version.
Posts made by mp5gosu
-
RE: External dependencies question
-
RE: Global Matrix - Trying to copy data from Mixamo Control Rig with Python
You have to update the document each frame with ExecutePasses()
In your for loop, simply adddoc.ExecutePasses(None, True, True, False, c4d.BUILDFLAGS_NONE)
as the first method call. (Adjust parameters to your needs.) -
RE: UVW coordinates in ShaderData.Output()
As far as I remember, Viewport drawing is handled in Draw() method.
-
RE: Erratic Keyboard Messages in GeDialog
Did you try my proposed fix? ;)
-
RE: Erratic Keyboard Messages in GeDialog
This happens because tools that will be called twice in short succession gain focus in the C4D layout. Therefore your Dialog loses focus as the Move tool is bound to
E
.
I don't kbnow exactly how to prevent that behavior, but there should be some message that can be processed. SDK team will be more of help here.edit: Easy fix: return
c4d.NOTOK
after your print statement. That consumes the message and does not call the base function, so Cinema simply does not get notified of the event. -
RE: Error: Wrong indentation of namespace member
Are both header files or is the upper one a cpp file?
Also, do the errors com from Intellisense or is it a style check/compilation error?If the LLVM convention is used, the error is correct. LLVM namespace formatting conventions don't use any intentaion. You might be a able to fix this by ignoring this error explicitly.
It also might be caused by a bug in XCode. -
RE: Purely dynamic description for shader?
Sure, your statement was correct. That's why I mentioned the possible misunderstanding here. That's on my side (as usual :)).
You posts are invavuable for all of us, so I'd be damned if I'm going to accuse you of being wrong. :P -
RE: Purely dynamic description for shader?
Sure. The reason why I know that is, I do it occassionally. :)
Niklas answered me that question a while ago: https://plugincafe.maxon.net/topic/9400/12588_multiple-nodedata-descriptions-solved/2But it seems, there's a misunderstanding here. Multiple plugin IDs cannot be registered. But you can create a composite plugin with different descriptions.
I usually do that with NodeData plugins.Best,
Robert -
RE: Purely dynamic description for shader?
@ferdinand said in Purely dynamic description for shader?:
- So you talk about multiple descriptions, but a singular plugin, which I do not understand. No matter what you do, you can only register a plugin once and provide a singular description for it. You cannot register the same plugin with multiple descriptions.
I have to disagree here. The Cinema 4D Multipasses for example are implemented in exactly this way. ( by registering multiple descriptions though)
-
Crash with GeListHead and TreeViewFunctions SetName()
Hello,
I noticed that when using a
GeListHead
for storing customBaseList2D
items leads to a crash whenTreeViewFunctions
'SetName
is called.
Is this a known bug/behavior?
If not, what did I do wrong? ;)Here's a minimal example. Try to rename any ListItem with Double-Click -> Freeze.
On R21 I did some more debugging and it turned out thatobj
inSetName()
is of typelong
.import c4d from c4d import gui from c4d import plugins PLUGIN_ID = 1000001 # Test plugin id PLUGIN_ID_ND = 1000002 # Test plugin id class ListItem(plugins.NodeData): def Init(self, node): # do stuff here return True class Tvf(gui.TreeViewFunctions): def GetFirst(self, root, userdata): if not root: return None return root.GetFirst() def GetNext(self, root, userdata, obj): return obj.GetNext() def GetName(self, root, userdata, obj): return obj.GetName() def SetName(self, root, userdata, obj, str): obj.SetName(str) class TestDialog(gui.GeDialog): def __init__(self): self.items = c4d.GeListHead() self.treegui = None self.tvf = Tvf() def add_item(self): item = c4d.BaseList2D(PLUGIN_ID_ND) item.SetName("ListItem") item.InsertUnder(self.items) def CreateLayout(self): settings = c4d.BaseContainer() settings.SetBool(c4d.TREEVIEW_HAS_HEADER, True) self.treegui = self.AddCustomGui(0, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 300, 300, settings) return True def InitValues(self): for x in range(5): self.add_item() layout_bc = c4d.BaseContainer() layout_bc.SetInt32(0, c4d.LV_TREE) self.treegui.SetLayout(1, layout_bc) self.treegui.SetHeaderText(0, "Name") self.treegui.Refresh() self.treegui.SetRoot(self.items, self.tvf, None) return True class TestCommand(plugins.CommandData): def __init__(self): self.dlg = None def Register(self): return plugins.RegisterCommandPlugin(PLUGIN_ID, "Test-Plugin", 0, None, None, self) def Execute(self, doc): if self.dlg is None: self.dlg = TestDialog() return self.dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaulth=400, defaultw=400) def RestoreLayout(self, sec_ref): if self.dlg is None: self.dlg = TestDialog() return self.dlg.Restore(pluginid=PLUGIN_ID, secret=sec_ref) if __name__ == '__main__': TestCommand().Register() plugins.RegisterNodePlugin(PLUGIN_ID_ND, "ListItem", c4d.PLUGINFLAG_HIDE, ListItem, None)
-
RE: "Frame Selected Elements" command not working when running script through c4dpy?
@ferdinand said in "Frame Selected Elements" command not working when running script through c4dpy?:
forgot to call c4d.documents.InsertDocument before calling c4d.documents.SetActiveDocument which causes all sorts of hiccups in Cinema, not only c4dpy
This is a real classic! I stumbled over this several times! :)
-
RE: "Frame Selected Elements" command not working when running script through c4dpy?
Maybe this script helps you to frame your objects manually. The called helper methods should be self-explanatory.
If you have any questions, feel free to ask.import c4d import sys import math from .. import Helpers class FramedCamera(object): """ Modifies a given camera to frame a given object. The object to frame must be a clone since it is modified """ def __init__(self, frame_obj, camera, azimuth=00, elevation=0): self.frame_object(frame_obj, camera, azimuth, elevation) # calculate the bounding sphere based on the camera FOV def calc_bsphere(self, op, camera): """Calculates a bounding sphere from a given object considering the FOV Args: op (c4d.BaseObject): The object to calculate the bounding sphere from camera (c4d.BaseObject): The camera to get the FOV from Returns: list: The bounding sphere center and radius """ points = Helpers.GetAllPoints(op) if not points: raise ValueError("Object {} has no points".format(op.GetName())) p_min = c4d.Vector(sys.float_info.max) p_max = c4d.Vector(-sys.float_info.max) for p in points: p_min = c4d.Vector(min(p.x, p_min.x), min(p.y, p_min.y), min(p.z, p_min.z)) p_max = c4d.Vector(max(p.x, p_max.x), max(p.y, p_max.y), max(p.z, p_max.z)) center = (p_min + p_max) * 0.5 radius = 0 for p in points: radius = max(radius, (center - p).GetLength()) fov_h = camera[c4d.CAMERAOBJECT_FOV] fov_v = camera[c4d.CAMERAOBJECT_FOV_VERTICAL] radius = (radius * 1.1) / math.sin(max(fov_h, fov_v) * 0.5) return center, radius # LookAt function def look_at(self, origin, target): """ Creates an orientation matrix from two vectors Args: origin (c4d.Vector): The Vector to be used to orient target (c4d.Vector): The target vector Returns: c4d.Matrix: The orientation matrix """ mat = c4d.Matrix() up_temp = c4d.Vector(0, 1.0, 0) v_fwd = (target - origin).GetNormalized() v_right = up_temp.Cross(v_fwd).GetNormalized() v_up = v_fwd.Cross(v_right).GetNormalized() mat.off = origin mat.v1 = v_right mat.v2 = v_up mat.v3 = v_fwd return mat # frame objects def frame_object(self, op, camera, elevation, azimuth): """ Places and orients a camera to fit a given object An optional angle (H,P) can be given. Args: op (c4d.BaseObject): The object to frame camera (c4d.BaseObject): The camera that is used elevation (float): Camera Heading, in radians azimuth (float): Camera Pitch, in radians Returns: bool: True for success, False otherwise. """ Helpers.convertInstances(op) # Get bounding sphere depending on camera FOV b_sphere = self.calc_bsphere(op, camera) if not b_sphere: raise ValueError("Bounding sphere cannot be calculated") # Set camera position and direction center, radius = b_sphere camera.SetMg(c4d.Matrix()) cam_pos = c4d.Vector(center) cam_pos.x = cam_pos.x + math.cos(azimuth) * math.sin(elevation) * radius cam_pos.y = cam_pos.y + math.sin(azimuth) * radius cam_pos.z = cam_pos.z + math.cos(azimuth) * math.cos(elevation) * -radius camera.SetMg(self.look_at(cam_pos, center))
Side note. This code comes from a prototype, therefore it is not optimized/comes with some syntactical flaws.
-
RE: OOP class struggles: treeview envoce gui refresh outside class ListView()
userdata parameter of the TreeViewFunctions overidden methods can be anything, your dialog for example. ;)
-
RE: Attribute Manamger Update Delay When Description Added Dynamically
By the way, it is also worth mentioning the Note on MSG_CHANGE
-
RE: GroupBorderNoTitle change GUI or flags after user input
Hello mogh.
I usually come over such tasks by having a helper routine that does the layout (re-)building.
In that routine, I can freely decide the gadget's appearance based on certain conditions. After rebuilding, the "old" gadgets have to be removed and replaced by the new ones and the only thing that's left is the refreshing of the dialog. Note that this only works for dynamic gadgets/groups. -
RE: How to change the EXR compression method via python
@m_adam maybe the code example in the repo should be updated. ;)
-
RE: How to change the EXR compression method via python
Oh yes, you are right. The SDK example doesn't work at all.
Problem is,maxon.Id
is wrong.maxon.InternedId
would be the correct way for setting the save options. Here's the correct code:""" Copyright: MAXON Computer GmbH Author: Maxime Adam Description: - Configures OpenEXR output render format with SetImageSettingsDictionary() then reads these with GetImageSettingsDictionary(). Class/method highlighted: - c4d.bitmaps.SetImageSettingsDictionary() - c4d.bitmaps.GetImageSettingsDictionary() Compatible: - Win / Mac - R20, R21, S22, R23 """ import c4d import maxon def main(): # Retrieves render data and its container renderData = doc.GetActiveRenderData() bc = renderData.GetDataInstance() # Gets image filters options saveOptions = bc.GetContainerInstance(c4d.RDATA_SAVEOPTIONS) # Sets OpenEXR output format bc[c4d.RDATA_FORMAT] = c4d.FILTER_EXR # Defines OpenEXR settings compressionmethodID = maxon.InternedId('net.maxon.mediasession.openexr.export.compressionmethod') halffloatID = maxon.InternedId('net.maxon.mediasession.openexr.export.halffloat') layernumberingID = maxon.InternedId('net.maxon.mediasession.openexr.export.layernumbering') # Configures OpenEXR format options with a maxon.DataDictionary exportSettings = maxon.DataDictionary() exportSettings.Set(compressionmethodID, maxon.Id("rle")) exportSettings.Set(halffloatID, True) exportSettings.Set(layernumberingID, True) # Stores settings in render data container c4d.bitmaps.SetImageSettingsDictionary(exportSettings, saveOptions, c4d.FILTER_EXR) # Pushes an update event to Cinema 4D c4d.EventAdd() # Retrieves OpenEXR images settings settings = c4d.bitmaps.GetImageSettingsDictionary(saveOptions, c4d.FILTER_EXR) # Reads and prints OpenEXR format options print("openexr.export.compressionmethod: " + str(settings.Get(compressionmethodID))) print("openexr.export.halffloat: " + str(settings.Get(halffloatID))) print("openexr.export.layernumbering: " + str(settings.Get(layernumberingID))) if __name__ == '__main__': main()
-
RE: Reflection Layer Settings
Reflection Layers aren't simple parameters. They are of type c4d.ReflectionLayer and have their own ID. Since the number of reflection layers can change dynamically, the parameter access also happens dynamically.
For example:
import c4d def main() : mat = doc.GetActiveMaterial() cntLayer = mat.GetReflectionLayerCount() # get the number of all reflection layers for i in xrange(0, cntLayer) : # loop through all layers layer = mat.GetReflectionLayerIndex(i) # process current layer # Sets the Strength for each layer to 50% mat[layer.GetDataID() + c4d.REFLECTION_LAYER_TRANS_BRIGHTNESS] = 0.5 # Here, the DataID is the unique, dynamic identifier for the layer. This can be chained with actual parameters. c4d.EventAdd() # update C4D if __name__=='__main__': main()
There's plenty of questions and answers to reflection layers on this forum. Just need to search for it. :)
-
RE: NodeData: How to get connected GeListNode
Thought so.
No, there's nothing missing in inherited methods. Thought, it'd be convenient. However, storing it to a member variable on init or forwarding does the trick.