Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
ok! finally, it is imporant to use the doc to get the irs ! now it works.
irs = c4d.modules.render.InitRenderStruct(doc)
but question: is this the only / best way to check if textures are missing?
an alternative would be to actually check if the file is existing somewhere in the given paths
I also just ran into this... < R24 you dont have BaseList2D.IsNodeBased, but as a small hack you can do:
def isNodeMaterial(op): return True if op.GetType == c4d.Mmaterial and '[Node]' in op.GetBubbleHelp() else False
hi and thanks Maxime !
GetAllAssetsNew() is S22 only, and I had problems with InitRender() and Vray Bitmaps
so I decided to manually check for the files... I had it already, but GenerateTexturePath() shortens the code quite a bit, because I dont have to check all possible paths.
It seem GenerateTexturePath() returns the absolute path, if the file is found somewhere in the texture paths, otherwise it returns None.
needs some testing, but until now it seems to work well.
best, index
Hi,
Just FYI ... I just noticed, that a Quicktab Radio UserData change results in two Messages (with the same UserData ID) If I change the interface to Cycle, I get only one Message as expected for an UserData change.
This might be a tiny miny Bug (?)
index
below is a simple CommandData plugin with a submenu to invoke different actions.
This works fine if more than one of these plugins (with unique Plugin Ids ofc) are in one plugin folder. But there is no menu if there is only one plugin present in the folder.
Is there a way to create such a menu with one plugin, while not registering each menu point as separate command?
best index
# encoding: utf-8 ''' CommandData Plugin with Menu ''' import c4d PLUGIN_ID = 12345678 # Unique Plugin Id MENUID_CMD0 = 1000 MENUID_CMD1 = 1001 class MenuHandler(c4d.plugins.CommandData): def Register(self): return c4d.plugins.RegisterCommandPlugin( id=PLUGIN_ID, str="Test", info=c4d.PLUGINFLAG_COMMAND_HOTKEY, icon=None, help=None, dat=MenuHandler()) def GetSubContainer(self, doc, submenu): bc = c4d.BaseContainer() bc.SetString(1, "Test") bc.SetString(MENUID_CMD0, "Command 0") bc.SetString(MENUID_CMD1, "Command 1") submenu.InsData(0, bc) return True def ExecuteSubID(self, doc, id): if id == MENUID_CMD0: pass if id == MENUID_CMD1: pass return True def Execute(self, doc): return True if __name__ == "__main__": MenuHandler().Register()
tx, i just wanted to report it...
Thanks a lot kbar.. i'll watch and learn! still... the hurdles to compile a c++ plugin are extremely high nowadays. it would be great if the sdk plugins would be downloadable ready compiled as well
this "Active Object Dialog" plugin looks very interesting if it would be understandably described how to compile it / the c++ sdk, we could check it out but sadly this got so complicated that you need a degree in IT to do it. .-)
FYI, developers.maxon.net is down since about 24 hours....
I have found another way to do this, which is maybe better (?) because it seems to work around tackling with parallel vectors....
LookAtCamera::Execute() translated to python ... https://github.com/PluginCafe/cinema4d_cpp_sdk_extended/blob/master/plugins/cinema4dsdk/source/tag/lookatcamera.cpp
def lookat(op, target, pitch=True): ''' orient op to look at target ''' local = (~(op.GetUpMg() * op.GetFrozenMln())) * target.GetMg().off - op.GetRelPos() hpb = c4d.utils.VectorToHPB(local) if not pitch: hpb.y = op.GetRelRot().y hpb.z = op.GetRelRot().z op.SetRelRot(hpb) c4d.EventAdd()
It seems to work fine... but for clarity... after checking the Matrix Manual (see end of the page) ... https://developers.maxon.net/docs/Cinema4DPythonSDK/html/manuals/data_algorithms/classic_api/matrix.html?highlight=matrix
Is this correct / covers all cases to get the targets position in local space? (~(op.GetUpMg() * op.GetFrozenMln())) * target.GetMg().off specifically.. what is m = utils.MatrixMove(op.GetAbsPos()) * utils.HPBToMatrix(op.GetAbsRot()) * utils.MatrixScale(op.GetAbsScale()) in this context? (ps. GetAbsScale misses the brackets in the docs)
and... is this the real code of the Target Tag ?
Hi Ferdinand, yes all solved and sorry if the gimbal lock was a false interpretation of what was happening. From reading the old threads I thought the quaternion solution was mandatory to solve this.
for clarity and as an example I'm including a comparison of your solution (working) and riccardos solution (showing the flip)
spotLight.c4d
but for me the case is closed... Thanks a lot for helping with this !
Hi Ferdinand,
thanks a lot, seems I'm not the only one missing the good weather outside .-)
The code in the first lookat() function should be abs(ri.x - 1.0), this comes from the post in the mentioned link. I corrected that in the original post. (it was just missing in the post, my code had the ri.x)
what I'm on to is a 2 axis ceiling spot. its a null with a python tag having a target link userdata, then inside a hierarchy with two axes. atm they are driven by 2 target tags (initialized by the pyTag) one needs pitch on, one needs pitch off. this works fine, but as i have 900 of these in a file, i am trying to get rid of the target tags and do all in the pyTag. I can post the file tomorrow.
what happens with my lookat() is that if you move the target, the spot sometimes turns upside down 180 degrees and sticks in the ceiling.
with lookatQ() the spot simply doesn't point in the correct direction. but it would be very interesting to learn how to do it with quaternions.
edit: your solution seems to work nicely, btw! p.s. i guess ~ is normalise and % is the cross product
Hi, I have seen and as expected this was discussed already in the past, but I could not find any working example in this forum.
I'd simply like to have a (gimbal lock safe) python replacement for the Target (Expression) Tag.
I'm attaching what I have come up with until now... two versions #1 without , #2 with quaternion --> sadly #1 has gimbal issues and #2 fails completely both with a pitch lock like in the Target Tag --> sure this could be done more elegant .-)
It was stated in one of the (below) mentioned threads, that support can't solve such problems for the users, but this would be such a valuable tool in the quiver that it might be an exception (?)
def lookat(op, target, pitchlock=0): ''' gimbal lock UNSAFE target expression this basically works, but results in axis flips sometimes ''' r1 = op.GetRelRot() # backup p1 = op.GetMg().off # from p2 = target.GetMg().off # to tmp = c4d.Vector(0, 1, 0) # temp-up fo = (p2 - p1).GetNormalized() # forward ri = tmp.Cross(fo).GetNormalized() # right up = fo.Cross(ri).GetNormalized() # up # https://plugincafe.maxon.net/topic/11152/object-target-expression-in-python/2 # try to mitigate gimbal-lock --> UNSAFE, RESULTS IN AXIS FLIPS ! if (fo + tmp).z < 0: up.x = -up.x if abs(ri.x - 1.0) < 0.001: ri = -ri m = c4d.Matrix() m.v1 = ri m.v2 = up m.v3 = fo m.off = p1 op.SetMg(m) if pitchlock: r = op.GetRelRot() op.SetRelRot(c4d.Vector(r.x, r1.y, r.z))
def lookatQ(op, target, pitchlock=0): ''' quaternion based (gimbal lock safe ???) target expression sadly doesn't work and results in a wrong rotation ''' r1 = op.GetRelRot() # backup p1 = op.GetMg().off # from p2 = target.GetMg().off # to tmp = c4d.Vector(0, 1, 0) # temp-up fo = (p2 - p1).GetNormalized() # forward ri = tmp.Cross(fo).GetNormalized() # right up = fo.Cross(ri).GetNormalized() # up # copied from # https://www.gamedev.net/forums/topic/613595-quaternion-lookrotationlookat-up/ w = math.sqrt(1.0 + ri.x + up.y + fo.z) * 0.5 w4_recip = 1.0 / (4.0 * w) x = (up.z - fo.y) * w4_recip y = (fo.x - ri.z) * w4_recip z = (ri.y - up.x) * w4_recip # given the above is correct, is this correctly applied here ??? q = c4d.Quaternion() v = c4d.Vector(x, y, z) q.SetAxis(v, w) m = q.GetMatrix() m.off = p1 op.SetMg(m) if pitchlock: r = op.GetRelRot() op.SetRelRot(c4d.Vector(r.x, r1.y, r.z))
ups, sorrryy. my bad .-)
I know that list ... but LOL, now i cant find the object type for the Cloner Object
hi.. just to report....
the object type for the Subdivision Surface object seems to be missing in the python and C++ sdk...
c4d.Osubdivisionsurface = 1007455
hi Ferdinand,
i noticed that there is actually an issue with excessive gelist heads.... if you have this :
<c4d.BaseShader object called 'Filter/Filter' with ID 1011128 at 0x7fcebe74eeb0> + <c4d.GeListHead object at 0x7fcebe787a70> branch 'Shaders' + + <c4d.LayerShader object called 'Layer/Layer' with ID 1011123 at 0x7fcebe787ab0> + + + <c4d.BaseShader object called 'Noise/Noise' with ID 1011116 at 0x7fcebe787b90>
GetUp() on the LayerShader seems to return None, which is a problem if - like in this case - you need to know if a shader is in the middle inside a shader tree, or if it is at the top / a direct child of the material
this makes something like this necessary to properly "insert" a shader ....
if isinstance(target, c4d.BaseShader): shader.InsertUnder(target) else: target.InsertShader(shader)