4
$\begingroup$

I think that Blender might do what I have in mind, but I am not a Blender and Python guru, so I am looking for directions.

I need to determine if a point in space is obscured by an object, i.e. does it cast the shadow over it (there is one source of light, the sun). This has to be done for:

  • many different objects of different shapes but of similar size: they are fairly simple with just a few surfaces (e.g. a collection of cubes of slightly different sizes and orientations). Each is stored in one OBJ, so there are many OBJs. The analysis should be done one by one.
  • a collection of many points that need to be tested, each has different 3D coordinates. For each point it should be determined if a shadow is cast over it or not, so the result is binary.
  • for a different position of the sun (e.g. 100-200), to mimic the variable position of the sun during the day and throughout the year.

I am interested in two things: how to automate this, and is there a function in Blender that determines if a point is obscured or not.

What I have so far is shown below. For the simplicity of the approach let's assume that all points that need to be tested have the same Z coordinate (i.e. they are planar).

for each OBJ:
    +Load the OBJ
    +Place a plane at the Z value of the points to be tested
    for each position of the sun:
            +Render the image so only the plane with the extent of the shadow is visible
            (option Cast Only, and the camera is orthogonal and has a top view.)
            +Export the image
            +Import the image with an image processing library in Python
            for each point to be tested is a shadow cast over it:
                            +Find the pixel in the image that corresponds to
                            the position of the point
                            if the pixel value at that point is dark:
                                   it is obscured
                            if not:
                                   it is not obscured

Is there a better method for this? Please note that the points might have different Z coordinates, so my method is not optimal (it would require multiple planes).

$\endgroup$

2 Answers 2

5
$\begingroup$

I would like to point out that the blender python has an API for ray_casting objects so you don't have to manually loop over all the faces of the object your self.

http://www.blender.org/api/blender_python_api_2_63_8/bpy.types.Object.html?highlight=object.ray_cast#bpy.types.Object.ray_cast

import bpy
from mathutils import Vector, Matrix

SunObj = bpy.data.objects['Sun']
sun_mx = SunObj.matrix_world

Surface_Object = bpy.data.objects['Test Points']
surface_mx = Surface_Object.matrix_world
for v in Surface_Object.data.vertices:
    v.select = False

#here some simple test objects
test_names = ['Torus', 'Suzanne', 'Cone']
test_objs = [bpy.data.objects[name] for name in test_names]
test_mxs = [ob.matrix_world for ob in test_objs]

#we get the sun location from the world matrix
sun_location = Vector((sun_mx[0][3], sun_mx[1][3], sun_mx[2][3]))

#Test test points are stored in object data
test_points = [surface_mx * v.co for v in Surface_Object.data.vertices]

hits = 0
for ob, mx in zip(test_objs, test_mxs):

    imx = mx.inverted() #ray_cast happens in local space
    for i, pt in enumerate(test_points):
        loc, no, indx = ob.ray_cast(imx * sun_location, imx * pt)

        #simulate shadow with selection of the test vert
        if indx != -1:
            hits += 1
            Surface_Object.data.vertices[i].select = True

print(hits) 

a sample blend https://www.dropbox.com/s/004eu6aaqxg6zxy/ray_cast_sun.blend?dl=0

enter image description here

Also works on non planar points

$\endgroup$
0
4
$\begingroup$

You dont need to render any images or setup any planes. This is what you should do:

for each OBJ:
    +Load the OBJ

for each position of sun:
    for each point to be tested:
         +Create a ray starting at point with direction of sun (sun's local Z axis)
         +Test if ray intersects any of OBJs, if yes:
             it is obscured
         if not:
             it is not obscured

sun's local Z axis you get from up_vector=(0,0,1) and sun's world_matrix:

from mathutils import Vector
up = Vector((0,0,1))    # global Z vector
up.rotate(bpy.context.scene.objects['SUN_NAME_HERE'].matrix_world)
# up is now sun's local Z axis - the ray direction

The part Test if line intersects any of OBJs is done by looping over all OBJs triangles and testing mathutils.geometry.intersect_ray_tri() function.

If your object have lots of triangles test the OBJs bounding box first.

$\endgroup$
13
  • 1
    $\begingroup$ I fixed the api intersect call, it was old 2.49 api. This will work in current blender. $\endgroup$ Dec 25, 2014 at 11:42
  • 1
    $\begingroup$ point_loc = mathutils.Vector((x,y,z)) where x,y,z are coords of point to be tested. sun_loc = sun.location where sun is bpy.data.objects['YOUR_SUN_NAME']. Then ray is (sun_loc - point_loc) and ray origin is point_loc $\endgroup$ Dec 25, 2014 at 22:37
  • 1
    $\begingroup$ Oh sure, i forgot that your rays are parallel. The direction of sun is its local Z axis. Updated the answer with how to get it. $\endgroup$ Dec 26, 2014 at 10:28
  • 1
    $\begingroup$ I see, consider 2 vectors point-intersection and ray. If their dot product is greater than 0 they have the same orientation. If its < 0 the intersection was a false positive then. blender.org/api/blender_python_api_2_60_1/… $\endgroup$ Dec 29, 2014 at 22:05
  • 1
    $\begingroup$ Vectors have same oriented direction if their cross product is zero and dot product is greater than zero. There's no need to test the direction (the vectors are on a line), so the orientation test should be enough. $\endgroup$ Dec 29, 2014 at 22:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .