"Placing" a reflection with ray_cast

let´s say, i want to place the reflection on the sphere a little bit to the right, on this exemple i can simply move the reflection plane to the right, but on more complex objects it can be a little bit tricky,


so, the plan is, to cast a ray on to the object and reflect it, so we can retrieve a location to put the white plane on.


i´m not a good python scripter (the other reason that im trying to do this, is to learn python :smiley: ), I found this function ray_cast(star, end), that returns a location, the normal, and the face index that the ray casted on.
the code i wrote:

ob = bpy.data.objects[‘Mesh’]

s = [0,0,0] # start location
e = [-5,0,0] # end location

ray = bpy.types.Object(ob).ray_cast(s,e)
but it always returns something strange like:
(0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -1) <-- ray casted on a plane at location(-5,0,0) and with a 45º rotation,
(-0.000002, 0.000000, 0.000000, 0.656184, -0.097809, 0.748235, 755) <-- ray casted on a sphere´s face at location(-5,0,0)


Here’s the commit log:
http://www.mail-archive.com/[email protected]/msg11306.html

It says there that it casts in object space. That means that to get the desired results you have to either:

  1. move/rotate/scale your object in editmode.
  2. press CTRL-A and apply the 1st three items.

Then run the script.

This would be a really useful addition! I’ll be watching this thread.

Yes, I know about the object space stuff, after some research i found out what those numbers were,
the first output (with plane rotated 45º) the “error” occur because the ray did´nt hit the face, the solution for that is to extrapolate the ray´s lenght, and the “weird” normal output is the X,Y,Z where the normal has the lenght of 1 unit

now, i only need help finding out the reflected vector (where the reflected plane is, or will be), we can use the AngleBetweenVecs() function, but them we need to rotate the inicial vector somehow using eulers rotation (no idea if this is right, I´m not a good math guy)
or we can use the reflection() function, look´s like this method is more apropriate (dãr) but it retuns some weird numbers, that apparently is not a reflection =(

Glad to see you are interested, Im not a good coder/math guy, so this script is a realy good learning resource, at least for me =]
so thanks in advance!

Wings has a similar function for placing highlights: you select a light and a face, then it reorients the light so that it reflects off of the face and into the camera. Is this what you are trying to do?

I’m not 100% sure, but I’d guess the the reflection() function is the way to go. How do you know it’s not returning the reflected vector?

yes, thats exactly what I´m trying to do, without repositioning a lamp, only showing a line where that position is, but that´s a small detail.

here´s an exemple of the output from start.reflected(nor):
ps1 : nor = the normal output from the ray_cast()


the object center is set at (0,0,0) and no rotation, scale is applied to the obj, so object space = world space (right?).
Now look at the point that the reflection() function returned = (1, -1.4142, -1), looks like the opposite from what it “should” return, =(

here is the script that i used to calculate that:

import Mathutils
import math

from Mathutils import Vector


starVec = Vector(2,0,0)
endVec = Vector(-6,0,0)


ob = bpy.data.objects[‘Mesh.001’]

ray = ob.ray_cast(starVec, endVec)

col = Vector(ray[0][0],ray[0][1],ray[0][2])
nor = Vector(ray[1][0],ray[1][1],ray[1][2])

newVec = starVec.reflect(nor)

print("new vec —> " + str(newVec))

ps2: sorry for the misspelling in the picture =]


I think it would be best to have the reflected line displayed, as Hperigo said. That way you can place whatever you want in the reflection, be it a white plane to accent the surface or for example to frame up a character in the reflection of a car. Very useful I think.

