jiangqiu Posted July 5, 2016 Posted July 5, 2016 Hi everyone, There have a question about mouse chose precision, I have input a object(.mesh ) in the scene, and I try to chose it by mouse click, but now I have a question that the mouse click around the model but not on the model I can chose the model too. my model input by C++ as follow: my model input code: ObjectMeshStaticPtr mesh; mesh = ObjectMeshStatic::create(modelPath.c_str()); mesh->setMaterial(texture_material_0, "*"); The code about mouse chose (It's refer to the Unigine demo "Orbits"): int checkIntersection() { if (Unigine::Editor::get()->isLoaded()) return 1; if (Unigine::ControlsApp::get()->isMouseEnabled()) return 1; if (Unigine::App::get()->getMouseButtonState(Unigine::App::BUTTON_LEFT) ) { mat4 projection; float x0 = float(Unigine::App::get()->getMouseX() - 1) / Unigine::App::get()->getWidth(); float y0 = float(Unigine::App::get()->getMouseY() - 1) / Unigine::App::get()->getHeight(); float x1 = float(Unigine::App::get()->getMouseX() + 1) / Unigine::App::get()->getWidth(); float y1 = float(Unigine::App::get()->getMouseY() + 1) / Unigine::App::get()->getHeight(); getPlayerMouseSelection2(x0, y0, x1, y1, projection); PlayerPtr player = Game::get()->getPlayer(); if (Unigine::Editor::get()->getPlayer().get() != NULL) { player = Unigine::Editor::get()->getPlayer(); } //bondbox Mat4 modelview = player->getIWorldTransform(); WorldBoundFrustum bound_frustum = WorldBoundFrustum(projection, modelview); Vector< NodePtr > nodes; Unigine::World::get()->getIntersection(bound_frustum, -1, nodes); for (int i = 0; i < Models.size(); i++) { Models[i]->isSelected = false; } if (nodes.size() != 0) { ObjectMeshStaticPtr OneOfSelected; NodePtr n; for (int i = 0; i < nodes.size(); i++) { n = nodes[i]; const char *name = "ObjectMeshStatic"; if (strcmp(n.get()->getTypeName(), name) == 0) { for (int i = 0; i < Models.size(); i++) { if (n.get()->getName() == Models[i]->mesh.get()->getName()) { Models[i]->isSelected = true; } } } } } } return 0; } // calculate the projection matrix int getPlayerMouseSelection2(float x0, float y0, float x1, float y1, mat4 &projection) { PlayerPtr player = Game::get()->getPlayer(); if (Unigine::Editor::get()->getPlayer().get() != NULL) { player = Unigine::Editor::get()->getPlayer(); } int width = Unigine::App::get()->getWidth(); int height = Unigine::App::get()->getHeight(); projection = player->getProjection(); projection.m00 *= float(height) / width; vec3 points[8]; points[0] = vec3(-1.0f, -1.0f, -1.0f); points[1] = vec3(1.0f, -1.0f, -1.0f); points[2] = vec3(-1.0f, 1.0f, -1.0f); points[3] = vec3(1.0f, 1.0f, -1.0f); points[4] = vec3(-1.0f, -1.0f, 1.0f); points[5] = vec3(1.0f, -1.0f, 1.0f); points[6] = vec3(-1.0f, 1.0f, 1.0f); points[7] = vec3(1.0f, 1.0f, 1.0f); mat4 iprojection = inverse(projection); for (int i = 0; i < 8; i++) { vec4 p = iprojection * vec4(points[i]); points[i] = vec3(p) / p.w; } float dx = points[1].x - points[0].x; float dy = points[0].y - points[2].y; x0 = points[0].x + dx * x0; x1 = points[0].x + dx * x1; y0 = points[2].y + dy * y0; y1 = points[2].y + dy * y1; if (projection.m32 == 0.0f) projection = ortho(x0, x1, y0, y1, -points[0].z, -points[4].z); else projection = frustum(x0, x1, y0, y1, -points[0].z, -points[4].z); return 1; } By those codes I can chose my model but not precision, when the mouse click almost everywhere in the red circle I can chose the model but not when the mouse click on the model only I can chose the model: Do you konw how can I make the mouse chose range more precise? Thanks!
ded Posted July 6, 2016 Posted July 6, 2016 Hi, Please try using the following method: Ptr<Object> World::getIntersection(const Math::Vec3 &p0, const Math::Vec3 &p1, int mask, const Ptr<WorldIntersection> &v); Here's the usage example: bool getPlayerMouseDirection(const PlayerPtr &player, float mouse_x, float mouse_y, float width, float height, Vec3 *p0, Vec3 *p1) { if (player.get() == NULL) return false; mat4 projection = player->getProjection(); Mat4 imodelview = player->getWorldTransform(); projection.m00 *= height / width; float x = -(mouse_x / width * 2.0f - 1.0f + projection.m02) / projection.m00; float y = (mouse_y / height * 2.0f - 1.0f + projection.m12) / projection.m11; if (projection.m32 == 0.0f) { *p0 = imodelview * Vec3(-x, -y, -1.0f); *p1 = imodelview * Vec3(-x, -y, 1.0f); } else { *p0 = Vec3(imodelview.m03, imodelview.m13, imodelview.m23); *p1 = imodelview * Vec3(x, y, 1.0f); } *p1 = *p0 - normalize(*p1 - *p0) * player->getZFar(); return true; } ObjectPtr getIntersection() { PlayerPtr player = Game::get()->getPlayer(); float x = App::get()->getMouseX(); float y = App::get()->getMouseY(); float width = App::get()->getWidth(); float height = App::get()->getHeight(); Vec3 p0, p1; if (!getPlayerMouseDirection(player, x, y, width, height, &p0, &p1)) return ObjectPtr(); WorldIntersectionPtr intersection = WorldIntersection::create(); ObjectPtr object = Unigine::World::get()->getIntersection(p0, p1, ~0, intersection); // object.get() == NULL when no object is intersected by a ray return object; } You can found more elaborate implementation of getPlayerMouseDirection() on UnigineScript in the SDK/data/core/scripts/utils.h file.
Recommended Posts