hit normal help... (2.49)

I’ve been looking all over trying to work this one out, or to try and find a way around it.
I tried modifying the bullethole script from the FPS template but couldn’t quite get what I wanted.

I want to get two angles from the hit normal, or another method.
They need to be related to the local x and y axis of the object which is casting the ray.

These two angles will be used to create properties which will create parent bones which can be adjusted as a modifier to a runcyle and alow my characters to run on uneven ground.

Here are some examples of what I mean:


The parent bones can be controlled in the game engine separate from the run animation.

I need at least the normal relative to the object’s x axis, the y axis would be optional (it would control the orientation of the feet whilst the x axis would control the armature floor).

I can do some python, so I just need some kind of function which I can plug in to my existing python code.
My problem so far is that the hit normal, when converted to euler, is a global measurement, and I need something simple and local which i can use to driver the actor’s bones.

I know this kind of thing is possible, I’ve seen something similar in mechwarrior games, but I’ve also noticed that it’s not always put in to games.

v = left_hip.worldPosition
v[2] -= ### some number - approximately the height of the hip should work

# cast ray straight down
# -this only detects geometry with the 'ground' property
# -omit 'ground' and it'll detect anything (might need to remove 'collision' from your mesh faces; not sure
ob, pt, n = left_hip.rayCastTo( v, left_hip, 'ground')

normal = Vector(n) * Matrix(*character.orientation).inverse()
point = Vector(character.worldPosition) - Vector(pt)

That should get you the normal and point relative to your character. Might need to mess with the matrix to multiply normal by. Not sure (inverse) is necessary, but it seems like it should be.
Just copy it for the other hip.
I personally would parent a couple empties (left_hip ,right_hip) to the hip bones of the character to get the left_hip/right_hip positions. If you can find their positions without extra objects, you can call rayCast on character instead of its hips.

Thanks, I’ll give it a try.

I thought of another way of doing it without having to mess with matrixes, though it does mean using three rays instead of one…

Here’s a quick video of my result.

The first part of my code is taken from the excellent FPS template here at blender art forums. They used it to orient the bulet hole textures.

Can anyone suggest a better way of orienting the footprints to the direction of the character? I know my way is very awkward…

from math import sin, cos, sqrt
import Mathutils

# vector functions
def VEC_length(x):
    return sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2])
def VEC_normalize(x): 
    length = VEC_length(x)
    return [x[0]/length,x[1]/length,x[2]/length]
def VEC_cross(x, y):
    return  [x[1]*y[2] - x[2]*y[1],
             x[2]*y[0] - x[0]*y[2],
             x[0]*y[1] - x[1]*y[0]]
def VEC_min(x, y):
    return [x[0] - y[0], x[1] - y[1], x[2] - y[2]]
def MAT_trackvector(fw, y):
    if abs(abs(fw[2]) - abs(y[2])) < .001: #prevent gimbol lock
        del y[0]
    right = VEC_normalize(VEC_cross(y, fw))
    up = VEC_cross(fw, right)
    return [[right[0], up[0], fw[0]],
        [right[1], up[1], fw[1]],
        [right[2], up[2], fw[2]]]
cont = GameLogic.getCurrentController()
own = cont.owner

#sensors and actuators
walker = cont.actuators['walker']
default = cont.actuators['default']
right_leg = cont.actuators['right_leg']
left_leg = cont.actuators['left_leg']
leg_tilt = cont.actuators['leg_tilt']
step = cont.actuators['step']
engine = cont.actuators['engine']

scn = GameLogic.getCurrentScene()
ob_list = scn.objects

w_speed = own['speed'] /2.5

#set walkspeed

own['walk'] = own['walk'] + w_speed
if own['walk'] >= 120:
    own['walk'] = 0
if own['walk'] <= -120:
    own['walk'] = 0

if w_speed <= 8:
    walker.action = "walk"
if w_speed >= 9:
    walker.action = "run"

if w_speed>= 0.2:
#engine noise
engine.pitch = ((w_speed +2) /4) + 1

#leg_height setup

left_hip = ob_list['OBl_hip']
pl = left_hip.worldPosition
pl_end = pl[2] -12
l_ender= [pl[0],pl[1],pl_end]

right_hip = ob_list['OBr_hip']
pr = right_hip.worldPosition
pr_end = pr[2] -12
r_ender= [pr[0],pr[1],pr_end]

front_hip = ob_list['OBfront_hip']
pf = front_hip.worldPosition
pf_end = pf[2] -12
f_ender= [pf[0],pf[1],pf_end]

<b>#player get_ori convert to euler
player = ob_list['OBplayer']
p_ori = player.worldOrientation
p_ori_m = Mathutils.Matrix(p_ori[0],p_ori[1],p_ori[2])
p_ori_e = p_ori_m.toEuler() </b>

l_ob, l_pt, l_n = own.rayCast(l_ender, pl, 10.0, "floor", 1, 1, 0)
if l_ob:
    l_leg_length = ((pl[2] - l_pt[2]) - 6.5) *10
    own['l_height']= float(l_leg_length)

r_ob, r_pt, r_n = own.rayCast(r_ender, pr, 10.0, "floor", 1, 1, 0)
if r_ob:
    r_leg_length = ((pr[2] - r_pt[2]) - 6.5) *10
    own['r_height']= float(r_leg_length)

f_ob, f_pt, f_n = own.rayCast(f_ender, pf, 0.0, "floor", 1, 1, 0)
if f_ob:
    f_leg_length = ((pf[2] - f_pt[2]) - 5) *10
    own['tilt']= float(f_leg_length)

st= own['walk']

if st &gt;= 0 and st &lt;=9:
    own['ini']= 0 
if st &gt;=10 and st &lt;=25 and own['ini']==0:
    own['ini']= 1
if st &gt;=26 and st &lt;=74:
    own['ini']= 0    
if st &gt;=75 and st &lt;=80 and own['ini']==0:    
    own['ini']= 2
if st &gt;=81:
    own['ini']= 0
leg = 1
own['step_set'] =0
make_r = f_ob and own['ini']== 1
if make_r:    
    own['ini']= 3
    leg = 2
    own['step_set'] =1
make_l = f_ob and own['ini']== 2
if make_l:
    own['ini']= 3
    leg = 1
    own['step_set'] =1

footstep_obj = step.objectLastCreated

#footstep_ori to euler

<b>def re_oreint():
    f_ori = MAT_trackvector(hit_norm, [0.0,0.0,1.0])
    f_ori_m = Mathutils.Matrix(f_ori[0],f_ori[1],f_ori[2])
    f_ori_e = f_ori_m.toEuler() 
    re_ori = (f_ori_e[0],f_ori_e[1],p_ori_e[2])
    re_ori_e = Mathutils.Euler(f_ori_e[0],f_ori_e[1],p_ori_e[2])
    re_ori_m = re_ori_e.toMatrix()
    return re_ori_m</b>

#left_foot place footprint
if l_ob and leg == 2 and own['step_set'] ==1:
    hit_pos = l_pt
    hit_norm = l_n
    <b>re_matrix = re_oreint()</b>
    footstep_obj.localOrientation = re_matrix
    footstep_obj.localPosition = hit_pos
    own['step_set'] =0

#right_foot place footprint
if r_ob and leg == 1 and own['step_set'] ==1:
    hit_pos = r_pt
    hit_norm = r_n
    <b>re_matrix = re_oreint()</b>
    footstep_obj.localOrientation = re_matrix
    footstep_obj.localPosition = hit_pos
    own['step_set'] =0