Question about mouse chose precision


photo

Recommended Posts

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:

post-2223-0-62896400-1467697301_thumb.png

 

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:

 

post-2223-0-55296600-1467698341_thumb.png

 

Do you konw how can I make the mouse chose range more precise?

 

 

Thanks!

 

Link to post

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.

Link to post