Casting a ray

In the BGE, casting a ray is easy, there are rayCast and rayCastTo fuctions.
How can I cast a ray and detect what is it coliding with in Blender python, without entering the game engine?

Anyone ?
Does anyone here have experience in coding line-plane intersections ?

i haven’t found anything built-in yet. what for do you need it? maybe some addon is already using such a function…

niko
.

go check out mathutil and geometry modules
many functions like that !

salutations

@niko: I need to cast a ray from a vertice in a specific direction. If the ray hits something I need the position of intersection, and if possible any other info, like color or something.

@RickyBlender: Thank you, the geometry module has something called “intersect_ray_tri”. I can use that to cast a ray and detect if it hits a specific triangle.

I am making a small script that will be used to calculate AO vertex based, and store it in vertex colors.
The procedure is pretty simple:


for every object:
    if object has mesh:
        for every vertice in the mesh:
            set vertex color = black
            -cast 5 rays, one in the direction of the normal, and other 4 spread around the normal in a kind of "hemisphere"
           for every ray:
               if the ray hits nothing:
                   set vertex color += ambient color

Something like that should work, and than I can improve on it.

The funny thing is, its easier to make it in the game engine, but I think I can not save vertex colors calculated in realtime.

Or maybe I can…hmm

Anyone ???

Here is something I cobbled together along that line.(With aothms help)


def pointInsideMesh(point,ob):
    # provided by aothms.
    # axes = [ mathutils.Vector((1,0,0)), mathutils.Vector((0,1,0)), mathutils.Vector((0,0,1))  ]
    # @Abel, ok just one then
    axes = [ mathutils.Vector((1,0,0)) ]
    outside = False
    for axis in axes:
        # @Atom you're right, ray_cast is in object_space
        # http://www.blender.org/documentation/250PythonDoc/bpy.types.Object.html#bpy.types.Object.ray_cast
        mat = mathutils.Matrix(ob.matrix_world).invert()
        orig = mat*point
        count = 0
        while True:
            location,normal,index = ob.ray_cast(orig,orig+axis*10000.0)
            if index == -1: break
            count += 1
            orig = location + axis*0.00001
        if count%2 == 0:
            outside = True
            break
    return not outside

It is kind of a generic ray hit on an object.

Thank you Atom, this is awesome.

Edit:
Tested it with 1 ray, and its working. There is however one small problem, if you cast a ray from a vertice, it hits the vertice. So just offset the ray start position a little.

can you explain what it does!

i mean you avhe an object with some faces then waht you make tri’s out of it of find the normal of each face then cast a ray following the normal or what else ?

thanks

The script calculates Ambient Oclusion, check it out. I will add a lot of stuff to it , but this is the basic setup.

The blend file
For now the script looks like this:


import bpy
from mathutils import Vector

for object in bpy.data.objects:
    
    mesh = object.data                              #<---mesh
    
    vertex_color = mesh.vertex_colors[0].data
    faces = mesh.faces
    vCol = []
    ambient = bpy.data.worlds.get("World").ambient_color
        
    for vert in mesh.vertices:
        x,y,z = vert.co
        normal = vert.normal
        r,g,b = 0,0,0
        
        ##-----Calculate RGB----------
        rays = [(0,0,1),(0.866,0,0.5),(0,0.866,0.5),(-0.866,0,0.5),(0,-0.866,0.5)]
        
        for ray in rays:
            radius = 20
            start = Vector((x+(ray[0] * 0.001), y+(ray[1] * 0.001), z+(ray[2] * 0.001)))
            end_p = Vector((x+(ray[0] * radius), y+(ray[1] * radius), z+(ray[2] * radius)))
            hit = object.ray_cast(start,end_p)
            
            if hit[2]== -1:
                r,g,b = r+ambient[0],g+ambient[1],b+ambient[2]
        ##---------------------------
        
        
        col = (r,g,b)
        vCol.append(col)
    
    #Set Color
    for i in range(len(faces)):
        v = vertex_color[i]
        f = faces[i].vertices_raw
        v.color1 = vCol[f[0]]
        v.color2 = vCol[f[1]]
        v.color3 = vCol[f[2]]

Here is a result:


sound interesting

can you explain how it does this ambient occlusions?

i mean do you add a lot of lamps around then calculate it ?

cause i think i already seen some ligth set up for this like Fake GI and fake AO?

cannot load the file has to be member of google and i’m not !

if i take script should it do the same then file?

or if file is less thant 1MB you can upload here in thread
should be this is a small script i and add all the suzanne afterward!

thanks

ok just ran the script and got an error

File “C:\Users\RJ\0blend25\0beta36326\old25files1\lgithfakeaoscrip1\fakeao5.bl
end\fakeao5.py”, line 8, in <module>
AttributeError: ‘Camera’ object has no attribute ‘vertex_colors’

