Open aspectron opened 10 years ago
Dominic (@dgregoire) added a function into the camera class that project mouse coordinates (x, y) into 3D space:
// get a world-space ray representing the mouse pointer
bool get_mouse_ray(int x, int y, math::vec3& out_near, math::vec3& out_far) const;
I think we could use it to get the ray end points and enumerate entities on mouse move in Mercury binding.
The quickest way to implement "mouse hovering" is to calculate mouse ray / bounding sphere intersection. For that, each entity needs to have it's radius. The radius can be calculated from Entity's geometry.
When mouse moves, for each entity "distance from ray" (mouse ray) is calculated and if it is less than entity's radius, then mouse is "in" otherwise it is "out". State of in/out should be tracked within the entity and if it changes, events emitted.
Entity should have virtual double size();
which in the case of mercury::Layer should be calculated by taking all points of geometry (layer polygon) and getting the maximum distance from entity's center for all of them.
As much as possible size should be a member value that would be updated on-demand (i.e. we should not calculate it when calling size() as it will eventually become too computationally expensive).
NOTE: When it has been determined that the entity intersects with the mouse ray, another virtual function can be called on the entity to do more precise mapping. This function should by default return true, however mercury::Layer can use 2d camera projection to see if the mouse ray falls within the polygon and if it doesn't, return false.
Keep in mind that we may have multiple cameras! as such, multiple clients may be looking at same entities.. I believe that this means that entity state tracking needs to occur either within the Binding class or it entity state should be kept by entity on "per camera" basis. (or on per Binding ID basis). Hope this makes sense.
I've just realized that we already have ray tracing in the Bullet engine. There is a rayTest function in btSoftRigidDynamicsWorld
class.
We have attached Mercury layers into the physics engine. I've tested this rayTest
with bounding sphere of radius 1000 for a Mercury layer. It works somehow. There is a bounding box supported in the Bullet that I think is more suitable for the layer. I see only 2 drawbacks:
Hydrogen needs to implement this on it's own, without Bullet. Bullet is a completely different subsystem.
The function itself is not complex. On mouse move, call update_mouse_intersections(ray), which will enumerate all entities and test them against the ray.
Added ray hit testing into Mercury Binding
class. Each camera, which is bound to the Binding
instance, stores its own list of entities that had been hit by the camera ray. On a mouse event that list is being updated and enter
and leave
events are being emitted in hydrogen Engine and each Entity. See Engine
and Entity
documentation in Hydrogen API.
Since this hit testing should scan over all entities in engine, this engine should be passed to Binding
constructor instead of window, see changes for Binding
class in Mercury API.
Few notes about implementation. There is a camera::hit_test(engine, ray)
function that enumerates all entities in the engine world and call a virtual function entity::ray_test(ray)
for each of them. Default ray_test()
implementation checks for the entity sphere intersection with the ray. In Mercury Layer class overrides ray_test()
to check for the entity plane intersection with the ray.
I've discovered that sphere intersection used by default in Hydrogen Entity works slightly inaccurately near the sphere edge. To test the sphere intersection, I draw a circle for each entity with its radius and see when I receive enter
and leave
events on mouse moving. These events occurs on several millimeters before the circle border.
I tried 3 different functions (see gl::entity::ray_test()
and below) for ray testing and none of them could work precisely. I may have bugs in these functions. I may draw wrong sphere border. There could be rounding errors in converting from 2D mouse coordinates to 3D world ray. I don't know yet the real reason.
We need a function that will enumerate all entities that fall under the ray with their geometries.
Current hit state needs to be tracked, so that if it changes, events are generated. I suppose engine needs to hook into a window..
Engine should be derived from EventEmitter and receive events such as 'enter' and 'leave'. Each entity should also be derived from EventEmitter and receive 'enter' and 'leave'.