PDA

View Full Version : Scripting: Python: Trouble with raycolider and matrixes


mogh
02-08-2013, 05:39 AM
I started to dive into the raycolider utility from python and the first steps are made, but after cleaning the code and trying to evaluate which object is nearest to a start point I get weird koordniates from raycolider.

As you can see in the screenshot, the collision point of the initial target is ok, but from the obviously closer cube the collision point is somewhere in free space. I painted where it should be.
import c4d
from c4d import gui
from c4d.documents import GetActiveDocument
from c4d import utils

def GetNextObject(op):
if not op: return
if op.GetDown(): return op.GetDown()
while op.GetUp() and not op.GetNext():
op = op.GetUp()
return op.GetNext()

def numberofobjects(op):
all_list = list()
while op:
all_list.append(op)
op = GetNextObject(op)
return all_list

def GetActiveObjects(doc):
lst = list()
op = doc.GetFirstObject()
while op:
if op.GetType() == 5100: # get all poly objects
lst.append(op)
op = GetNextObject(op)
return lst

# create nulls for visualizing the hitpos
def create_null (coordinates, null_name):
mynull = c4d.BaseObject(c4d.Onull)
mynull[c4d.ID_BASEOBJECT_USECOLOR] = True
mynull[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(255,0,0)
mynull.SetAbsPos(coordinates)
mynull.SetName(null_name)
doc.InsertObject(mynull)
return

def firerayat (start, direction, length, optemp_test): # startpoint, direction, length, object to colide
collider = c4d.utils.GeRayCollider()
collider.Init(optemp_test, True) #force cache rebuild with true
did_intersect = collider.Intersect(start.GetAbsPos(), direction, length)
if did_intersect:
create_null(collider.GetNearestIntersection()["hitpos"], optemp_test.GetName()) # creates null objects at the hitpos to visualize for debugging
return collider.GetNearestIntersection()["distance"]
else:
return

def raylength (startray, endray):
return (startray.GetAbsPos() - endray.GetAbsPos()).GetLength()

def ray_direction (start, optarget):
return -(start.GetAbsPos() - optarget.GetAbsPos()).GetNormalized()

def main():
c4d.CallCommand(13957) # Konsole löschen
now = c4d.GeGetTimer() # start stopwatch

if GetActiveDocument():
doc = GetActiveDocument()
if doc.GetFirstObject():
c4d.StatusSetSpin()
op = doc.GetFirstObject()
myobject = op
all_objects = numberofobjects(op) # list off all objects
counter = len(all_objects)
secondcounter = 0
c4d.StatusSetText ('%s Objects are processed.' %(counter))
opactive = None
else:
print "Error: No Objects"
return False
else:
print "Error: No Document"
return False

opstart = doc.SearchObject("Start")
optarget = doc.SearchObject("Target")

lst = GetActiveObjects(doc)
print "Polygon Obects: ", len(lst)
hit_or_tested = []
never_hit = []

# delet all Nulls exept my start this is just for debugging
n = 0
while n < len(all_objects):
optempdelete = all_objects[n]
if optempdelete.GetType() == 5140 and not optempdelete.GetName() == "Start":
optempdelete.Remove()
n = n+1
c4d.EventAdd()
# end

length = raylength(optarget, opstart) # two times just in case
direction = ray_direction(opstart, optarget)
print "Ray length: ", length
print "Direction: ", direction
print "-------------------------------------------------------------"
temp_distance_list = []
temp_op_tested_list = []

i = 0

while i < len(lst):
optemp = lst[i]
distance = None
temp_op_tested_list.append(optemp)
distance = firerayat(opstart, direction, length, optemp) # target and testobject check ????
print optemp.GetName(), ": Collision at length: ", distance
temp_distance_list.append(distance)
i = i+1

nearest_distance = min(x for x in temp_distance_list if x is not None)
print nearest_distance
index_of_list = temp_distance_list.index(nearest_distance)
print "Nearest Object: ", temp_op_tested_list[index_of_list].GetName()
print "-------------------------------------------------------------"
print temp_op_tested_list
print temp_distance_list
print "-------------------------------------------------------------"
print 'END OF SCRIPT %s ms ' %(c4d.GeGetTimer() - now)
c4d.EventAdd()
c4d.StatusClear()
if __name__=='__main__':
main()


I think the trouble is somewhere here:
snippet from above ...
def firerayat (start, direction, length, optemp_test): # startpoint, direction, length, object to colide
collider = c4d.utils.GeRayCollider()
collider.Init(optemp_test, True) #force cache rebuild with true, dont know if it helps
did_intersect = collider.Intersect(start.GetAbsPos(), direction, length)
if did_intersect:
create_null(collider.GetNearestIntersection()["hitpos"], optemp_test.GetName()) # creates null objects at the hitpos to visualize for debugging
return collider.GetNearestIntersection()["distance"]
else:
return

def raylength (startray, endray):
return (startray.GetAbsPos() - endray.GetAbsPos()).GetLength() #is this ok?

def ray_direction (start, optarget):
return -(start.GetAbsPos() - optarget.GetAbsPos()).GetNormalized() #is this right?

If you want to test the above script put a Null called "Start" and some randomly placed polygon objects one called Target in your scene.

The script puts Null Objects at the collision points but the AbsSpace does not match or something entirely different ... I am stuck at the moment.

Any Ideas?

littledevil
02-08-2013, 12:06 PM
i will take a closer look at it later, at the first look the code looks ok, just one thing.
the absolute coordinates are NOT the world coordinates. abs/rel coords are tied to
the freeze coords system. calculating a normal out of two coords in local space does
not really make sense.

you are trying to do this object culls object thing, right ?

Darter
02-08-2013, 12:11 PM
I haven't had time to test the script but one issue appears to be the coordinate space used for the ray collison calculation.

The start point and ray direction passed to Intersect() must be in the coordinate space of the object passed to Init(). This is 'optemp' in the while loop.

The inverted global matrix of 'optemp' must be multiplied with the global positions of the start and end objects, e.g.
startPoint = ~optemp.GetMg() * opstart.GetMg().off
This will involve some restructuring of your code.

mogh
02-08-2013, 01:18 PM
Darter your code works somehow, now i have points floating somewhere in space, need to check my nulls generation two - I hate matrices can't wrap my head around it ---- but I am on track again

yes little devil I'am trying to get the impossible done ...

which me luck ---

Update:
def create_null (coordinates, null_name, optemp_test):
print coordinates, optemp_test
wc = ~optemp_test.GetMg() * coordinates
print wc
mynull = c4d.BaseObject(c4d.Onull)
mynull[c4d.ID_BASEOBJECT_USECOLOR] = True
mynull[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(255,0,0)
mynull.SetAbsPos(coordinates)
mynull.SetName(null_name + " Point")
doc.InsertObject(mynull)
return

this is oviusly wrong ... but how do i transfer the local Matrix to the other Nulls representing a position in my c4D scene? I read matrix fundamentals 5 times and still can't understand how to tackle my Nulls ...

littledevil
02-08-2013, 06:16 PM
obj_global_matrix = parent_global_matrix * obj_local_matrix,

but again , SetAbsPosition is local space, which is correct, as you do insert the
new nulls under your root null, so i do not really understand your question, i guess :)

Darter
02-08-2013, 10:03 PM
You've gone the wrong way. The hit position is converted from goal object to global coordinates like this:
def create_null (coordinates, null_name, optemp):
wc = optemp.GetMg() * coordinates
mynull = c4d.BaseObject(c4d.Onull)
mynull[c4d.ID_BASEOBJECT_USECOLOR] = True
mynull[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(255,0,0)
mynull.SetAbsPos(wc)
mynull.SetName(null_name)
doc.InsertObject(mynull)
return
The start point and ray direction still needed to be converted to goal object coordinate space:
def get_ray(start_obj, end_obj, goal):
start = ~goal.GetMg() * start_obj.GetMg().off
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}
The updated scrip (http://bit.ly/VLJIMc)t seems to be working okay with various hierarchy configurations.

obj_global_matrix = parent_global_matrix * obj_local_matrix
I'm aware of the calculation under Freeze Transformation in the SDK but find that GetMg() usually suffices. Most usage examples on Plugin Cafe since R12 support this.

mogh
02-09-2013, 02:26 PM
Thanks to both of you I did already incoporate the changes and streamlined it even more.

@Darter: Are you returning a list of lists with the get_ray def?

How do I create a List of Lists (e.g. Object : Distance) and the get the Min Value with the coresponding Object.

At the moment I have two lists which are stored seperatly and I have to get the ID of List one and the get the object with the ID of List Two. Is there a better way to do this ?


kind regards

Darter
02-11-2013, 07:15 PM
get_ray() returns a dictionary.

mogh
02-11-2013, 08:05 PM
Thanks Darter.


i found a inconsistancy between
R14 and R13 of the get Ray function

R13 works but in R14 it seems as if the direction is the opposite but nevertheless the script gives positive hits ... weird ...

have to go to bed ... but I am already excluding obects yay :bounce:
good night

mogh
02-12-2013, 01:19 PM
forget the previous post, I seem to have broken it somewhere else on the code ...

:banghead:

suddenly not the nearest object but all objects are considerated as a near object and then the script jumps over all the other loops because the list "hit_list" was already filled with all objects in the scene.

FYI:
To get that script going you only need a 2 point spline called "ray" and some poly objects to fire at. The rest is generated automatically.

import c4d
from c4d import gui
from c4d.documents import GetActiveDocument
from c4d import utils
# import math

def GetNextObject(op):
if not op: return
if op.GetDown(): return op.GetDown()
while op.GetUp() and not op.GetNext():
op = op.GetUp()
return op.GetNext()

def numberofobjects(op):
all_list = list()
poly_list = list()
while op:
all_list.append(op)
if op.GetType() == 5100 and op.GetName() != "Start Point Cloud": # get all poly objects
poly_list.append(op)
op = GetNextObject(op)
return {'all_objects_list' : all_list, 'polygon_obj_list' : poly_list }

def find_layer(layername):
root = doc.GetLayerObjectRoot() #Gets the layer manager
myLayersList = root.GetChildren()
foundname = False
for lname in myLayersList:
if lname.GetName() == str(layername):
return lname

def create_layer(name, color, display_seen):
root = doc.GetLayerObjectRoot()#Gets the layer manager
c4d.CallCommand(100004738) #create new layer
mynewLayersList = root.GetChildren() # get the new list
newlayer = mynewLayersList[-1] # get the last index of a list in this case layer
newlayer[c4d.ID_LAYER_COLOR] = color # Sets layer color
newlayer.SetName(name) # Sets layer name
newlayer[c4d.ID_LAYER_VIEW] = display_seen #set layer view setting
newlayer[c4d.ID_LAYER_RENDER] = display_seen #set layer render setting
return newlayer

def create_sphere(sub, radius):
obj = c4d.BaseObject(c4d.Osphere)
obj[c4d.PRIM_SPHERE_RAD] = radius
obj[c4d.PRIM_SPHERE_SUB] = sub
obj[c4d.PRIM_SPHERE_TYPE] = 4
obj[c4d.PRIM_SPHERE_PERFECT] = False
obj.SetName("Start Point Cloud")
# obj.SetMg(c4d.Matrix(c4d.Vector(1,1,1)))
doc.InsertObject(obj) # Insert object in document
obj.SetBit(c4d.BIT_ACTIVE)
c4d.CallCommand(12236) # Grundobjekt konvertieren
# obj.Message(c4d.MSG_UPDATE)
newobj = doc.SearchObject("Start Point Cloud")
create_display_tag(newobj)
p_positions = newobj.GetAllPoints()
"""
for p in p_positions:
print p_positions.index(p), p, obj.GetUpMg()
p_positions[p_positions.index(p)] = obj.GetUpMg()*p # gloabl coordinates
#print p_positions[p_positions.index(p)]
"""
# newobj.Remove()
obj.DelBit(c4d.BIT_ACTIVE)
c4d.EventAdd() # Send global event message
return p_positions

def create_display_tag(myobject):
mytag = myobject.MakeTag(c4d.Tdisplay)
mytag[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
mytag[c4d.DISPLAYTAG_SDISPLAYMODE] = 6
return

# create nulls for visualizing the hitpos
def create_null (coordinates, null_name, optemp_test):
wc = optemp_test.GetMg() * coordinates
mynull = c4d.BaseObject(c4d.Onull)
mynull[c4d.ID_BASEOBJECT_USECOLOR] = True
mynull[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1,0,0)
mynull.SetAbsPos(wc)
mynull.SetName(null_name + " Point")
doc.InsertObject(mynull)
return

def firerayat (start, direction, length, optemp_test): # startpoint, direction, length, object to colide
collider = c4d.utils.GeRayCollider()
collider.Init(optemp_test) #force cache rebuild with , True
did_intersect = collider.Intersect(start, direction, length) #(start.GetAbsPos(), direction, length)
if did_intersect:
# creates null objects at the hitpos to visualize for debugging
create_null(collider.GetNearestIntersection()["hitpos"], optemp_test.GetName(), optemp_test)
return collider.GetIntersection(0)["distance"]
else:
return False

""" Darter original
def get_ray(start_obj, end_obj, goal):
start = ~goal.GetMg() * start_obj.GetMg().off
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}
"""

def get_ray(start_obj, end_obj, goal): #modified to accept vectors as start instead of object Global Mg
start = ~goal.GetMg() * c4d.Vector(start_obj)
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}


def f2(seq):
# order preserving
checked = []
for e in seq:
if e not in checked:
checked.append(e)
return checked

def statusbar (counter, secondcounter):
#c4d.StatusSetText ('%s - %s Objects are processed.' %(secondcounter, counter)) # very slow
c4d.StatusSetBar(100*secondcounter/counter) #statusbar

def put_on_layer (objlist, layer):
nr = 0
while nr < len(objlist):
objlist[nr].SetLayerObject(layer)
objlist[nr][c4d.ID_BASEOBJECT_USECOLOR]=3
nr = nr+1

def delete_nulls (all_objects_list): # delet all Nulls exept my start this is just for debugging
n = 0
while n < len(all_objects_list):
optempdelete = all_objects_list[n]
if optempdelete.GetType() == 5140 and not optempdelete.GetName() == "Start" and len(optempdelete.GetChildren())<1 :
optempdelete.Remove()
n = n+1
c4d.EventAdd()

def main():
c4d.CallCommand(13957) # Konsole löschen
now = c4d.GeGetTimer() # start stopwatch

if GetActiveDocument():
doc = GetActiveDocument()
if doc.GetFirstObject():
c4d.StatusSetSpin()
op = doc.GetFirstObject()
myobject = op
all_objects = numberofobjects(op) # list off all objects
counter = len(all_objects['all_objects_list'])
all_objects_list = all_objects['all_objects_list']
poly_obj_list = all_objects['polygon_obj_list']
print "Polygon Objects: ", len(poly_obj_list)
secondcounter = 0
c4d.StatusSetText ('%s Objects are processed.' %(counter))
opactive = None
else:
print "Error: No Objects"
return False
else:
print "Error: No Document"
return False

delete_nulls (all_objects_list) # delet all Nulls exept my start this is just for debugging
rayspline = doc.SearchObject("ray")

if find_layer("Not hit"):
layer_not_hit = find_layer("Not hit")
else:
layer_not_hit = create_layer("Not hit", c4d.Vector(0.5,0,0), True)

if find_layer("Seen"):
layer_seen = find_layer("Seen")
else:
layer_seen = create_layer("Seen", c4d.Vector(0,0.75,0), True)

if find_layer("checked"):
layer_checked = find_layer("checked")
else:
layer_checked = create_layer("checked", c4d.Vector(0,0,0.5), True)

if doc.SearchObject("Start Point Cloud"):
oldsphere = doc.SearchObject("Start Point Cloud")
oldsphere.Remove()

start_point_list = create_sphere(5, 500) # Subdivisions, Radius

hit_list = []
never_hit = []
tested = []

print "Startpoint positions: ", len(start_point_list)
print "-------------------------------------------------------------"
c4d.EventAdd()

si = 0
while si < len(start_point_list):
statusbar(len(start_point_list), si)

c4d.StatusSetText ('%s Objects and %s Ray Start Points are processed.' %(len(poly_obj_list), len(start_point_list)))

nr_index = 0
while nr_index < len(poly_obj_list):

optarget = poly_obj_list[nr_index]
# print "Target: ",optarget.GetName()

if optarget not in hit_list:

tested.append(optarget)

temp_op_tested_list = []
temp_distance_list = []

i = 0
while i < len(poly_obj_list):
temp_op_tested_list.append(poly_obj_list[i])

if poly_obj_list[i] not in hit_list:
ray = get_ray(start_point_list[si], optarget, poly_obj_list[i])
distance = firerayat(ray['ray_p'], ray['ray_dir'], ray['ray_length'], poly_obj_list[i])
temp_distance_list.append(distance)
else:
temp_distance_list.append(None)
#print "Jumped: ", poly_obj_list[i].GetName()
i = i+1

# print "temp_distance_list: ", temp_distance_list
atuple = filter(None, tuple(temp_distance_list))
# print "Tuple: ", atuple

if 0 != len(atuple):
nearest_distance = min(x for x in atuple if x is not None)
# attention min() is a generator and can only be called once for a list !
# Can this be done better - List Of List or similar?
near_obj = temp_op_tested_list[temp_distance_list.index(nearest_distance)]

print "Nearest Object: ", near_obj.GetName(), nearest_distance

if near_obj not in hit_list:
hit_list.append(near_obj)

else:
print "OpTarget was in hitlist - jumped: ", optarget.GetName()

nr_index = nr_index + 1
si = si+1
# after loops

never_hit = temp_op_tested_list + never_hit
never_hit = f2(never_hit) # here or later have to watch memmory consumption !!!
tested = f2(tested)

for x in hit_list:
if x in tested:
tested.remove(x)

for z in hit_list:
if z in never_hit:
never_hit.remove(z)

# put on layer
put_on_layer (hit_list, layer_seen)
put_on_layer (never_hit, layer_not_hit)
put_on_layer (tested, layer_checked)

print "-------------------------------------------------------------"
print "Tested count: ", len(tested)
print "Hitlist count: ", len(hit_list)
# print hit_list
print "Never Hit: ", len(never_hit)
print "Ray length: ", ray['ray_length']
print "Direction: ", ray['ray_dir']
rayspline.SetPoint(0, ~rayspline.GetMg() * -start_point_list[si-1] ) # si - 1
rayspline.SetPoint(1, ~(ray['ray_length'] * ray['ray_dir']) * rayspline.GetMg() ) # something wrong here ...
rayspline.Message(c4d.MSG_UPDATE)
print "-------------------------------------------------------------"
print 'END OF SCRIPT - Duration: %s s ' %((c4d.GeGetTimer() - now)/1000)
c4d.EventAdd()
c4d.StatusClear()

if __name__=='__main__':
main()

mogh
02-13-2013, 08:56 AM
Updated script Splines for debugging are generated automatically ...

otherwise still a lot of stuff wrong ... :cry:


import c4d
from c4d import gui
from c4d.documents import GetActiveDocument
from c4d import utils
# import math

def GetNextObject(op):
if not op: return
if op.GetDown(): return op.GetDown()
while op.GetUp() and not op.GetNext():
op = op.GetUp()
return op.GetNext()

def numberofobjects(op):
all_list = list()
poly_list = list()
while op:
all_list.append(op)
if op.GetType() == 5100 and op.GetName() != "Start Point Cloud": # get all poly objects
poly_list.append(op)
op = GetNextObject(op)
return {'all_objects_list' : all_list, 'polygon_obj_list' : poly_list }

def find_layer(layername):
root = doc.GetLayerObjectRoot() #Gets the layer manager
myLayersList = root.GetChildren()
foundname = False
for lname in myLayersList:
if lname.GetName() == str(layername):
return lname

def create_layer(name, color, display_seen):
root = doc.GetLayerObjectRoot()#Gets the layer manager
c4d.CallCommand(100004738) #create new layer
mynewLayersList = root.GetChildren() # get the new list
newlayer = mynewLayersList[-1] # get the last index of a list in this case layer
newlayer[c4d.ID_LAYER_COLOR] = color # Sets layer color
newlayer.SetName(name) # Sets layer name
newlayer[c4d.ID_LAYER_VIEW] = display_seen #set layer view setting
newlayer[c4d.ID_LAYER_RENDER] = display_seen #set layer render setting
return newlayer

# ray spline
def create_spline_ray (goal, start, ray_dir, ray_length):
spl = c4d.SplineObject(2,c4d.SPLINETYPE_LINEAR) #Create a 2pt. Bezier spline in memory only ~goal.GetMg() *
spl.SetPoint(0, start * spl.GetMg() )
spl.SetPoint(1, ~spl.GetMg() * (ray_dir*ray_length)) # something wrong here ... ?
spl.Message(c4d.MSG_POINTS_CHANGED)
spl[c4d.ID_BASEOBJECT_USECOLOR] = True
spl[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1,1,0)
spl.SetName("Ray to - " + goal.GetName())
doc.InsertObject(spl)
c4d.EventAdd()

def create_sphere(sub, radius):
obj = c4d.BaseObject(c4d.Osphere)
obj[c4d.PRIM_SPHERE_RAD] = radius
obj[c4d.PRIM_SPHERE_SUB] = sub
obj[c4d.PRIM_SPHERE_TYPE] = 4
obj[c4d.PRIM_SPHERE_PERFECT] = False
obj.SetName("Start Point Cloud")
# obj.SetMg(c4d.Matrix(c4d.Vector(1,1,1)))
doc.InsertObject(obj) # Insert object in document
obj.SetBit(c4d.BIT_ACTIVE)
c4d.CallCommand(12236) # Grundobjekt konvertieren
# obj.Message(c4d.MSG_UPDATE)
newobj = doc.SearchObject("Start Point Cloud")
create_display_tag(newobj)
p_positions = newobj.GetAllPoints()
"""
for p in p_positions:
print p_positions.index(p), p, obj.GetUpMg()
p_positions[p_positions.index(p)] = obj.GetUpMg()*p # gloabl coordinates
#print p_positions[p_positions.index(p)]
"""
# newobj.Remove()
obj.DelBit(c4d.BIT_ACTIVE)
c4d.EventAdd() # Send global event message
return p_positions

def create_display_tag(myobject):
mytag = myobject.MakeTag(c4d.Tdisplay)
mytag[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
mytag[c4d.DISPLAYTAG_SDISPLAYMODE] = 6
return

# create nulls for visualizing the hitpos
def create_null (coordinates, null_name, optemp_test):
wc = optemp_test.GetMg() * coordinates
mynull = c4d.BaseObject(c4d.Onull)
mynull[c4d.ID_BASEOBJECT_USECOLOR] = True
mynull[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1,0,0)
mynull.SetAbsPos(wc)
mynull.SetName(null_name + " Point")
doc.InsertObject(mynull)
return

def firerayat (start, direction, length, optemp_test): # startpoint, direction, length, object to colide
collider = c4d.utils.GeRayCollider()
collider.Init(optemp_test) #force cache rebuild with , True
did_intersect = collider.Intersect(start, direction, length) #(start.GetAbsPos(), direction, length)
if did_intersect:
# creates null objects at the hitpos to visualize for debugging
# create_null(collider.GetNearestIntersection()["hitpos"], optemp_test.GetName(), optemp_test)
return collider.GetIntersection(0)["distance"]
else:
return False

""" Darter original
def get_ray(start_obj, end_obj, goal):
start = ~goal.GetMg() * start_obj.GetMg().off
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}
"""

def get_ray(start_obj, end_obj, goal): #modified to accept vectors as start instead of object Global Mg
start = ~goal.GetMg() * c4d.Vector(start_obj)
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}


def f2(seq):
# order preserving
checked = []
for e in seq:
if e not in checked:
checked.append(e)
return checked

def statusbar (counter, secondcounter):
#c4d.StatusSetText ('%s - %s Objects are processed.' %(secondcounter, counter)) # very slow
c4d.StatusSetBar(100*secondcounter/counter) #statusbar

def put_on_layer (objlist, layer):
nr = 0
while nr < len(objlist):
objlist[nr].SetLayerObject(layer)
objlist[nr][c4d.ID_BASEOBJECT_USECOLOR]=3
nr = nr+1

def delete_nulls (all_objects_list): # delet all Nulls exept my start this is just for debugging
n = 0
while n < len(all_objects_list):
optempdelete = all_objects_list[n]
if optempdelete.GetType() == 5140 and len(optempdelete.GetChildren()) == 0 or optempdelete.GetType() ==5101:
optempdelete.Remove()
n = n+1
c4d.EventAdd()

def main():
c4d.CallCommand(13957) # Konsole löschen
now = c4d.GeGetTimer() # start stopwatch

if GetActiveDocument():
doc = GetActiveDocument()
if doc.GetFirstObject():
c4d.StatusSetSpin()
op = doc.GetFirstObject()
myobject = op
all_objects = numberofobjects(op) # list off all objects
counter = len(all_objects['all_objects_list'])
all_objects_list = all_objects['all_objects_list']
poly_obj_list = all_objects['polygon_obj_list']
print "Polygon Objects: ", len(poly_obj_list)
secondcounter = 0
c4d.StatusSetText ('%s Objects are processed.' %(counter))
opactive = None
else:
print "Error: No Objects"
return False
else:
print "Error: No Document"
return False

delete_nulls (all_objects_list) # delet all Nulls exept my start this is just for debugging
rayspline = doc.SearchObject("ray")

if find_layer("Not hit"):
layer_not_hit = find_layer("Not hit")
else:
layer_not_hit = create_layer("Not hit", c4d.Vector(0.5,0,0), True)

if find_layer("Seen"):
layer_seen = find_layer("Seen")
else:
layer_seen = create_layer("Seen", c4d.Vector(0,0.75,0), True)

if find_layer("checked"):
layer_checked = find_layer("checked")
else:
layer_checked = create_layer("checked", c4d.Vector(0,0,0.5), True)

if doc.SearchObject("Start Point Cloud"):
oldsphere = doc.SearchObject("Start Point Cloud")
oldsphere.Remove()

start_point_list = create_sphere(5, 500) # Subdivisions, Radius

hit_list = []
never_hit = []
tested = []

print "Startpoint positions: ", len(start_point_list)
print "-------------------------------------------------------------"
c4d.EventAdd()

si = 0
while si < len(start_point_list):
statusbar(len(start_point_list), si)

c4d.StatusSetText ('%s Objects and %s Ray Start Points are processed.' %(len(poly_obj_list), len(start_point_list)))

nr_index = 0
while nr_index < len(poly_obj_list):

optarget = poly_obj_list[nr_index]
print "Target: ",optarget.GetName()

temp_op_tested_list = []
temp_distance_list = []

if optarget not in hit_list:
tested.append(optarget)
i = 0
while i < len(poly_obj_list):
temp_op_tested_list.append(poly_obj_list[i])

if poly_obj_list[i] not in hit_list:

ray = get_ray(start_point_list[si], optarget, poly_obj_list[i])
distance = firerayat(ray['ray_p'], ray['ray_dir'], ray['ray_length'], poly_obj_list[i])

create_spline_ray (poly_obj_list[i], start_point_list[si] , ray['ray_dir'], ray['ray_length']) # slow just for debugging

temp_distance_list.append(distance)

else:
temp_distance_list.append(None)
#print "Jumped: ", poly_obj_list[i].GetName()
i = i+1

# print ray['ray_p'] , "Direction: ", ray['ray_dir'], " Ray length: ", ray['ray_length']

print "temp_distance_list: ", temp_distance_list
atuple = filter(None, tuple(temp_distance_list))
# print "Tuple: ", i, atuple

if 0 != len(atuple):
nearest_distance = min(x for x in atuple if x is not None)
# attention min() is a generator and can only be called once for a list !
# Can this be done better - List Of List or similar?
near_obj = temp_op_tested_list[temp_distance_list.index(nearest_distance)]

#print "Nearest Object: ", near_obj.GetName(), nearest_distance

if near_obj not in hit_list:
hit_list.append(near_obj)

# else: print "OpTarget was in hitlist - jumped: ", optarget.GetName()
nr_index = nr_index + 1
si = si+1
# after loops

never_hit = temp_op_tested_list + never_hit
never_hit = f2(never_hit) # here or later have to watch memmory consumption !!!
tested = f2(tested)

for x in hit_list:
if x in tested:
tested.remove(x)

for z in hit_list:
if z in never_hit:
never_hit.remove(z)

# put on layer
put_on_layer (hit_list, layer_seen)
put_on_layer (never_hit, layer_not_hit)
put_on_layer (tested, layer_checked)

print "-------------------------------------------------------------"
print "Tested count: ", len(tested)
print "Hitlist count: ", len(hit_list)
# print hit_list
print "Never Hit: ", len(never_hit)
print "-------------------------------------------------------------"
print 'END OF SCRIPT - Duration: %s s ' %((c4d.GeGetTimer() - now)/1000)
c4d.EventAdd()
c4d.StatusClear()
if __name__=='__main__':
main()

pgrooff
02-14-2013, 07:44 PM
I'm still not sure what you want to achieve.
If it is just hitting an object with the ray collidion, have a look at my blog (http://blog.grooff.eu/?p=119) for a short tutorial on using the Ray Collision Xpresso node and python.
The node is used to get the polygon that was ‘hit’ by the Ray.
Python is then used to get the neighbor polygons.
All these polygons are added to the Polygon Selection Tag.

mogh
02-14-2013, 08:06 PM
I am trying to build an advanced "manual" occlusion script.

http://forums.cgsociety.org/showthread.php?f=47&t=1091288

I am hunting bugs for several days now and I've gone back to an earlier version just to understand more whats going on.

but as soon as i replace the target with all objects in a loop it gets weird ... :sad:

- First thing is to get my Globals and local Positions spot on its a mess at the moment I think.
- second is to know why it gets messy when i replace targets and goals and start points.

I have a hunch that my lists are not resetted the right way ...

anyway its to much to ask for you guys to solve my problems hence the script is quiet big already

but perhaps is there a "visual" explanation of Global and Local conversions ? :lightbulb:
kind regards mogh

mogh
02-20-2013, 12:24 PM
Yay, first working version, :bowdown:

be carefull with number of polyobjects in your scene hence it chekcs every object against every object at least 12 times !

to control the rays increase the sphere subdiv in the script

regards mogh


import c4d
from c4d import gui
from c4d.documents import GetActiveDocument
from c4d import utils
# Version 0.18

def gime_time (time_start):
milliseconds = c4d.GeGetTimer()-time_start
hours,milliseconds = divmod(milliseconds, 3600000)
minutes, milliseconds = divmod(milliseconds, 60000)
seconds = float(milliseconds) / 1000
s = "%i:%02i:%06.3f" % (hours, minutes, seconds)
return s

def statusbar (counter, secondcounter):
#c4d.StatusSetText ('%s - %s Objects are processed.' %(secondcounter, counter)) # very slow
c4d.StatusSetBar(100*secondcounter/counter) #statusbar

def GetNextObject(op):
if not op: return
if op.GetDown(): return op.GetDown()
while op.GetUp() and not op.GetNext():
op = op.GetUp()
return op.GetNext()

def numberofobjects(op):
all_list = list()
poly_list = list()
while op:
all_list.append(op)
if op.GetType() == 5100 and op.GetName() != "Start Point Cloud": # get all poly objects
obj_atribute = [op, 0, 0] # object, #_tested, #_hitcount_nearest
poly_list.append(obj_atribute)
op = GetNextObject(op)
return {'all_objects_list' : all_list, 'polygon_obj_list' : poly_list }

# Layerstuff ----------------------------------------------------------------------------------
def find_layer(layername):
root = doc.GetLayerObjectRoot() #Gets the layer manager
myLayersList = root.GetChildren()
foundname = False
for lname in myLayersList:
if lname.GetName() == str(layername):
return lname

def create_layer(name, color, display_seen):
root = doc.GetLayerObjectRoot()#Gets the layer manager
c4d.CallCommand(100004738) #create new layer
mynewLayersList = root.GetChildren() # get the new list
newlayer = mynewLayersList[-1] # get the last index of a list in this case layer
newlayer[c4d.ID_LAYER_COLOR] = color # Sets layer color
newlayer.SetName(name) # Sets layer name
newlayer[c4d.ID_LAYER_VIEW] = display_seen #set layer view setting
newlayer[c4d.ID_LAYER_RENDER] = display_seen #set layer render setting
return newlayer

def put_on_layer (objlist, layer):
nr = 0
while nr < len(objlist):
objlist[nr].SetLayerObject(layer)
objlist[nr][c4d.ID_BASEOBJECT_USECOLOR]=3
nr = nr+1
# End Layerstuff /////////////////////////////////////////////////////////////////////////////


# ray spline ---------------------------------------------------------------------------------
def create_spline_ray (optarget, start):
spl = c4d.SplineObject(2,c4d.SPLINETYPE_LINEAR) #Create a 2pt. Bezier spline in memory only ~goal.GetMg() *
spl.SetPoint(0, start * spl.GetMg() )
spl.SetPoint(1, optarget.GetMg().off * spl.GetMg() )
spl.Message(c4d.MSG_POINTS_CHANGED)
spl[c4d.ID_BASEOBJECT_USECOLOR] = True
spl[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1,1,0)
spl.SetName("Ray to - " + optarget.GetName())
doc.InsertObject(spl)
c4d.EventAdd()
# End ray spline /////////////////////////////////////////////////////////////////////////////

# sphere startpoints -------------------------------------------------------------------------
def create_sphere(sub, radius, cord_vec, delete_me):
obj = c4d.BaseObject(c4d.Osphere)
obj[c4d.PRIM_SPHERE_RAD] = radius
obj[c4d.PRIM_SPHERE_SUB] = sub
obj[c4d.PRIM_SPHERE_TYPE] = 4
obj[c4d.PRIM_SPHERE_PERFECT] = False
obj.SetName("Start Point Cloud")
obj.SetMg(c4d.Matrix(cord_vec))
obj.Message(c4d.MSG_POINTS_CHANGED)
doc.InsertObject(obj) # Insert object in document
obj.SetBit(c4d.BIT_ACTIVE)
c4d.CallCommand(12236) # Grundobjekt konvertieren
# obj.Message(c4d.MSG_UPDATE)
newobj = doc.SearchObject("Start Point Cloud")
if delete_me != True:
create_display_tag(newobj)
p_positions = newobj.GetAllPoints()
new_list = []
for p in p_positions:
# print p_positions.index(p), p, obj.GetMg()
new_list.append(obj.GetMg() * p) # gloabl coordinates
#print p_positions[p_positions.index(p)]
if delete_me == True:
newobj.Remove()
obj.DelBit(c4d.BIT_ACTIVE)
c4d.EventAdd() # Send global event message
return new_list

def create_display_tag(myobject):
mytag = myobject.MakeTag(c4d.Tdisplay)
mytag[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
mytag[c4d.DISPLAYTAG_SDISPLAYMODE] = 6
return
# End sphere startpoints //////////////////////////////////////////////////////////////////////

# create nulls for visualizing the hitpos -----------------------------------------------------
def create_null (coordinates, null_name, optemp_test):
wc = optemp_test.GetMg() * coordinates
mynull = c4d.BaseObject(c4d.Onull)
mynull[c4d.ID_BASEOBJECT_USECOLOR] = True
mynull[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1,0,0)
mynull.SetAbsPos(wc)
mynull.SetName(null_name + " Point")
doc.InsertObject(mynull)
return

def delete_nulls (all_objects_list): # delet all Nulls exept my start this is just for debugging
n = 0
while n < len(all_objects_list):
optempdelete = all_objects_list[n]
if optempdelete.GetType() == 5140 and len(optempdelete.GetChildren()) == 0 or optempdelete.GetType() == 5101:
optempdelete.Remove()
n = n+1
c4d.EventAdd()
# End create nulls ///////////////////////////////////////////////////////////////////////////

def f2(seq):
# order preserving
checked = []
for e in seq:
if e not in checked:
checked.append(e)
return checked


# Ray stuff and nearest obj -------------------------------------------------------------------------------------

""" Darter original
def get_ray(start_obj, end_obj, goal):
start = ~goal.GetMg() * start_obj.GetMg().off
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}
"""

def get_ray(start_obj, end_obj, goal): #modified to accept vectors as start instead of object Global Mg
start = ~goal.GetMg() * c4d.Vector(start_obj)
end = ~goal.GetMg() * end_obj.GetMg().off
return {'ray_p' : start, 'ray_length' : (end - start).GetLength(), 'ray_dir' : (end - start).GetNormalized()}

def firerayat (start, direction, length, optemp_test): # startpoint, direction, length, object to colide
collider = c4d.utils.GeRayCollider()
collider.Init(optemp_test) #force cache rebuild with , True
did_intersect = collider.Intersect(start, direction, length) #(start.GetAbsPos(), direction, length)
if did_intersect:
create_null(collider.GetNearestIntersection()["hitpos"], optemp_test.GetName(), optemp_test) #debugging
return collider.GetNearestIntersection()["distance"]
#return collider.GetIntersection(0)["distance"]
else:
return None

def get_nearest_obj_in_list (temp_op_distance_list):
temp_op_distance_list.sort(key=lambda x: x[1])
#print temp_op_distance_list[0][0], temp_op_distance_list[0][1]
if len(temp_op_distance_list) != 0 and temp_op_distance_list[0][1] != None:
return temp_op_distance_list[0][0]

def get_nearest_obj (start_point, target, obj_list, jump):
#jump is bullshit we can't jump anything hence it could be in the line of sight
temp_op_distance_list = [] #Reset
for obj_rows in obj_list:
opgoal = obj_rows[0] # object, #_tested, #_counter_nearest
ray = get_ray( start_point, target, opgoal )
distance = firerayat(ray['ray_p'], ray['ray_dir'], ray['ray_length'], opgoal)

if distance != None:
#print "Distance: ", distance, " - ", opgoal.GetName(), start_point
temp_op_distance_list.append( [opgoal, distance] )

near_obj = get_nearest_obj_in_list(temp_op_distance_list)
for i, row in enumerate(obj_list):
if near_obj in row:
print "Found Near Object at Row Index: ", i, " Column: ", row.index(near_obj), " obj Name: ", obj_list[i][0].GetName()
obj_list[i][2] = obj_list[i][2] + 1 # increment the hitcounter

# End ray //////////////////////////////////////////////////////////////////////

def layer_init (l_name, color, displayseen):
if find_layer(l_name):
x_layer = find_layer(l_name)
else:
x_layer = create_layer(l_name, color, displayseen)
return x_layer

# Main ----------------------------------------------------------------------------------------

def main():
c4d.CallCommand(13957) # Konsole löschen
time_start = c4d.GeGetTimer() # start stopwatch

if GetActiveDocument():
doc = GetActiveDocument()
if doc.GetFirstObject():
c4d.StatusSetSpin()
op = doc.GetFirstObject()
all_objects = numberofobjects(op) # list off all objects
counter = len(all_objects['all_objects_list'])
all_objects_list = all_objects['all_objects_list']
poly_obj_list = all_objects['polygon_obj_list']
c4d.StatusSetText ('%s Objects are processed.' %(counter))
else:
print "Error: No Objects"
return False
else:
print "Error: No Document"
return False

# delete_nulls (all_objects_list) # delete all Nulls exept my start this is just for debugging

layer_not_hit = layer_init ("Not hit", c4d.Vector(0.5,0,0), True) # True layer seen display option
layer_seen = layer_init ("Seen", c4d.Vector(0,0.25,0), True)
layer_seen_def = layer_init ("Seen more than once", c4d.Vector(0.5,0.75,0), True)
layer_checked = layer_init ("checked", c4d.Vector(0,0,0.75), True)

if doc.SearchObject("Start Point Cloud"):
oldsphere = doc.SearchObject("Start Point Cloud")
oldsphere.Remove()

if doc.SearchObject("Manual_Target_01"):
manual_target = doc.SearchObject("Manual_Target_01")
else:
manual_target = 0

start_point_list = create_sphere(5, 500, c4d.Vector(100,1,1), True) # Subdivisions, Radius, c4d.vector, deleteme=True False

hit_list = []
never_hit = []
tested = []
hit_list_definatly = []
jump = 3 # if an object was hit 2 times jump it for ray colision

print "Polygon Objects: ", len(poly_obj_list)
print "Startpoint positions: ", len(start_point_list)
print "-------------------------------------------------------------"

count_a = 0
count_b = 0
count_c = 0
si = 0
for start_cord in start_point_list:
#start_cord = start_point_list[5] #manual for debugging

c4d.StatusSetText ('%s Objects and %s Ray Start Points are processed.' %(len(poly_obj_list), len(start_point_list)))
count_a += 1

if manual_target == 0:
for row_obj in poly_obj_list:
statusbar(len(poly_obj_list)*len(start_point_list), count_b)
count_b += 1
optarget = row_obj[0] # Target for Ray - may also be a coordinate in the future
row_obj[1] += 1 # targetcounter in list of list +1
# if optarget.GetName() == "should not": create_spline_ray (optarget, start_cord) # slow just for debugging
# this is the main function which dows the magic
get_nearest_obj( start_cord, optarget, poly_obj_list, jump) # startpoint, target, objlist, jump
# End magic //////////////////////////////////////////////////////////////////////
else:
print "Manual Target Used"
statusbar(len(poly_obj_list)*len(start_point_list), count_b)
count_b += 1
optarget = manual_target # Target for Ray - may also be a coordinate in the future
create_spline_ray (optarget, start_cord) # slow just for debugging
# this is the main function which dows the magic
get_nearest_obj( start_cord, optarget, poly_obj_list, jump) # startpoint, target, objlist, jump
# End magic //////////////////////////////////////////////////////////////////////

# after loops

print "--------------"
for row in poly_obj_list:
print "Tested: ", row[1]," - Hitcounter: ", row[2], " - Name: ", row[0].GetName()
if row[1] == 0:
tested.append(row[0]) # append the object to the tested list this is not used at the moment just stored
if row[2] == 0:
never_hit.append(row[0])
else:
if row[2] == jump:
hit_list.append(row[0])
if row[2] >= jump:
hit_list_definatly.append(row[0])

put_on_layer (hit_list_definatly, layer_seen_def)
put_on_layer (hit_list, layer_seen)
put_on_layer (never_hit, layer_not_hit)
#put_on_layer (tested, layer_checked)

print "-------------------------------------------------------------"
print "Never Tested count: ", len(tested)
print "Hitlist count: ", len(hit_list)
print "Hit more than %s times: " %jump, len(hit_list_definatly)
print "Never Hit: ", len(never_hit)
print "---------------------------------------------------------------------"
print 'END OF SCRIPT - Duration (H:MM:SS:ms): %s' %(gime_time(time_start))
c4d.EventAdd()
c4d.StatusClear()

if __name__=='__main__':
main()

CGTalk Moderation
02-20-2013, 12:24 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.