yup, that´s exactly the point, but i can´t get it to work =(

Yep, that’s what I get.
The normal is: [-0.500000, -0.707107, 0.500000]
The reflected vector is: [1.000000, -1.414214, 1.000000]

I checked it against standard code and the result is the same. So my guess is that the code is correct.
V = starVec
N = nor
R = V - (2 * V.dot(N)) * N

Maybe it just looks wrong. You should try drawing a line (a mesh with 2 verts at the endpoints) to visualize the results better.

nop, pretty sure it looks wrong… :frowning:


maybe the values are beeing missinterpreted?

That does look wrong. It seems to give the correct vector when the plane is rotated on just one axis. I can’t seem to figure this one out.

yeap… well thanks anyway!

which Blender you are using?

the vector reflection function in Blender 2.49 was wrong. It was fixed in the svn, but Blender 2.49b was released before that.

My suggestions:

  1. to use Blender 2.49svn (i.e. a version newer than 23037 - Sept. 2009
  2. to write your own reflect function (http://www.pasteall.org/7654/python)
  3. to use Blender 2.5 (which has it fixed already)

more on that:

I hope it helps !

Actually it looks like you are using Blender 2.5 …

In that case I think you forgot to add the reflect_vector to your hit_point.
A reflect vector is a direction from the origin [0,0,0], for you need to “move” it to the hit position to visualize it properly.

(as scorpius said to draw the 3D elements - rays, points - helps A LOT)

yeap, I´m using blender 2.5

ummm… I will try to do that… thanks for the help man!

so, i tried to use the “custom” function from here and it worked!
well kind of, the result had the Y, and Z axis mirrored, so i multiplyed those by -1, and it kind of worked, still a litle bit wrong, but its an improvement!

here are some pics:


as you can see, the reflection its pretty close, but still a little bit off the place it shoud be…

and the code:

import Mathutils as M
import bpy, math

from Mathutils import Vector

begin the reflected ray calculation

def Ray_calc():

starVec = Vector(2,0,0)
endVec = Vector(-6,0,0)


ob = bpy.context.active_object

ray = ob.ray_cast(starVec, endVec)

col = Vector(ray[0][0],ray[0][1],ray[0][2]) #gets the coalision vector
nor = Vector(ray[1][0],ray[1][1],ray[1][2]) #gets the normal vector

newVec = Vector(vec_reflect_py(starVec, nor)) #reflects
newVec += col #adding the coalinsion vector to the result vector
newVec = Vector(newVec[0],newVec[1]*-1,newVec[2]*-1) #weird Y, Z axis flipin

return starVec, col, newVec

#begin reflect function
def vec_reflect_py(vec, mirror):

reflect = [0.0, 0.0, 0.0]
# normalizing
length = 0.0
for i in range(3):
 length += mirror[i] * mirror[i]

length = float(math.sqrt(length))

for i in range(3):
 mirror[i] /= length
dot2 = 2 * (vec[0]*mirror[0]+vec[1]*mirror[1]+vec[2]*mirror[2])

reflect[0] = vec[0] - (dot2 * mirror[0])
reflect[1] = vec[1] - (dot2 * mirror[1])
reflect[2] = vec[2] - (dot2 * mirror[2])

return reflect

#begin to draw the calculated ray
def Ray_draw(v0,v1,v2):

verts_loc = []

a = 0    
b = 0
c = 0
while a &lt; 3:
   a += 1
while b &lt; 3:
   b += 1
while c &lt; 3:
   c += 1
print("sequence ---&gt; " + str(verts_loc))

mesh = bpy.data.meshes.new("Ray")

mesh.verts.foreach_set("co", verts_loc)
#mesh.faces.foreach_set("verts_raw", faces )
scene = bpy.context.scene

ob_new = bpy.data.objects.new("Reflection Vectors", 'MESH')
ob_new.data = mesh
ob_new.selected = True

ob_new.location = (0,0,0)

obj_act = scene.objects.active

Ray_calc() #executes the reflection
Ray_draw(Ray_calc()[0],Ray_calc()[1],Ray_calc()[2]) #draws the reflection

ps1: the ray starts at (2,0,0), and ends at (-6,0,0) OBJECT SPACE, so a good idea is to place the mesh center at (0,0,0) global space, with applied rotation, scale, so that the coordinates don´t get mixed up.

ps2: the Ray_draw function creates a new object with 3 vertices, if no face is hited by the ray, a ZeroDivisionError will occur