how to correct that ?
vista version 36415

salutations

can you explain how it does this ambient occlusions?
Its still very basic, but it works. The script takes every vertice in the mesh, and cast rays in a few predefined directions (my last version uses ~25). Vertex colors are set as black in the beginning, and if a ray hits nothing it adds a little bit of ambient color to the vertex.
And that is it… for now. I will try to implement GI with this, but at this time it seams impossible.

Anyway this is just a simple script to add a little depth to the entvironment. As I usualy prototype in Texture Face Mode, I don’t want to spend a lot of time working on the look of the entvironment, I just want to have something playable as fast as possible.

Edit:
About the error:
The script is currently very limited, since I wanted to test it as soon as possible, I didn’t spend time cleaning it and finishing.
Your scene should have only 1 object, and that object must be in triangles (ctrl+t). The object must have alleast 1 vertex color layer.

Next version of the script will fix all that.

ok i’ll wait your next version

but what is the overall goal here make a sort of new GI or Fake AO using ray tracing ?
and is it to complete what we have in 2.5 or may be add a new fake light set up to render
but definitively interesting!

let us know as soon as possible and good luck

thanks

There is a major problem, ray_cast works only inside an object. So 2 objects can’t shade each other.
I will try to work around that, maybe even stop acting smart and do all of this inside the BGE where its much easier… wich is sad.

The first goal here is to add a bit of depth to a test environment. So when prototypeing a game, I can quickly make something that looks nice. And focus on the gameplay and mehanics.

The other goal is to practice Python, and get ready to make some sick addons, mostly GE related.

Tonight version

import bpy
from mathutils import Vector

for object in bpy.data.objects:
    
    mesh = object.data                     #&lt;---mesh
    
    if hasattr(mesh,"vertex_colors"):
        
        if mesh.vertex_colors:    
            vertex_color = mesh.vertex_colors[0].data
            faces = mesh.faces
            vCol = []
            ambient = bpy.data.worlds.get("World").ambient_color
                
            for vert in mesh.vertices:
                x,y,z = vert.co
                normal = vert.normal
                r,g,b = 0,0,0
                
                ##-----Calculate RGB----------
                vects = [(0.5, 0.0, -0.133), (0.866, 0.0, -0.5), (1.0, 0.0, -1.0), (0.707, 0.707, -1.0), (0.612, 0.612, -0.5), (0.353, 0.353, -0.133), (0.0, 0.0, 0.0), (0, 0.5, -0.133), (0, 0.866, -0.5), (0, 1.0, -1.0), (-0.707, 0.707, -1.0), (-0.612, 0.612, -0.5), (-0.353, 0.353, -0.133), (-0.5, 0, -0.133), (-0.866, 0, -0.5), (-1.0, 0, -1.0), (-0.707, -0.707, -1.0), (-0.612, -0.612, -0.5), (-0.353, -0.353, -0.133), (0, -0.5, -0.133), (0, -0.866, -0.5), (0, -1.0, -1.0), (0.707, -0.707, -1.0), (0.612, -0.612, -0.5), (0.353, -0.353, -0.133)]
                        
                for vect in vects:
                    ray = (normal[0]+vect[0],normal[1]+vect[1],normal[2]+vect[2])
                    radius = 4
                    start = Vector((x+(normal[0] * 0.00001), y+(normal[1] * 0.00001), z+(normal[2] * 0.00001)))
                    end_p = Vector((x+(ray[0] * radius), y+(ray[1] * radius), z+(ray[2] * radius)))
                    hit = object.ray_cast(start,end_p)
                    
                    if hit[2]== -1:
                        r,g,b = r+(ambient[0]/25),g+(ambient[1]/25),b+(ambient[2]/25)
                    else:
                        hit_pos = hit[0]
                        dist = hit_pos[0]-start[0]**2 + hit_pos[1]-start[1]**2 + hit_pos[2]-start[2]**2
                        rs = 20**2
                        
                        fact = dist / rs
                        #print (dist)
                        
                ##---------------------------
                
                
                col = (r,g,b)
                vCol.append(col)
            
            #Set Color
            for i in range(len(faces)):
                v = vertex_color[i]
                f = faces[i].vertices_raw
                v.color1 = vCol[f[0]]
                v.color2 = vCol[f[1]]
                v.color3 = vCol[f[2]]
                v.color4 = vCol[f[3]]

well to get some texture in viewport with UV you can use GLSL!

now you could add around your scene a box and put the camera inside!
some of the light set up use this technic!

like the lightbox set up

salutations

do you have a file sample with scene where it works ok

like to test this and see results!

thanks

Try changing the ambient color in the world panel and that press Alt+P in the text editor to run the script.

Attachments

Vertex AOv2.blend (158 KB)

ok very interesting

but you coild add a panel where you set the color and redo you script
would be faster i think!

but looking nice!

thanks