3
$\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$
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$
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$
  • 1
    $\begingroup$ I fixed the api intersect call, it was old 2.49 api. This will work in current blender. $\endgroup$ – Jaroslav Jerryno Novotny Dec 25 '14 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$ – Jaroslav Jerryno Novotny Dec 25 '14 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$ – Jaroslav Jerryno Novotny Dec 26 '14 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$ – Jaroslav Jerryno Novotny Dec 29 '14 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$ – Jaroslav Jerryno Novotny Dec 29 '14 at 22:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.