# Is it posible to get the coordinates of the shadow from its rendering?

I need to know the volume of the shadow cast by an object by a light or at least the coordinates of the contour of the shadow in the floor. I thought that it would be possible to get the coordinates from the rendering, as it must calculate them to generate the shadow. Im new to both python and blender so I'm not sure if it's posible.

I found a diferent methode with the api in this question Using Blender to investigate the cast of shadows from an object onto a specific point in space , but i'm wondering if its posible to extract the information directly from the rendering.

## 1 Answer

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