How to find thickness of a wall?

My player casts a ray onto the wall at point A. Now how do I find the position of point B on the other side of the wall? I thought of having an empty looking back from the end of the ray, but as my example shows, I may have multiple objects or even an extension of the same object between the player and the empty. Additionally I want to find B in a single frame, rather than through any trial-and-error searching over multiple frames.

I don’t seem to be coming up with any ideas for how I might solve this problem, so perhaps I don’t even need a full answer, just a pointer to get me started in the right direction. Thanks for any help!

You could use Python to cast a ray slightly past the initial collision point along the same vector. This would give you the result within the same frame.

-edit-
This assumes that every ‘wall’ it hits has thickness, and that the thickness is greater than the “slightly past” amount that I mentioned. Although, if the second ray doesn’t hit anything, then you’d know that the wall had no thickness

Thank you for the reply! The only trouble I’m finding with your solution is if the object has “Box” bounds, the ray formed inside the object doesn’t seem to detect the other side of the box. Maybe it’s a testing error as I’ve only spent a few moments working with your solution, but thank you none the less! I’ll keep working on it.

Hi-the first thing that came to my mind is to use the collision counter - and the rayCast check to get not the first face of the ray collision, but the second or third, or to get all these positions as a dictionary or a nested list of positions and select the farthest position in it or the one that is needed - through sorting or iterating through the data
ray = own. rayCast(start, finish, 10,")
hit = ray[0]
position = ray[1]
if hit:
if ‘cube’ in hit and not hit in dict:
dict[hit]=position

My bad, I assumed you were using static collision. With static collision, a ‘wall’ is actually two faces on the same mesh which each have collision, which would work with the solution I mentioned. AFAIK, static collision is the most efficient way to do terrain collision.

If you’re using box collision, then you might need to do fancy maths based on the size and orientation of the box to work out where the other side is. I think box collision means that the entire area counts as collidable. Maybe you could still use rays, but fire lots of them in reverse direction and progressively further away from the start location until you find the edge. The moment you get a distance >0, you know you’ve fired the ray from outside the box.

start_position.getVectTo(end_target)

You now have the direction, now simply cast a ray in that direction, it hits A, get position A and add the wall thickness to A, now you are at B cast a ray from B to C and repeat… until you hit the end_target.

This is a bounding box.

WINDING

In bpy.data.objects[name].bound_box, these points are given in this exact order. At least up to 2.79.

If the front face of your wall faces towards Y, then width is (p0 - p4).length, and thickness is (p0 - p3).length. Turn it the other way around if your wall faces towards X.

In upbge you could calculate these points on the fly with the min and max values of an objects cullingBox attribute. Point 0 being (min[0], min[1]), whereas point 4 is (max[0], min[1]) and point 3 (min[0], max[1]). Note I’m discarding the Z as unless you also need to calculate how tall the wall is (or if it rotates weird like that), you can ignore it.

But if you’re not on upbge, or you just want to know these values beforehand rather than do the calculation at runtime, you can just get them. Write down a tool script that performs the calculation, select an object to operate on, hit the run script button, and done.

Ah, alright. Here, let me write the tool for you.

import bpy; from mathutils import Vector;

ob     = bpy.context.object;
bounds = ob.bound_box;

p0, p3, p4 = Vector(bounds[0]), Vector(bounds[3]), Vector(bounds[4]);

if "thickness" not in ob.game.properties:
    bpy.ops.object.game_property_new(type='FLOAT', name="thickness");

if "width" not in ob.game.properties:
    bpy.ops.object.game_property_new(type='FLOAT', name="width");

ob.game.properties["thickness"].value = (p0 - p3).length;
ob.game.properties["width"    ].value = (p0 - p4).length;

Now it’s a game property so you can just go object["thickness"] when you need it.

Hope some of this is useful.

EDIT: Vector.length is not a callable. My bad.

Thank you all for the replies! When I have time I will certainly be experimenting with the ideas you’ve given me.

@TheDave, you were correct that I am using Static Collision, rather it was Box Bounds that seemed to create the issue. My ray could not detect the inside face of the box bounds, and so could not determine distance to the other side of the box. When I do not have Box Bounds checked it seems like your idea will work very well for what I need. (Actually, when I think it over, this “problem” may provide a solution to an issue with my idea I was looking at down the road.)

@Villi89, thanks for the idea. Unfortunately, due my use case, I can not be sure that my initial ray cast will be long enough to detect the far side of the wall, though I certainly think that your solution will be useful to me in other uses.

@Cotaks,

get position A and add the wall thickness to A

I’m afraid I modified the question I was going to ask after I had made my example image, so it might be a bit misleading. Unfortunately “wall thickness” is what I’m trying to determine.

@Liebranca, Thank you, if I have to fall back to manually imputing each wall’s thickness this could certainly save me a lot of time. I was hoping to find some all-encompassing method that would address Box Bounds and not Box Bounds objects, with a projectile entering them from any angle, but a fall back plan is always welcome.

Again, thank you all, I should be able to work it out with the ideas you’ve given.

Thank you all for your ideas, but I think TheDave’s solution solves my question.

Something I found interesting, and perhaps useful for others as well,

cast a ray slightly past the initial collision point

I didn’t even have to change the new ray’s start point. I just cast the new ray from the original ray’s hitPosition and it found the inside of the far wall.

1 Like