- Home /
Is there a way to click on a render texture to select soemthing within the view?
Basically I was thinking if there was a way to click/select a certain part of a render texture that selects the correct selection within that view provided. How would that work? Would I have a Physics.Raycast within another Physics.Raycast call or am I forgetting something here?
Answer by Nischo · Jul 30, 2015 at 12:20 PM
So i tried it in a simple test scene because the problem intrigued me. My setup is rather simple and looks something like this.
a MainCamera looking at a Plane that uses a Render Texture in its Material. And the PortalCamera which looks at 2 primitives and renders it into the before mentioned render texture. On the Main Camera i attached this script.
public class RayCast : MonoBehaviour {
public Camera portalCamera;
void Update ()
{
if(Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// do we hit our portal plane?
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.collider.gameObject);
var localPoint = hit.textureCoord;
// convert the hit texture coordinates into camera coordinates
Ray portalRay = portalCamera.ScreenPointToRay(new Vector2(localPoint.x * portalCamera.pixelWidth, localPoint.y * portalCamera.pixelHeight));
RaycastHit portalHit;
// test these camera coordinates in another raycast test
if(Physics.Raycast(portalRay, out portalHit))
{
Debug.Log(portalHit.collider.gameObject);
}
}
}
}
}
I also angled the portal camera a bit to made sure i don't have "false positives" but still i can't assure that this code works on every possible angle or orientation. But it should be a good start.
It does help a bit, I will look into RaycastHit.normal and experiment with what you have mentioned. Because right now, I do have a main camera facing a plane that is rendering another view (like a bird's eye view/top-down view) at a location. And different objects can be in different locations but all can still be seen by this camera view. (I am not sure if orthographic or perspective view may change the way it processes the click, but I will experiment with this as well.)
Ok, this is what I have so far:
//Get/create the normal of the plane
Vector3 normal = mouseHit.normal;
Ray ray = topViewCamera.ScreenPointToRay(normal);
RaycastHit screenHit;
//Get the point of where it was clicked on the plane
if(Physics.Raycast(ray, out screenHit))
{
//If that point was an item (another ray deter$$anonymous$$ed there was an item)...
if(screenHit.collider.gameObject.name == "item")
{
print("hit");
}
}
This is already within the first Physics.Raycast that succeeded (mouse click from the screen), and when it comes to the second Physics.Raycast check (the render texture), it becomes false. What did I do wrong that resulted in this raycast to fail?
Ok, it works well, and I will accept this as the answer. Thanks for the help and I also did not know that "textureCoord" would be so helpful on getting the points needed to find an object.
@Nischo @AmasterAmaster The solution what you have said works perfectly when the render texture is applied a 3d game object. but do you have any solution how to get the same result when the render texture is applied to a UI element. i.e(panel).Thanks
did you find a way to get this work with UI element ?
I am also looking for a UI solution to make a typical $$anonymous$$imap teleport-on-click mechanic. any info would be a great help!
At line 20 you can use portalCamera.ViewportPointToRay(hit.textureCoord)
ins$$anonymous$$d of converting texture coords into camera coords.
Answer by Andrey-Postelzhuk · Jun 23, 2020 at 08:39 PM
Version for Unity UI:
public class RenderTextureRaycast : MonoBehaviour, IPointerClickHandler
{
[SerializeField] protected Camera UICamera;
[SerializeField] protected RectTransform RawImageRectTrans;
[SerializeField] protected Camera RenderToTextureCamera;
public void OnPointerClick(PointerEventData eventData)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(RawImageRectTrans, eventData.position, UICamera, out localPoint);
Vector2 normalizedPoint = Rect.PointToNormalized(RawImageRectTrans.rect, localPoint);
var renderRay = RenderToTextureCamera.ViewportPointToRay(normalizedPoint);
if (Physics.Raycast(renderRay, out var raycastHit))
{
Debug.Log("Hit: " + raycastHit.collider.gameObject.name);
}
else
{
Debug.Log("No hit object");
}
}
}
Answer by ForceMagic · Sep 19, 2020 at 02:25 AM
One notable thing that got my initial results wrong, as the Unity doc says it if you use RectTransformUtility.ScreenPointToLocalPointInRectangle
.
.. For a RectTransform in a Canvas set to Screen Space - Overlay mode, the cam parameter should be null. ..
Otherwise, even if you pass your UI Camera you'll get weird results! So pass null if your in Screen Space Overlay!
If there is a "should" case, I wonder why there is no warning in console if you assign one:(
Thank you! I think you just saved me a few hours of troubleshooting! :)
Answer by DEGUEKAS · Aug 04, 2021 at 06:38 PM
UI version with collider 2d
using UnityEngine.EventSystems;
public class RenderTextureRaycast : MonoBehaviour, IPointerClickHandler
{
[SerializeField] protected Camera UICamera;
[SerializeField] protected RectTransform RawImageRectTrans;
[SerializeField] protected Camera RenderToTextureCamera;
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Click");
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(RawImageRectTrans, eventData.position, UICamera, out localPoint);
Vector2 normalizedPoint = Rect.PointToNormalized(RawImageRectTrans.rect, localPoint);
Vector2 screenPosition = RenderToTextureCamera.ViewportToWorldPoint(normalizedPoint);
RaycastHit2D hit = Physics2D.Raycast(screenPosition, -Vector2.up);
if(hit != null)
{
Debug.Log("Hit: " + hit.collider.gameObject.name);
}
}
}
Your answer
