0
$\begingroup$

In BGE, I have a simple mesh, say, a cube that has been subdivided a few times to give it more than 8 vertices, like so:

Subdivided cube

What I'd like to do, generically speaking, is find the shortest distance from the surface, or alternately the bounding box, of that mesh a given location.

To be more specific, I want to find the distance from the camera (player) to the mesh. I would then pass that information into a text field on a HUD (which I already know how to do). Think of it like a range-finder, where the player always sees the distance from him/herself to the target object. I've found a few methods that work using the object's origin, but that doesn't work for me. I need the distance to the closest vertex on the object's mesh. Or alternately, at least the closest point on the object's bounding box.

I know how to get the camera's current location with object.worldPosition. I've tested that successfully.

Here's what else I've found so far, none of which works for me:

  • closest_point_on_mesh, an object property in BPY. This seems like it would work perfectly - I'd find the closest point, and find the distance from that point to the camera's location. Except that it's only for BPY, which doesn't help me for BGE.
  • Ray casting in BGE, from this similar object property list for BGE. I'm not quite understanding how ray casting works here or how I would use it to find the nearest point to my origin point (the camera location). Note, I already know what mesh I want to "hit" (the cube), I just need to find the closest vertex or closest point on its surface.
  • This StackExchange answer that relates to BPY. Again, I need a BGE-workable solution.
  • This other StackExchange answer that is in BGE, but it is only for the distance between two objects' origins. I need the distance from one point, to the closest point on the object. Not the origin-to-origin distance.

Finally, here's what I've tried to implement. Since object.closest_point_on_mesh from the first bullet above seems to be the closest to what I want, I decided why not try it in BGE and see if it works after all. It didn't.

import bge
from math import sqrt

#There's a bunch of other code in here that I won't repeat,
#but one of them is getHUDfield(), which retrieves the text
#objects in the HUD scene so that their text can be updated

def RangeUpdate():
    #Have this actuated by "Always" and reside on the camera
    #Find camera location
    cam_loc = bge.logic.getCurrentController().owner.worldPosition
    print(cam_loc) #for debugging - this works, successfully gives me the cam's location in the console
    #Find the cube object and find the closest point on its mesh
    objects = bge.logic.getCurrentScene().objects
    bounding_cube = objects["Cube_00"]
    loc, norm, idx = bounding_cube.closest_point_on_mesh(cam_loc)
    #^^^Right now the problem is here: closest_point_on_mesh might not work in BGE?

    #Find the distance between cam's location and this location
    dist = sqrt((loc[0]-cam_loc[0])**2 + (loc[1]-cam_loc[1])**2 + (loc[2]-cam_loc[2])**2)

    #Display it on the HUDfield called RangeLabel
    allhudfields = getHUDfield()
    hudfield = allhudfields["RangeLabel"]
    hudfield["Text"] = str(dist) + " blender units"

The code fails at bounding_cube.closest_point_on_mesh(cam_loc). The console output says AttributeError: 'KX_GameObject' object has no attribute 'closest_point_on_mesh' For the curious or skeptical, the part where it updates the hud field's text DOES work (if I feed it a dummy value). Clearly the failure is in finding the point on the mesh closest to the given location.

So does anyone know either how I can do something similar to calling the property closest_point_on_mesh, but in BGE instead of BPY? Or, is there a totally different method or a work-around that works in BGE? To reiterate, my objective is to find the shortest possible distance from an arbitrary point (the camera's location), to the surface of a specified object/mesh (or at least the nearest vertex on the mesh, or the closest point on its bounding box).

$\endgroup$

2 Answers 2

2
$\begingroup$

If it's just the distance to the Bound Box, does not require any complex function for this.

I do not usually use bge, but you can take advantage of this code to get the nearest point of a Bound_Box.

#bound.min: smaller coordinates x, y, z of Bound Box
#bound.max: greater coordinates x, y, z of Bound Box
#co coordinate of the point to test the nearest
from math import sqrt
def find_nearest_t_AABB(bound, co):
    nearest = [0.,0.,0.]
    dist = 0.
    for i in range(3):
        if (bounds.min[i] > co[i]):
            nearest[i] = bounds.min[i]
        elif (bounds.max[i] < co[i]):
            nearest[i] = bounds.max[i]
        else:
            nearest[i] = co[i]

        dist += (co[i] - nearest[i])**2
    return sqrt(dist), nearest
$\endgroup$
1
  • $\begingroup$ This is a nice work-around that hadn't occurred to me, thanks! It should be good enough for my needs and probably faster than checking every mesh point (though I'm still curious about BluePrintRandom's method for learning's sake). I'll mark it as the answer once I have a chance to test and confirm that it works for this case. $\endgroup$
    – DrSandwich
    Feb 22, 2016 at 21:21
1
$\begingroup$

To get the closest vertex to a mesh you can build a kdtree and check a point to get the closest vertex, but be aware, any time the object moves you will need to build a new tree.

$\endgroup$
3
  • $\begingroup$ I'll have to look into how to build a kdtree. Do you mean I would iterate through every point and see which is the closest? $\endgroup$
    – DrSandwich
    Feb 22, 2016 at 21:19
  • $\begingroup$ A kd tree you itterate to build, its in mathutils, and when you request the closest point, it spits it out, much faster then itterating with python. Be aware when you build the tree you have to translate the vertices to worldspace. $\endgroup$ Feb 23, 2016 at 3:28
  • $\begingroup$ or * translate your point to check into localspace $\endgroup$ Mar 7, 2016 at 21:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .