Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get 3D world space position from Render Texture

Tags:

c#

unity3d

camera

I am using Render Texture to make a Side Map, it is working fine and I have made it through these steps.

  1. One Main Camera Rendering the Scene.
  2. NGUI Camera Rendering the GUI.
  3. That GUI contains the Render Texture (minimap) which rendering the scene on the texture using GUI Camera.

But now I want to improve the map further and want it to make intractable. I want world space position from Render Texture click point. Is there any way available that I get world space position from render texture's specific click point?

If I click somewhere in render texture then, how can I get the point in 3D world space.

For example: I clicked a car object on Render Texture. Now, how can I highlight or get it in 3D world space.? How can Convert 2D render texture click position to World Space Position!

like image 947
Muhammad Faizan Khan Avatar asked Apr 26 '16 07:04

Muhammad Faizan Khan


1 Answers

This assumes some things.

First i use EventSystems to get mouse clicks. This is no requirement, it can be changed easily (by you though ^^). To set it up correctly, you need an EventSystem in your scene (if you have a UI, you probably have one already).

Second you need to attach a PhysicsRaycaster component to your main camera (the camera the player sees through).

Lastly, on the GameObject which contains the renderer for the render texture (i used a simple quad) you apply the below script and assign the corresponding camera.

using UnityEngine;
using UnityEngine.EventSystems;

//i chose box collider because its cheap
[RequireComponent(typeof(BoxCollider))]
public class RenderTextureRaycaster : MonoBehaviour, IPointerDownHandler {

    //assign in inspector
    public Camera portalExit;

    BoxCollider portal;
    Vector3 portalExitSize;

    void Start() {
        portal = GetComponent<BoxCollider>();
        //this is the target camera resolution, idk if there is another way to get it.
        portalExitSize = new Vector3(portalExit.targetTexture.width, portalExit.targetTexture.height, 0);
    }

    public void OnPointerDown(PointerEventData eventData) {
        //the click in world space
        Vector3 worldClick = eventData.pointerCurrentRaycast.worldPosition;
        //transformed into local space
        Vector3 localClick = transform.InverseTransformPoint(worldClick);
        //since the origin of the collider is in its center, we need to offset it by half its size to get it realtive to bottom left
        Vector3 textureClick = localClick + portal.size / 2;
        //now we scale it up by the actual texture size which equals to the "camera resoution"
        Vector3 rayOriginInCameraSpace = Vector3.Scale(textureClick, portalExitSize);

        //with this knowledge we can creata a ray.
        Ray portaledRay = portalExit.ScreenPointToRay(rayOriginInCameraSpace );
        RaycastHit raycastHit;

        //and cast it.
        if (Physics.Raycast(portaledRay, out raycastHit)) {
            Debug.DrawLine(portaledRay.origin, raycastHit.point, Color.blue, 4);
        }
        else {
            Debug.DrawRay(portaledRay.origin, portaledRay.direction * 100, Color.red, 4);
        }
    }
}

edit: above maybe is a bit verbose, you could reduce it easily if you like one liners, its just to show how it works. also please only consider this a proof of concept, its not thoroughly tested.

like image 171
yes Avatar answered Oct 16 '22 19:10

yes