I haven't been able to extract the data directly from the render, but i have been able to put together a code from different sources that works. I'm posting it here in case somebody finds it useful.
import bpy
from mathutils import Vector, Matrix
import random
# In case we wabnt to asign a random color to the shadow
def get_random_color():
''' generate rgb using a list comprehension '''
r, g, b = [random.random() for i in range(3)]
return r, g, b
#We create the material for the shadow and assignt transparency
mat_shadow=bpy.data.materials.new('shadow')
#mat_shadow.diffuse_color=get_random_color()
mat_shadow.diffuse_color=(0.01,0.01,0.01)
mat_shadow.alpha=0.5
mat_shadow.use_transparency = True
#From this point we assign the objects we are gonna work with
#We assign the light, a point in this case
LightObj = bpy.data.objects['Point']
light_mx = LightObj.matrix_world
light_location = Vector((light_mx[0][3], light_mx[1][3], light_mx[2][3]))
#We select the surface we want the shadow
Surface_Object = bpy.data.objects['Plane']
surface_mx = Surface_Object.matrix_world
imx=surface_mx.inverted()
#we select the test objects
test_names = [ 'Cube','Suzanne']
test_objs = [bpy.data.objects[name] for name in test_names]
test_mxs = [ob.matrix_world for ob in test_objs]
#We loop througth the objects to create the shadows
for ob, mx in zip(test_objs, test_mxs):
pol_accepted=[]
shadow_mesh=[]
shadow_object=[]
cont=0
#We loop through all the faces of the object
for poly in ob.data.polygons:
Loca_hit=[] # Where the ray hit
Vertice_hit=[] #if vertice hits we save it here
hits=0
#We loop through the vertices of the face
for indx in poly.vertices:
i=indx #We save the indx in a variable, if not it will change to -1 when used
P0=imx * light_location
P1=imx *mx*ob.data.vertices[i].co
#We check that the object it's not higher than the light
#We should check in a more general case, that the point of the light it's farther than the point of the object
if P0[2]>P1[2]:
#We use the equation of the line that goes through two points to select the point of the line that
#goes through P0 and P1, bellow the plane
d=P1-P0
n=(surface_mx[2][3]-1)/d[2]
Pfin=P1+d*n
re,loc, no, ind = Surface_Object.ray_cast(P0, Pfin,distance=1.70141e+10)
if re:
hits += 1
Loca_hit.append(surface_mx *loc)
Vertice_hit.append(surface_mx *P1)
#We only consider a face has a shadow if at least three points touch, the minimum to crerate a face
if hits>=3:
#We create the vertices with the hits and the original points, the faces to make a 3D mesh of each face shadow
verts=Vertice_hit+Loca_hit
f1=[n for n in range(hits)]
f2=[n+hits for n in range(hits)]
faces=[tuple(f1),tuple(f2),(0,hits,hits*2-1,hits-1)]
for n in range(hits-1):
faces.append((n,n+hits,n+1+hits,n+1))
name='shad'+str(cont)
shadow_mesh.append(bpy.data.meshes.new(name))
shadow_object.append(bpy.data.objects.new(name,shadow_mesh[-1]))
bpy.context.scene.objects.link(shadow_object[-1])
shadow_mesh[-1].from_pydata(verts, [], faces)
# Calculate the edges
shadow_mesh[-1].update(calc_edges=True)
cont += 1
# We change the name of the first
if len(shadow_object)!=0:
shadow_object[0].name='Shadow_'+str(ob.name) #We change the name of the first shadow
#We are going to join all the meshes together from the object
scene = bpy.context.scene
ctx = bpy.context.copy()
# one of the objects to join
ctx['active_object'] = shadow_object[0]
ctx['selected_objects'] = shadow_object
# we need the scene bases as well for joining
ctx['selected_editable_bases'] = [scene.object_bases[ob.name] for ob in shadow_object]
bpy.ops.object.join(ctx)
# Assign material to object
if shadow_object[0].data.materials:
# assign to 1st material slot
shadow_object[0].data.materials[0] = mat_shadow
else:
# no slots
shadow_object[0].data.materials.append(mat_shadow)
shadow_object[0].show_transparent = True

