Pass Clicks Through Camera

Hi,

I have a scene with 2 cameras. The first cam (FPS Cam) is the first-person view. The second camera (Map Cam) takes a top-down view of the playing field. The Map Cam is then rendered as a Render Texture that is visible in the FPS Cam's field of view. In other words, the Map Cam is used to render a live map for the player, who views that map and the rest of the world through FPS Cam.

Now, I would like to make the map interactive, so that the player can click on enemies on the map and perform commands related to that enemy. To achieve this I would like to have those enemies detect mouse clicks on them (through the map) and register themselves as the currently selected enemy. But in my simple test I could not get the clicks to pass through the map/Map Cam and onto the enemy. I assume the clicks are simply being consumed by the plane with the map on it.

So my question is, is there a built-in or known way to allow clicks onto a Render Texture to be passed through to the corresponding camera in order to effectively click objects rendered in that second camera's view? Or are there any related tips/tricks which might help me?

Huge Thanks,

Pete.

You're sort of correct that the plane is eating your mouse click in the sense that the since the player is only ever seeing from the view of the FPS camera and the plane is seen by that camera (despite having a texture generated from another camera.

There is no "built-in" way to do this of which I am aware, but the problem does not seem too difficult overall. Here's a couple of solutions that come to mind:

Calculating your own pick ray from the map camera

You have the plane and probably even know the screen position and size of the plane. You know where the mouse is on the screen. You therefore can know where on the plane the user clicks. If you do something like

int planeLeft; //The screen position of the left side of the plane
int planeBottom; //The screen position of the bottom side of the plane
int planeWidth; //The width of the plane on the screen
int planeHeight; //The height of the plane on the screen

//Get the point on the plane
Vector3 screenPoint = Input.mousePosition - Vector3(planeLeft, planeBottom, 0);

//If not inside of an OnMouse function
//Check for clicks off the plane
if(screenPoint.x < 0 || screenPoint.y < 0
    || screenPoint.x > planeWidth || screenPoint.y > planeHeight) return;    

//If the plane is not the same screen size as the mapCam's resolution
//Convert the coordinate to the mapCam's resolutiion
screenPoint.x *= mapCam.pixelWidth / planeWidth;
screenPoint.y *= mapCam.pixelHeight / planeHeight;
//You could simply do the division in stead and later use ViewportPointToRay

//Raycast from the map camera
RaycastHit hitInfo; //Stores the information about the hit
int layerMask = kDefaultRaycastLayers; //The layers to raycast against
if(Physics.Raycast(mapCam.ScreenPointToRay(screenPoint), out hitInfo, mapCam.farClipPlane, layerMask))
{
    if(hitInfo.collider.gameObject is Enemy) //you could also check the rigidBody
    {
        //do something
    }
}

Using what you should know or be able to figure out, you can create your own raycast at the mapCamera's position and can check in the scene if you hit something and then using the information about what you hit, you have your answer.

Generate a map with collider representations

As 0V3RWR173D said, you could create colliders at the points on the map plane representing the things you want to collide with and then it would be a simple matter of using OnMouse events. The problem is how you know where on the map the enemies are. If your map camera rotates as your FPS camera does, then so too would the representative colliders have to.

This solution is valid, but can be trickier depending on your use case.

One way to generate your colliders is to place a trigger volume representing your mapped area and when stuff that you care about enters or is inside of the trigger volume, create the colliders on the mini map. Remember that event handling and message passing has overhead to be concerned about.

Another valid solution is to maintain a list of things that you want to be able to interact with on the mini map and check their positions. Using distance or distance squared (and the directional vector if using a non-circular mini map) you can check if the thing is within an area the mini map encompasses and if it is, you can then use the distance or distance squared and the directional vector to calculate the location that the thing should be at on the mini map.

Depending on your use case, you might want a representative map rather than a literal one (circles and lines in stead of the actual objects. This can be achieved numerous ways, but bear in mind that you can generate the map and the collider representations at the same time. Also, generating the map doesn't have the overhead of rendering your scene twice and, if elements of your map are static, you can generate an orhographic base map texture which you then scroll over and rotate as you need, rather than having to render it every frame.

I'm not exactly sure on what you are trying to do but I assume that you have a picture that corresponds to the real map so that you are just clicking a plane when you click on it. If you could create a point that corresponds with the location of the enemy and add a box collider, then you could make it so that if you click it, it broadcasts a message to the enemy to make it do something in response. If you need more information or this is not the answer you are looking for, please comment telling me.

-0V3RWR173D