Raycast: export exact pointing location (#6304)

* Return intersection point in node coordinates.
* Clarify 'intersection_point' documentation
This commit is contained in:
Dániel Juhász 2018-08-16 20:10:08 +02:00 committed by SmallJoker
parent 798724efea
commit 325bf68041
9 changed files with 63 additions and 17 deletions

@ -1317,6 +1317,17 @@ For helper functions see [Spatial Vectors].
* `{type="node", under=pos, above=pos}` * `{type="node", under=pos, above=pos}`
* `{type="object", ref=ObjectRef}` * `{type="object", ref=ObjectRef}`
Exact pointing location (currently only `Raycast` supports these fields):
* `pointed_thing.intersection_point`: The absolute world coordinates of the
point on the selection box which is pointed at. May be in the selection box
if the pointer is in the box too.
* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts
from 1).
* `pointed_thing.intersection_normal`: Unit vector, points outwards of the
selected selection box. This specifies which face is pointed at.
Is a null vector `{x = 0, y = 0, z = 0}` when the pointer is inside the
selection box.
@ -5323,7 +5334,12 @@ It can be created via `PseudoRandom(seed)`.
--------- ---------
A raycast on the map. It works with selection boxes. A raycast on the map. It works with selection boxes.
Can be used as an iterator in a for loop. Can be used as an iterator in a for loop as:
local ray = Raycast(...)
for pointed_thing in ray do
...
end
The map is loaded as the ray advances. If the map is modified after the The map is loaded as the ray advances. If the map is modified after the
`Raycast` is created, the changes may or may not have an effect on the object. `Raycast` is created, the changes may or may not have an effect on the object.
@ -5338,7 +5354,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
### Methods ### Methods
* `next()`: returns a `pointed_thing` * `next()`: returns a `pointed_thing` with exact pointing location
* Returns the next thing pointed by the ray or nil. * Returns the next thing pointed by the ray or nil.
`SecureRandom` `SecureRandom`

@ -175,12 +175,12 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
bool is_colliding = false; bool is_colliding = false;
// Minimal distance of all collisions // Minimal distance of all collisions
float min_distance_sq = 10000000; float min_distance_sq = 10000000;
// ID of the current box (loop counter)
u16 id = 0;
v3f npf = intToFloat(np, BS); v3f npf = intToFloat(np, BS);
for (std::vector<aabb3f>::const_iterator i = boxes.begin(); // This loop translates the boxes to their in-world place.
i != boxes.end(); ++i) { for (aabb3f &box : boxes) {
// Get current collision box
aabb3f box = *i;
box.MinEdge += npf; box.MinEdge += npf;
box.MaxEdge += npf; box.MaxEdge += npf;
@ -188,8 +188,10 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
v3s16 intersection_normal; v3s16 intersection_normal;
if (!boxLineCollision(box, state->m_shootline.start, if (!boxLineCollision(box, state->m_shootline.start,
state->m_shootline.getVector(), &intersection_point, state->m_shootline.getVector(), &intersection_point,
&intersection_normal)) &intersection_normal)) {
++id;
continue; continue;
}
f32 distanceSq = (intersection_point f32 distanceSq = (intersection_point
- state->m_shootline.start).getLengthSQ(); - state->m_shootline.start).getLengthSQ();
@ -198,9 +200,11 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
min_distance_sq = distanceSq; min_distance_sq = distanceSq;
result.intersection_point = intersection_point; result.intersection_point = intersection_point;
result.intersection_normal = intersection_normal; result.intersection_normal = intersection_normal;
result.box_id = id;
found_boxcenter = box.getCenter(); found_boxcenter = box.getCenter();
is_colliding = true; is_colliding = true;
} }
++id;
} }
// If there wasn't a collision, stop // If there wasn't a collision, stop
if (!is_colliding) { if (!is_colliding) {

@ -1757,7 +1757,8 @@ void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
lua_pop(L, 1); // Pop value lua_pop(L, 1); // Pop value
} }
void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm) void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
bool hitpoint)
{ {
lua_newtable(L); lua_newtable(L);
if (pointed.type == POINTEDTHING_NODE) { if (pointed.type == POINTEDTHING_NODE) {
@ -1782,6 +1783,14 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm)
lua_pushstring(L, "nothing"); lua_pushstring(L, "nothing");
lua_setfield(L, -2, "type"); lua_setfield(L, -2, "type");
} }
if (hitpoint && (pointed.type != POINTEDTHING_NOTHING)) {
push_v3f(L, pointed.intersection_point / BS); // convert to node coords
lua_setfield(L, -2, "intersection_point");
push_v3s16(L, pointed.intersection_normal);
lua_setfield(L, -2, "intersection_normal");
lua_pushinteger(L, pointed.box_id + 1); // change to Lua array index
lua_setfield(L, -2, "box_id");
}
} }
void push_objectRef(lua_State *L, const u16 id) void push_objectRef(lua_State *L, const u16 id)

