EventAdd() doesn't update C4D
-
On 06/02/2013 at 13:22, xxxxxxxx wrote:
I feel like I'm not being clear enough about why you can't (normally) do this kind of thing with a script.
You are comparing an object's points to a camera's position. Which means that you have to physically have these objects in the scene to do the comparison. It can't be done virtually in memory where the user doesn't see this happening unless the whole thing is done in a separate document.This kind of thing is much easier to do in a python tag. Because you can re-run the entire code just by using EventAdd() until the condition you're testing for becomes true.
You don't have this option in a script. It runs once then you're done.
There is no such thing as: Test the objects->Move one of the objects->Test the objects again etc. until you get the desired result.
You can't do that in a script.However. That said you can force a script to do this kind of thing.
But it's a lot of extra work. And it requires a lot of adding and removing objects.
Which might not be considered a good practice.This script will position the camera so the cube is within the safeFrame view.
And it does it in one click:import c4d def TestPointInFrame(pt, frame) : return pt.x > frame['cl'] and pt.x < frame['cr'] and \ pt.y > frame['ct'] and pt.y < frame['cb'] def CheckIfInView(cam, obj, doc) : #Get the current BaseDraw bd = doc.GetActiveBaseDraw() safeFrame = bd.GetSafeFrame() #Get the active object bouding box center and radius box = [c4d.Vector() for x in xrange(8)] points = [c4d.Vector() for x in xrange(8)] rd = obj.GetRad() mp = obj.GetMp() #Build the active object bouding box box[0] = c4d.Vector() box[0].x = mp.x - rd.x box[0].y = mp.y - rd.y box[0].z = mp.z - rd.z box[0] *= obj.GetMgn() box[1] = c4d.Vector() box[1].x = mp.x - rd.x box[1].y = mp.y + rd.y box[1].z = mp.y - rd.z box[1] *= obj.GetMgn() box[2] = c4d.Vector() box[2].x = mp.x + rd.x box[2].y = mp.y - rd.y box[2].z = mp.y - rd.z box[2] *= obj.GetMgn() box[3] = c4d.Vector() box[3].x = mp.x + rd.x box[3].y = mp.y + rd.y box[3].z = mp.y - rd.z box[3] *= obj.GetMgn() box[4] = c4d.Vector() box[4].x = mp.x + rd.x box[4].y = mp.y - rd.y box[4].z = mp.z + rd.z box[4] *= obj.GetMgn() box[5] = c4d.Vector() box[5].x = mp.x + rd.x box[5].y = mp.y + rd.y box[5].z = mp.y + rd.z box[5] *= obj.GetMgn() box[6] = c4d.Vector() box[6].x = mp.x - rd.x box[6].y = mp.y - rd.y box[6].z = mp.y + rd.z box[6] *= obj.GetMgn() box[7] = c4d.Vector() box[7].x = mp.x - rd.x box[7].y = mp.y + rd.y box[7].z = mp.y + rd.z box[7] *= obj.GetMgn() #Calculate bouding box coordinates in screen space for i in xrange(len(box)) : points[i] = bd.WS(box[i]) #Test if the current object is completely visible in the rendered safe frame for i in xrange(len(points)) : visible = TestPointInFrame(points[i], safeFrame) if not visible: break return visible Zvalue = 0 def main() : global Zvalue cube = c4d.BaseObject(c4d.Ocube) cube.SetName('Cube') doc.InsertObject(cube) cube.SetBit(c4d.BIT_ACTIVE) c4d.CallCommand(12236) # Make Editable cam = c4d.CameraObject() cam.SetName('Cam') camMg = cam.GetMg() camMg.off = c4d.Vector(0,0,-200) cam.SetMg(camMg) doc.InsertObject(cam) stage = c4d.BaseObject(c4d.Ostage) doc.InsertObject(stage) count = 0 while count< 150: #<--------------- Force the loop to stop after a set amount for safety tempcam = c4d.BaseObject(c4d.Ocamera) doc.InsertObject(tempcam) pos = tempcam.GetAbsPos() tempcam.SetAbsPos(c4d.Vector(0, 0, Zvalue - 3)) tempcam.Message(c4d.MSG_UPDATE) pos = tempcam.GetAbsPos() Zvalue = pos.z stage[c4d.STAGEOBJECT_CLINK] = tempcam c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW|c4d.DRAWFLAGS_NO_THREAD|c4d.DRAWFLAGS_NO_REDUCTION|c4d.DRAWFLAGS_STATICBREAK) if CheckIfInView(cam, cube, doc) :break tempcam.Remove() #print Zvalue count +=1 #Set the original camera to the position the last cloned camera version was cam.SetAbsPos(c4d.Vector(0,0, Zvalue)) c4d.EventAdd() if __name__ == '__main__': main()
Quite a mouthful of code for such a seemingly simple task ain't it.
-ScottA
-
On 06/02/2013 at 15:05, xxxxxxxx wrote:
Hi,
it is also possible without calling DrawViews() by moving the object itself, taking the delta from
its original position, move the camera by this delta and reset the object.import c4d def TestPointInFrame(pt, frame) : return pt.x > frame['cl'] and pt.x < frame['cr'] and \n pt.y > frame['ct'] and pt.y < frame['cb'] def CheckIfInView(obj, bd) : safeFrame = bd.GetSafeFrame() #Get the active object bounding box center and radius box = [c4d.Vector() for x in xrange(8)] rd = obj.GetRad() mp = obj.GetMp() #Build the active object bouding box box[0].x = mp.x - rd.x box[0].y = mp.y - rd.y box[0].z = mp.z - rd.z box[0] *= obj.GetMgn() box[1].x = mp.x - rd.x box[1].y = mp.y + rd.y box[1].z = mp.y - rd.z box[1] *= obj.GetMgn() box[2].x = mp.x + rd.x box[2].y = mp.y - rd.y box[2].z = mp.y - rd.z box[2] *= obj.GetMgn() box[3].x = mp.x + rd.x box[3].y = mp.y + rd.y box[3].z = mp.y - rd.z box[3] *= obj.GetMgn() box[4].x = mp.x + rd.x box[4].y = mp.y - rd.y box[4].z = mp.z + rd.z box[4] *= obj.GetMgn() box[5].x = mp.x + rd.x box[5].y = mp.y + rd.y box[5].z = mp.y + rd.z box[5] *= obj.GetMgn() box[6].x = mp.x - rd.x box[6].y = mp.y - rd.y box[6].z = mp.y + rd.z box[6] *= obj.GetMgn() box[7].x = mp.x - rd.x box[7].y = mp.y + rd.y box[7].z = mp.y + rd.z box[7] *= obj.GetMgn() #Calculate bouding box coordinates in screen space points = [bd.WS(p) for p in box] #Test if the current object is completely visible in the rendered safe frame for i in xrange(len(points)) : if not TestPointInFrame(points[i], safeFrame) : return False return True def MoveObjectRel(op, axis, offset) : axis = axis.GetNormalized() axis.off = op.GetRelPos() op.SetRelPos(axis * offset) def EscapePressed(bc=None) : if bc is None: bc = c4d.BaseContainer() c4d.gui.GetInputEvent(c4d.BFM_INPUT_KEYBOARD, bc) return bc[c4d.BFM_INPUT_CHANNEL] == c4d.KEY_ESC def main() : if not op: c4d.gui.MessageDialog("please select an object") return bd = doc.GetActiveBaseDraw() cam = bd.GetSceneCamera(doc) if op is cam: return MessageDialog("can not apply on the cam") campos = cam.GetAbsPos() pos = op.GetAbsPos() axis = cam.GetMg() offset = c4d.Vector(0, 0, 10) # Create an undo-state for the camera because we will offset it. doc.AddUndo(c4d.UNDOTYPE_CHANGE, cam) c4d.StatusSetSpin() passes = 0 stopped = False while not CheckIfInView(op, bd) : stopped = EscapePressed() if stopped: break MoveObjectRel(op, axis, offset) passes += 1 delta = op.GetAbsPos() - pos op.SetAbsPos(pos) if not stopped: campos -= delta cam.SetAbsPos(campos) c4d.StatusClear() c4d.EventAdd() main()
-
On 08/02/2013 at 05:34, xxxxxxxx wrote:
Thank you for your wonderful codes! I experimented the last two days with them and still have a few questions about them.
@Scott: You said, that scripts should not be used for this and that I should use a plugin instead. I'm quite open to that but I'm not really sure what the significant changes regarding your code will be. Can I use a complete new (and simpler) approach when using PlugIns? If so, what will it look like? I'm sorry if you had this question already answered, but I still have problems with that.
@Niklas: You move the object, not the camera. In future the scene I'll use this script/plugin on will have about 18.000 objects. I couldn't test it yet, but i suppose that this will be a serious performance issue.
And you use this line of code "op.SetRelPos(axis * offset)" to set the new offset of the object. If I'm not completely wrong vector math dictates to add the two vectors to get the resulting vector, not to multiply them. Obviously your solution works, so can you please tell me, why you multiply these two vectors instead of adding them? I'm really confused about this fact...I really appreciate all your input and you all are helping me a lot! I'm really looking forward for your further answers. Thanks in advance!
-
On 08/02/2013 at 05:46, xxxxxxxx wrote:
Hi Nachtmahr,
I am moving the object, because moving the camera would require to redraw the editor in order for
BaseDraw.WS() to work correctly. The result is exactly the same. Compare Scotts and mine
example. You can watch the editor slowly moving away from the object in Scotts code, mine works
almost instantly. Do you really think it is more performant to redraw the editor on each pass?axis is not a vector, it is a matrix. I'm moving the object away from the camera to simulate a
"zooming out". After the object is far away enough to fit into the editor view, I reset it to its
original position and move the camera about the anmount the object was moved in negative
direction.> >> In future the scene I'll use this script/plugin on will have about 18.000 objects.
Separately or all at once (so they all fit into the view at once)? Make CheckInView() traverse the
hierarchy recursively to check if all objects in the scene are in the frame. You should put all
objects under a Null-Object then (to make the simulation of "zooming out" work) assuming you
keep sticking to my solution.-Niklas
-
On 08/02/2013 at 06:15, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Separately or all at once (so they all fit into the view at once)?
It's a machine imported from a CAD-Tool for rendering. In most cases I have to render seperate parts of the whole machine, so the focusing will affect multiple thousands of objects, but not all of them.
Originally posted by xxxxxxxx
You should put all objects under a Null-Object then (to make the simulation of "zooming out" work)
I think this won't be possible, because the inner structure of the imported data has to be kept. And if I move the parts under a Null-object I have to seperate them to their old places after the focusing is done. This sounds a bit of overkill to me.
-
On 08/02/2013 at 06:19, xxxxxxxx wrote:
You can also just automate the process of putting them under a null-object, run what the script
currently does on the null-object (but with taking its children into account) and unpack the null-object
again. Still better then redrawing the editor for each pass.If you don't want that workaround, you could also manage to offset the objects aiming for seperately,
but this would be more code to write and less perfomant (because of Pythons slow iterations). -
On 08/02/2013 at 08:30, xxxxxxxx wrote:
Originally posted by xxxxxxxx
@Scott: You said, that scripts should not be used for this and that I should use a plugin instead. I'm quite open to that but I'm not really sure what the significant changes regarding your code will be. Can I use a complete new (and simpler) approach when using PlugIns? If so, what will it look like? I'm sorry if you had this question already answered, but I still have problems with that.
A plugin or pytag is just the usual choice for this kind of thing. Because they can execute their code several times. Not just once.
It's often an advantage to have this ability so you can compare things->move them->compare them again.Most people would probably use a plugin or a pytag for this task you're doing. And take advantage of that running several times thing to do a task like multiple comparisons and moves.
But Niklas found a way to do this using a script that's just a s good as using a plugin or a pytag.
Normally this kind of task isn't done with a script due to it's run once nature.
But people who are clever (like Niklas) can often figure out a way to get around that problem.-ScottA
-
On 12/02/2013 at 02:13, xxxxxxxx wrote:
Hey guys!
Thanks for your replies!
I did some calculations the last days and it took me quite a while, because I got really confused about that many coordinate systems and matrices and vectors...
Anyways, I managed to get a working code which did the repositioning of my camera in one calculation, without Redrawing or moving objects. It works pretty fine as long as the camera aims directly to the midpoint of the object (need to add an offset to the midpoint to the calculation) and the object is in front of the camera (not necessarily completly). So there is room for improvements''' Created on 12.02.2013 ''' import c4d from c4d import documents import math def GetNewCameraPosition(cam, obj, doc) : bd = doc.GetActiveBaseDraw() safeFrame = bd.GetSafeFrame() #Get the active object bounding box center and radius, including midpoint as last point box = [c4d.Vector() for x in xrange(9)] points = [c4d.Vector() for x in xrange(9)] rd = obj.GetRad() mp = obj.GetMp() #Build the active object bounding box box[0].x = mp.x - rd.x box[0].y = mp.y - rd.y box[0].z = mp.z - rd.z box[0] *= obj.GetMgn() box[1].x = mp.x - rd.x box[1].y = mp.y + rd.y box[1].z = mp.z - rd.z box[1] *= obj.GetMgn() box[2].x = mp.x + rd.x box[2].y = mp.y - rd.y box[2].z = mp.z - rd.z box[2] *= obj.GetMgn() box[3].x = mp.x + rd.x box[3].y = mp.y + rd.y box[3].z = mp.z - rd.z box[3] *= obj.GetMgn() box[4].x = mp.x + rd.x box[4].y = mp.y - rd.y box[4].z = mp.z + rd.z box[4] *= obj.GetMgn() box[5].x = mp.x + rd.x box[5].y = mp.y + rd.y box[5].z = mp.z + rd.z box[5] *= obj.GetMgn() box[6].x = mp.x - rd.x box[6].y = mp.y - rd.y box[6].z = mp.z + rd.z box[6] *= obj.GetMgn() box[7].x = mp.x - rd.x box[7].y = mp.y + rd.y box[7].z = mp.z + rd.z box[7] *= obj.GetMgn() box[8].x = mp.x box[8].y = mp.y box[8].z = mp.z box[8] *= obj.GetMgn() #convert bounding box points to Screenspace for i in xrange(len(box)) : points[i] = bd.WS(box[i]) #looking for extreme points minXIndex = maxXIndex = minYIndex = maxYIndex = minZIndex = maxZIndex = 0 minX = maxX = points[minXIndex][0] minY = maxY = points[minYIndex][1] minZ = maxZ = points[minZIndex][2] for i in xrange(1, len(points) - 1) : #-1: Midpoint can never be an extreme point if points[i][0] < minX: minX = points[i][0] minXIndex = i if points[i][0] > maxX: maxX = points[i][0] maxXIndex = i if points[i][1] < minY: minY = points[i][1] minYIndex = i if points[i][1] > maxY: maxY = points[i][1] maxYIndex = i if points[i][2] < minZ: minZ = points[i][2] minZIndex = i if points[i][2] > maxZ: maxZ = points[i][2] maxZIndex = i #if a pair of indices is equal than a calculation can't be done if (minXIndex == maxXIndex) or (minYIndex == maxYIndex) or (minZIndex == maxZIndex) : print 'At least one pair of indices are equal: minX {0}, maxX {1}, minY {2}, maxY {3}, minZ {4}, maxZ {5}\nAborting function'.format(minXIndex, maxXIndex, minYIndex, maxYIndex, minZIndex, maxZIndex) return cam.GetMg().off #calculate offset from midpoint to nearest extreme point in z direction in sight of cam if points[minXIndex][2] <= points[maxXIndex][2]: offsetX = math.fabs(points[8][2] - points[minXIndex][2]) else: offsetX = math.fabs(points[8][2] - points[maxXIndex][2]) if points[minYIndex][2] <= points[maxYIndex][2]: offsetY = math.fabs(points[8][2] - points[minYIndex][2]) else: offsetY = math.fabs(points[8][2] - points[maxYIndex][2]) #calculate necessary distance between camera and extreme point fd_x = ((box[maxXIndex] - box[minXIndex]).GetLength() / 2.0) / math.tan(cam[c4d.CAMERAOBJECT_FOV] / 2) fd_y = ((box[maxYIndex] - box[minYIndex]).GetLength() / 2.0) / math.tan(cam[c4d.CAMERAOBJECT_FOV_VERTICAL] / 2) #add the corresponding offset fd_x += offsetX fd_y += offsetY #check if calculation went wrong (camera distance can't be negative), # set the focus distance to distance to midpoint of bounding box if fd_x > fd_y: if fd_x <= 0: print 'fd_x smaller than 0' return cam.GetMg().off cam[c4d.CAMERAOBJECT_TARGETDISTANCE] = fd_x else: if fd_y <= 0: print 'fd_y smaller than 0' return cam.GetMg().off cam[c4d.CAMERAOBJECT_TARGETDISTANCE] = fd_y #calculate the new camera position camMg = cam.GetMg() camMgOff = obj.GetMg().off camMgOff += camMg.v3.__neg__() * cam[c4d.CAMERAOBJECT_TARGETDISTANCE] #repositioning in negative z-axis return camMgOff def main() : doc = documents.GetActiveDocument() cam = doc.SearchObject('Cam') cube = doc.SearchObject('Cube') camMg = cam.GetMg() camMg.off = GetNewCameraPosition(cam, cube, doc) cam.SetMg(camMg) c4d.EventAdd() if __name__ == '__main__': main()
Any recommandations on this code would be appreciated!
Greetings Nachtmahr
-
On 25/06/2015 at 05:46, xxxxxxxx wrote:
Originally posted by xxxxxxxx
You can also just automate the process of putting them under a null-object, run what the script
currently does on the null-object (but with taking its children into account) and unpack the null-object
again. Still better then redrawing the editor for each pass.
...How do i do that ?
I am itterating through all objects at the moment and the result is the camera moves away way too far. (some cubes dimenson 200m camera moves to 246666m)
I need to have my Null-Object with lots of objects inside to be full inside the rendersave frame. Is it posible to get a boundingbox from a Null-Object with its children taken into acount without iterationg through several thousand objects ?
thanks in advance.
-
On 27/06/2015 at 10:21, xxxxxxxx wrote:
So I managed to add Niklas aabb Boundingbox Routine to your script but I am still getting weird results.
sometimes nothing happens, passes = 0 even when something is not in view,
sometimes it works kind of but the object is way to small in the midle,
sometimes it runs forever in a loopcan we get this as neat and tidy and better working than this "H"-Key in C4D?
kind regrads mogh
# Added Niklas Rosenstein AABB Utility to get the boundingbox of a Null-Object with its Children # please note that you have to install it # http://pythonhosted.org/c4dtools/ # https://github.com/NiklasRosenstein/c4dtools <- download from here import c4d from c4d import utils import c4dtools.misc.aabb as aabb def TestPointInFrame(pt, frame) : return pt.x > frame['cl'] and pt.x < frame['cr'] and \ pt.y > frame['ct'] and pt.y < frame['cb'] #def CheckIfInView(obj, bd) : def CheckIfInView(obj, rd, mp, bd) : safeFrame = bd.GetSafeFrame() #Get the active object bounding box center and radius box = [c4d.Vector() for x in xrange(8)] #rd = obj.GetRad() #mp = obj.GetMp() #print box, rd, mp #Build the active object bouding box box[0].x = mp.x - rd.x box[0].y = mp.y - rd.y box[0].z = mp.z - rd.z box[0] *= obj.GetMgn() box[1].x = mp.x - rd.x box[1].y = mp.y + rd.y box[1].z = mp.y - rd.z box[1] *= obj.GetMgn() box[2].x = mp.x + rd.x box[2].y = mp.y - rd.y box[2].z = mp.y - rd.z box[2] *= obj.GetMgn() box[3].x = mp.x + rd.x box[3].y = mp.y + rd.y box[3].z = mp.y - rd.z box[3] *= obj.GetMgn() box[4].x = mp.x + rd.x box[4].y = mp.y - rd.y box[4].z = mp.z + rd.z box[4] *= obj.GetMgn() box[5].x = mp.x + rd.x box[5].y = mp.y + rd.y box[5].z = mp.y + rd.z box[5] *= obj.GetMgn() box[6].x = mp.x - rd.x box[6].y = mp.y - rd.y box[6].z = mp.y + rd.z box[6] *= obj.GetMgn() box[7].x = mp.x - rd.x box[7].y = mp.y + rd.y box[7].z = mp.y + rd.z box[7] *= obj.GetMgn() #Calculate bouding box coordinates in screen space points = [bd.WS(p) for p in box] #Test if the current object is completely visible in the rendered safe frame for i in xrange(len(points)) : if not TestPointInFrame(points[i], safeFrame) : return False return True def MoveObjectRel(op, axis, offset) : axis = axis.GetNormalized() axis.off = op.GetRelPos() op.SetRelPos(axis * offset) def EscapePressed(bc=None) : if bc is None: bc = c4d.BaseContainer() c4d.gui.GetInputEvent(c4d.BFM_INPUT_KEYBOARD, bc) return bc[c4d.BFM_INPUT_CHANNEL] == c4d.KEY_ESC def main() : c4d.CallCommand(13957) # Konsole löschen if not op: c4d.gui.MessageDialog("please select an object") return bd = doc.GetActiveBaseDraw() cam = bd.GetSceneCamera(doc) if op is cam: return MessageDialog("can not apply on the cam") campos = cam.GetAbsPos() pos = op.GetAbsPos() axis = cam.GetMg() offset = c4d.Vector(0, 0, 10) # Create an undo-state for the camera because we will offset it. doc.AddUndo(c4d.UNDOTYPE_CHANGE, cam) c4d.StatusSetSpin() passes = 0 oppasses = 0 stopped = False # Added Niklas Rosenstein AABB Utility to get the boundingbox of a Null-Object with its Children # please note that you have to install it # http://pythonhosted.org/c4dtools/ # https://github.com/NiklasRosenstein/c4dtools <- download from here box = aabb.AABB() box.expand_object(op, recursive=True) print "AABB Values:" print "Size: ", box.size print "Midpoint: ", box.midpoint mp = box.midpoint rd = box.size #while not CheckIfInView(op, bd) : while not CheckIfInView(op, rd, mp, bd) : # pass aabb values to check routine stopped = EscapePressed() if stopped: break MoveObjectRel(op, axis, offset) oppasses += 1 print "Check in view passes: ", oppasses delta = op.GetAbsPos() - pos op.SetAbsPos(pos) if not stopped: campos -= delta cam.SetAbsPos(campos) c4d.StatusClear() c4d.EventAdd() main()