@ -178,7 +178,13 @@ bool push_json_value (lua_State *L,
void read_json_value (lua_State *L, Json::Value &root, void read_json_value (lua_State *L, Json::Value &root,
int index, u8 recursion = 0); int index, u8 recursion = 0);
void push_pointed_thing (lua_State *L, const PointedThing &pointed, bool csm = false); /*!
* Pushes a Lua `pointed_thing` to the given Lua stack.
* \param csm If true, a client side pointed thing is pushed
* \param hitpoint If true, the exact pointing location is also pushed
*/
void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm =
false, bool hitpoint = false);
void push_objectRef (lua_State *L, const u16 id); void push_objectRef (lua_State *L, const u16 id);

@ -255,10 +255,10 @@ bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname,
return false; return false;
} }
void ScriptApiItem::pushPointedThing(const PointedThing& pointed) void ScriptApiItem::pushPointedThing(const PointedThing &pointed, bool hitpoint)
{ {
lua_State* L = getStack(); lua_State* L = getStack();
push_pointed_thing(L, pointed); push_pointed_thing(L, pointed, false, hitpoint);
} }

@ -54,6 +54,10 @@ protected:
friend class LuaRaycast; friend class LuaRaycast;
bool getItemCallback(const char *name, const char *callbackname, const v3s16 *p = nullptr); bool getItemCallback(const char *name, const char *callbackname, const v3s16 *p = nullptr);
void pushPointedThing(const PointedThing& pointed); /*!
* Pushes a `pointed_thing` tabe to the stack.
* \param hitpoint If true, the exact pointing location is also pushed
*/
void pushPointedThing(const PointedThing &pointed, bool hitpoint = false);
}; };

@ -150,7 +150,7 @@ int LuaRaycast::l_next(lua_State *L)
if (pointed.type == POINTEDTHING_NOTHING) if (pointed.type == POINTEDTHING_NOTHING)
lua_pushnil(L); lua_pushnil(L);
else else
script->pushPointedThing(pointed); script->pushPointedThing(pointed, true);
return 1; return 1;
} }

@ -25,13 +25,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
PointedThing::PointedThing(const v3s16 &under, const v3s16 &above, PointedThing::PointedThing(const v3s16 &under, const v3s16 &above,
const v3s16 &real_under, const v3f &point, const v3s16 &normal, const v3s16 &real_under, const v3f &point, const v3s16 &normal,
f32 distSq): u16 box_id, f32 distSq):
type(POINTEDTHING_NODE), type(POINTEDTHING_NODE),
node_undersurface(under), node_undersurface(under),
node_abovesurface(above), node_abovesurface(above),
node_real_undersurface(real_under), node_real_undersurface(real_under),
intersection_point(point), intersection_point(point),
intersection_normal(normal), intersection_normal(normal),
box_id(box_id),
distanceSq(distSq) distanceSq(distSq)
{} {}

@ -64,7 +64,8 @@ struct PointedThing
s16 object_id = -1; s16 object_id = -1;
/*! /*!
* Only valid if type isn't POINTEDTHING_NONE. * Only valid if type isn't POINTEDTHING_NONE.
* First intersection point of the ray and the nodebox. * First intersection point of the ray and the nodebox in irrlicht
* coordinates.
*/ */
v3f intersection_point; v3f intersection_point;
/*! /*!
@ -74,9 +75,14 @@ struct PointedThing
* points outside of the box and it's length is 1. * points outside of the box and it's length is 1.
*/ */
v3s16 intersection_normal; v3s16 intersection_normal;
/*!
* Only valid if type isn't POINTEDTHING_NONE.
* Indicates which selection box is selected, if there are more of them.
*/
u16 box_id = 0;
/*! /*!
* Square of the distance between the pointing * Square of the distance between the pointing
* ray's start point and the intersection point. * ray's start point and the intersection point in irrlicht coordinates.
*/ */
f32 distanceSq = 0; f32 distanceSq = 0;
@ -85,7 +91,7 @@ struct PointedThing
//! Constructor for POINTEDTHING_NODE //! Constructor for POINTEDTHING_NODE
PointedThing(const v3s16 &under, const v3s16 &above, PointedThing(const v3s16 &under, const v3s16 &above,
const v3s16 &real_under, const v3f &point, const v3s16 &normal, const v3s16 &real_under, const v3f &point, const v3s16 &normal,
f32 distSq); u16 box_id, f32 distSq);
//! Constructor for POINTEDTHING_OBJECT //! Constructor for POINTEDTHING_OBJECT
PointedThing(s16 id, const v3f &point, const v3s16 &normal, f32 distSq); PointedThing(s16 id, const v3f &point, const v3s16 &normal, f32 distSq);
std::string dump() const; std::string dump() const;