I'm programming a game in Unity and I need to load a static map. The map are correctly displayed in the editor, and in Android devices, but not in iOS devices. It says the url is incorrect... I don´t know what is the solution. Can anybody help me?
I call the map with this code:
url= "http://maps.google.com/maps/api/staticmap?center="+fixLat+","+fixLon+"&zoom="+zoom+"&scale=2&size=640x640&style=feature:all|element:geometry|hue:0x00fff0|lightness:0|gamma:0.21|visibility:on&style=feature:all|element:labels|visibility:off&style=feature:landscape.man_made|element:geometry|color:0x133f42|visibility:on&style=feature:landscape.natural|element:geometry.fill|visibility:on|hue:0x00ffd2|saturation:35|lightness:0|gamma:0.5&style=feature:poi|element:geometry.fill|lightness:0|gamma:0.6|visibility:on&style=feature:poi.park|element:geometry|visibility:on|saturation:0|color:0x2e9470&style=feature:road|element:geometry.fill|visibility:on|color:0x05111a&style=feature:road|element:geometry.stroke|visibility:off&style=feature:transit|element:geometry|visibility:off"+key;
This is the full code to call the url:
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class Gpsconnect : MonoBehaviour
{
public Transform user;
public bool simGPS = true;
public float userSpeed = 5.0f;
public bool realSpeed = false;
public float fixLat = 42.3627f;
public float fixLon = -71.05686f;
public float altitude;
public float heading;
public float accuracy;
public int maxZoom = 18;
public int minZoom = 1;
public int zoom = 17;
private float multiplier;
public string key = "";
public string[] maptype;
public int[] mapSize;
public int index;
public int indexSize;
public float camDist = 15.0f;
public int camAngle = 40;
public int initTime = 3;
public int maxWait = 30;
public bool buttons = true;
public string dmsLat;
public string dmsLon;
public float updateRate = 0.1f;
public bool autoCenter = true;
public string status;
public bool gpsFix;
public Vector3 iniRef;
public bool info;
public bool triDView = false;
public bool ready;
public bool freeCam = false;
public bool pinchToZoom = true;
public bool dragToPan = true;
public bool mapDisabled;
public bool mapping = false;
public Transform cam;
public float userLon;
public float userLat;
private float levelHeight;
private float smooth = 1.3f;
private float yVelocity = 0.0f;
private float speed;
private Camera mycam;
private float currentOrtoSize;
private LocationInfo loc;
private Vector3 currentPosition;
private Vector3 newUserPos;
private Vector3 currentUserPos;
private float download;
private WWW www;
private string url = "";
private double longitude;
private double latitude;
private Rect rect;
private float screenX;
private float screenY;
private Renderer maprender;
private Transform mymap;
private float initPointerSize;
private double tempLat;
private double tempLon;
private bool touchZoom;
private string centre;
private bool centering;
private Texture centerIcon;
private Texture topIcon;
private Texture bottomIcon;
private Texture leftIcon;
private Texture rightIcon;
private GUIStyle arrowIcon;
private float dot;
private bool centered = true;
private int borderTile = 0;
private bool tileLeft;
private bool tileRight;
private bool tileTop;
private bool tileBottom;
private Rect topCursorPos;
private Rect rightCursorPos;
private Rect bottomCursorPos;
private Rect leftCursorPos;
void Awake(){
//Set the map's tag to GameController
transform.tag = "GameController";
cam = Camera.main.transform;
mycam = Camera.main;
user = GameObject.FindGameObjectWithTag("Player").transform;
//Store most used components and values into variables for faster access.
mymap = transform;
maprender = GetComponent<Renderer>();
screenX = Screen.width;
screenY = Screen.height;
//Add possible values to maptype and mapsize arrays (GOOGLE)
maptype = new string[]{"satellite","roadmap","hybrid","terrain"};
mapSize = new int[]{640}; //in pixels
//Set GUI "center" button label
if(triDView){
centre = "refresh";
}
//Enable autocenter on 2D-view (default)
else{
autoCenter = true;
}
//Load required interface textures
centerIcon = Resources.Load("centerIcon") as Texture2D;
topIcon = Resources.Load("cursorTop") as Texture2D;
bottomIcon = Resources.Load("cursorBottom") as Texture2D;
leftIcon = Resources.Load("cursorLeft") as Texture2D;
rightIcon = Resources.Load("cursorRight") as Texture2D;
//Resize GUI according to screen size/orientation
if(screenY >= screenX){
dot = screenY/800.0f;
}else{
dot = screenX/800.0f;
}
}
IEnumerator Start () {
//Setting variables values on Start
gpsFix=false;
rect = new Rect (screenX/10, screenY/10, 8*screenX/10, 8*screenY/10);
topCursorPos = new Rect(screenX/2-25*dot, 0, 50*dot, 50*dot);
rightCursorPos = new Rect(screenX-50*dot, screenY/2-25*dot, 50*dot, 50*dot);
if(!buttons)
bottomCursorPos = new Rect(screenX/2-25*dot, screenY-50*dot, 50*dot, 50*dot);
else
bottomCursorPos = new Rect(screenX/2-25*dot, screenY-50*dot-screenY/12, 50*dot, 50*dot);
leftCursorPos = new Rect(0, screenY/2-25*dot, 50*dot, 50*dot);
Vector3 tmp = mymap.eulerAngles;
tmp.y=180;
mymap.eulerAngles = tmp;
initPointerSize = user.localScale.x;
user.position = new Vector3(0, user.position.y, 0);
//Initial Camera Settings
//3D
if(triDView){
mycam.orthographic = false;
pinchToZoom = false;
dragToPan = false;
//Set the camera's field of view according to Screen size so map's visible area is maximized.
if(screenY > screenX){
mycam.fieldOfView = 72.5f;
}else{
mycam.fieldOfView = 95-(28*(screenX/screenY));
}
}
//2D
else{
mycam.orthographic = true;
mycam.nearClipPlane = 0.1f;
mycam.farClipPlane = cam.position.y+1;
if(screenY >= screenX){
mycam.orthographicSize = mymap.localScale.z*5.0f;
}else{
mycam.orthographicSize = (screenY/screenX)*mymap.localScale.x*5.0f;
}
}
//The "ready" variable will be true when the map texture has been successfully loaded.
ready = false;
//STARTING LOCATION SERVICES
// First, check if user has location service enabled
#if (UNITY_IOS && !UNITY_EDITOR)
if (!Input.location.isEnabledByUser){
//This message prints to the Editor Console
print("Ha sido imposible iniciar los servicios de localizacion.\nComprueba los ajustes de localización de tu teléfono");
//You can use this "status" variable to show messages in your custom user interface (GUIText, etc.)
status = "Ha sido imposible iniciar \nlos servicios de localizacion.\nComprueba los ajustes de \nlocalización de tu teléfono";
yield return new WaitForSeconds(4);
Application.LoadLevel("0_Login");
}
#endif
// Start service before querying location
Input.location.Start (3.0f, 3.0f);
Input.compass.enabled = true;
print("Iniciando servicios de localización...");
status = "Iniciando servicios de localización...";
// Wait until service initializes
while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0) {
yield return new WaitForSeconds (1);
maxWait--;
}
// Service didn't initialize in 30 seconds
if (maxWait < 1) {
print("Ha sido imposible iniciar los servicios de localizacion.\nComprueba los ajustes de localización de tu teléfono");
status = "Ha sido imposible iniciar \nlos servicios de localizacion.\nComprueba los ajustes de \nlocalización de tu teléfono";
yield return new WaitForSeconds(4);
Application.LoadLevel("0_Login");
}
// Connection has failed
if (Input.location.status == LocationServiceStatus.Failed) {
print("Ha sido imposible determinar tu localización\nComprueba los ajustes de localización de tu teléfono");
status = "Ha sido imposible determinar \ntu localización.\nComprueba los ajustes de \nlocalización de tu teléfono";
yield return new WaitForSeconds(4);
Application.LoadLevel("0_Login");
}
// Access granted and location value could be retrieved
else {
if(!mapDisabled){
print("GPS conectado. Ajustando posición...");
status = "GPS conectado!\n Ajustando posición...";
}
else{
print("GPS conectado.");
status = "GPS conectado!";
}
if(!simGPS){
//Wait in order to find enough satellites and increase GPS accuracy
yield return new WaitForSeconds(initTime);
//Set position
loc = Input.location.lastData;
iniRef.x = ((loc.longitude*20037508.34f/180)/100);
iniRef.z = (float)(System.Math.Log(System.Math.Tan((90+loc.latitude)*System.Math.PI/360))/(System.Math.PI/180));
iniRef.z = ((iniRef.z*20037508.34f/180)/100);
iniRef.y = 0;
fixLon = loc.longitude;
fixLat = loc.latitude;
//Successful GPS fix
gpsFix = true;
//Update Map for the current location
StartCoroutine(MapPosition());
}
else{
//Simulate initialization time
yield return new WaitForSeconds(initTime);
//Set Position
iniRef.x = ((fixLon*20037508.34f/180)/100);
iniRef.z = (float)(System.Math.Log(System.Math.Tan((90+fixLat)*System.Math.PI/360))/(System.Math.PI/180));
iniRef.z = (iniRef.z*20037508.34f/180)/100;
iniRef.y = 0;
//Simulated successful GPS fix
gpsFix = true;
//Update Map for the current location
StartCoroutine(MapPosition());
}
}
//Rescale map, set new camera height, and resize user pointer according to new zoom level
StartCoroutine(ReScale());
//Set player's position using new location data (every "updateRate" seconds)
//Default value for updateRate is 0.1. Increase if necessary to improve performance
InvokeRepeating("MyPosition", 1, updateRate);
//Read incoming compass data (every 0.1s)
InvokeRepeating("Orientate", 1, 0.1f);
//Get altitude and horizontal accuracy readings using new location data (Default: every 2s)
InvokeRepeating("AccuracyAltitude", 1, 2);
//Auto-Center Map on 2D View Mode
InvokeRepeating("Check", 1, 0.2f);
}
void MyPosition(){
if(gpsFix){
if(!simGPS){
loc = Input.location.lastData;
newUserPos.x = ((loc.longitude*20037508.34f/180)/100)-iniRef.x;
newUserPos.z = (float)(System.Math.Log(System.Math.Tan((90+loc.latitude)*System.Math.PI/360))/(System.Math.PI/180));
newUserPos.z = ((newUserPos.z*20037508.34f/180)/100)-iniRef.z;
dmsLat = convertdmsLat(loc.latitude);
dmsLon = convertdmsLon(loc.longitude);
userLon = loc.longitude;
userLat = loc.latitude;
}
else{
userLon = (18000*(user.position.x+iniRef.x))/20037508.34f;
userLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(user.position.z+iniRef.z))))-90;
dmsLat = convertdmsLat(userLat);
dmsLon = convertdmsLon(userLon);
}
}
}
void Orientate(){
if(!simGPS && gpsFix){
heading = Input.compass.trueHeading;
}
else{
heading = user.eulerAngles.y;
}
}
void AccuracyAltitude(){
if(gpsFix)
altitude = loc.altitude;
accuracy = loc.horizontalAccuracy;
}
void Check(){
if(autoCenter && triDView == false){
if(ready == true && mapping == false && gpsFix){
if (rect.Contains(Vector2.Scale(mycam.WorldToViewportPoint (user.position), new Vector2(screenX, screenY)))){
//DoNothing
}
else{
centering=true;
StartCoroutine(MapPosition());
StartCoroutine(ReScale());
}
}
}
}
//Auto-Center Map on 3D View Mode when exiting map's collider
void OnTriggerExit(Collider other){
if(other.tag == "Player" && autoCenter && triDView){
StartCoroutine(MapPosition());
StartCoroutine(ReScale());
}
}
//Update Map with the corresponding map images for the current location ============================================
IEnumerator MapPosition(){
//The mapping variable will only be true while the map is being updated
mapping = true;
CursorsOff();
//CHECK GPS STATUS AND RESTART IF NEEDED
if (Input.location.status == LocationServiceStatus.Stopped || Input.location.status == LocationServiceStatus.Failed){
// Start service before querying location
Input.location.Start (3.0f, 3.0f);
// Wait until service initializes
int maxWait = 20;
while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0) {
yield return new WaitForSeconds (1);
maxWait--;
}
// Service didn't initialize in 20 seconds
if (maxWait < 1) {
print ("Timed out");
//use the status string variable to print messages to your own user interface (GUIText, etc.)
status = "Timed out";
}
// Connection has failed
if (Input.location.status == LocationServiceStatus.Failed) {
print ("Unable to determine device location");
//use the status string variable to print messages to your own user interface (GUIText, etc.)
status = "Unable to determine device location";
}
}
//------------------------------------------------------------------ //
www = null;
//Get last available location data
loc = Input.location.lastData;
//Make player invisible while updating map
user.gameObject.GetComponent<Renderer>().enabled = false;
//Set target latitude and longitude
if(triDView){
if(simGPS){
fixLon = (18000*(user.position.x+iniRef.x))/20037508.34f;
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(user.position.z+iniRef.z))))-90;
}else{
fixLon = loc.longitude;
fixLat = loc.latitude;
}
}else{
if(centering){
if(simGPS){
fixLon = (18000*(user.position.x+iniRef.x))/20037508.34f;
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(user.position.z+iniRef.z))))-90;
}else{
fixLon = loc.longitude;
fixLat = loc.latitude;
}
}
else{
if(borderTile == 0){
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(cam.position.z+iniRef.z))))-90;
fixLon = (18000*(cam.position.x+iniRef.x))/20037508.34f;
}
//North tile
if (borderTile == 1){
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(cam.position.z+3*mycam.orthographicSize/2+iniRef.z))))-90;
fixLon = (18000 *(cam.position.x+iniRef.x))/20037508.34f;
borderTile=0;
tileTop=false;
}
//East Tile
if (borderTile == 2){
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(cam.position.z+iniRef.z))))-90;
fixLon = (18000*(cam.position.x+3*(screenX*mycam.orthographicSize/screenY)/2+iniRef.x))/20037508.34f;
borderTile = 0;
}
//South Tile
if (borderTile == 3){
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(cam.position.z-3*mycam.orthographicSize/2+iniRef.z))))-90;
fixLon = (18000*(cam.position.x+iniRef.x))/20037508.34f;
borderTile=0;
}
//West Tile
if (borderTile == 4){
fixLat = ((360/Mathf.PI)*Mathf.Atan(Mathf.Exp(0.00001567855943f*(cam.position.z+iniRef.z))))-90;
fixLon = (18000*(cam.position.x-3*(screenX*mycam.orthographicSize/screenY)/2+iniRef.x))/20037508.34f;
borderTile=0;
}
}
}
//MAP ================================================================================
//Build a valid Google Maps tile request for the current location
url= "https://maps.google.com/maps/api/staticmap?center="+fixLat+","+fixLon+"&zoom="+zoom+"&scale=2&size=640x640&style=feature:all|element:geometry|hue:0x00fff0|lightness:0|gamma:0.21|visibility:on&style=feature:all|element:labels|visibility:off&style=feature:landscape.man_made|element:geometry|color:0x133f42|visibility:on&style=feature:landscape.natural|element:geometry.fill|visibility:on|hue:0x00ffd2|saturation:35|lightness:0|gamma:0.5&style=feature:poi|element:geometry.fill|lightness:0|gamma:0.6|visibility:on&style=feature:poi.park|element:geometry|visibility:on|saturation:0|color:0x2e9470&style=feature:road|element:geometry.fill|visibility:on|color:0x05111a&style=feature:road|element:geometry.stroke|visibility:off&style=feature:transit|element:geometry|visibility:off"+"&sensor=false&key="+key;
tempLat = fixLat;
tempLon = fixLon;
//=================================================================================================
//Proceed with download if a Wireless internet connection is available
if(Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork){
StartCoroutine(Online());
}
//Proceed with download if a 3G/4G internet connection is available
else if(Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork){
StartCoroutine(Online());
}
//No internet connection is available. Switching to Offline mode.
else{
Offline();
}
}
//ONLINE MAP DOWNLOAD
IEnumerator Online(){
if(!mapDisabled){
// Start a download of the given URL
www = new WWW(url);
// Wait for download to complete
download = (www.progress);
while(!www.isDone){
print("Actualizando mapa "+System.Math.Round(download*100)+" %");
//use the status string variable to print messages to your own user interface (GUIText, etc.)
status="Actualizando mapa "+System.Math.Round(download*100)+" %";
yield return null;
}
//Show download progress and apply texture
if(www.error == null){
print("Actualizando mapa 100 %");
print("Mapa preparado!");
//use the status string variable to print messages to your own user interface (GUIText, etc.)
status = "Actualizando mapa 100 %\nMapa preparado!";
yield return new WaitForSeconds (0.5f);
maprender.material.mainTexture = null;
Texture2D tmp;
tmp = new Texture2D(1280, 1280, TextureFormat.RGB24, false);
maprender.material.mainTexture = tmp;
www.LoadImageIntoTexture(tmp);
}
//Download Error. Switching to offline mode
else{
print("Error en el mapa:"+www.error);
//use the status string variable to print messages to your own user interface (GUIText, etc.)
status = "Error en el mapa:"+www.error;
yield return new WaitForSeconds (4);
maprender.material.mainTexture = null;
Offline();
}
maprender.enabled = true;
}
ReSet();
user.gameObject.GetComponent<Renderer>().enabled = true;
ready = true;
mapping = false;
}
//USING OFFLINE BACKGROUND TEXTURE
void Offline(){
if(!mapDisabled){
maprender.material.mainTexture=Resources.Load("offline") as Texture2D;
maprender.enabled = true;
}
ReSet();
ready = true;
mapping = false;
user.gameObject.GetComponent<Renderer>().enabled = true;
}
//Re-position map and camera using updated data
void ReSet(){
Vector3 tmp = transform.position;
tmp.x = (float)((tempLon*20037508.34f/180)/100)-iniRef.x;
tmp.z = (float)(System.Math.Log(System.Math.Tan((90+tempLat)*System.Math.PI/360))/(System.Math.PI/180));
tmp.z = ((tmp.z*20037508.34f/180)/100)-iniRef.z;
transform.position = tmp;
if(!freeCam){
cam.position = new Vector3(transform.position.x, cam.position.y, transform.position.z);
}
if(triDView == false && centering){
centered = true;
autoCenter = true;
centering = false;
}
}
void Update(){
//Rename GUI "center" button label
if(!triDView){
if(cam.position.x != user.position.x || cam.position.z != user.position.z)
centre ="center";
else
centre ="refresh";
}
//User pointer speed
if(realSpeed){
speed = userSpeed*0.05f;
}
else{
speed = userSpeed*10000/(Mathf.Pow(2, zoom)*1.0f);
}
//3D-2D View Camera Toggle (use only while game is stopped)
if(triDView && !freeCam){
cam.parent = user;
if(ready)
cam.LookAt(user);
}
if(ready){
if(!simGPS){
//Smoothly move pointer to updated position
currentUserPos.x = user.position.x;
currentUserPos.x = Mathf.Lerp (user.position.x, newUserPos.x, 2.0f*Time.deltaTime);
currentUserPos.z = user.position.z;
currentUserPos.z = Mathf.Lerp (user.position.z, newUserPos.z, 2.0f*Time.deltaTime);
user.position = new Vector3(currentUserPos.x, user.position.y, currentUserPos.z);
//Update rotation
if(System.Math.Abs(user.eulerAngles.y-heading) >= 5){
float newAngle = Mathf.SmoothDampAngle(user.eulerAngles.y, heading, ref yVelocity, smooth);
user.eulerAngles = new Vector3(user.eulerAngles.x, newAngle, user.eulerAngles.z);
}
}
else{
//When GPS Emulator is enabled, user position is controlled by keyboard input.
if(mapping == false){
//Use keyboard input to move the player
if (Input.GetKey ("up") || Input.GetKey ("w")){
user.transform.Translate(Vector3.forward*speed*Time.deltaTime);
}
if (Input.GetKey ("down") || Input.GetKey ("s")){
user.transform.Translate(-Vector3.forward*speed*Time.deltaTime);
}
//rotate pointer when pressing Left and Right arrow keys
user.Rotate(Vector3.up, Input.GetAxis("Horizontal")*80*Time.deltaTime);
}
}
}
if(mapping && !mapDisabled){
//get download progress while images are still downloading
if(www != null)
download = www.progress;
}
//Enable/Disable map renderer
if(mapDisabled)
maprender.enabled = false;
else
maprender.enabled = true;
void CheckBorders(){
//Reached left tile border
if(Mathf.Round((mycam.ScreenToWorldPoint(new Vector3(0, 0.5f, cam.position.y)).x)*100.0f)/100.0f <= Mathf.Round((mymap.position.x-mymap.localScale.x*5)*100.0f)/100.0f){
//show button for borderTile=4;
tileLeft = true;
}else{
//hide button
tileLeft = false;
}
//Reached right tile border
if(Mathf.Round((mycam.ScreenToWorldPoint(new Vector3(mycam.pixelWidth, 0.5f, cam.position.y)).x)*100.0f)/100.0f >= Mathf.Round((mymap.position.x+mymap.localScale.x*5)*100.0f)/100.0f){
//show button for borderTile=2;
tileRight = true;
}else{
//hide button
tileRight = false;
}
//Reached bottom tile border
if(Mathf.Round((mycam.ScreenToWorldPoint(new Vector3(0.5f, 0, cam.position.y)).z)*100.0f)/100.0f <= Mathf.Round((mymap.position.z-mymap.localScale.z*5)*100.0f)/100.0f){
//show button for borderTile=3;
tileBottom = true;
}else{
//hide button
tileBottom = false;
}
//Reached top tile border
if(Mathf.Round((mycam.ScreenToWorldPoint(new Vector3(0.5f, mycam.pixelHeight, cam.position.y)).z)*100.0f)/100.0f >= Mathf.Round((mymap.position.z+mymap.localScale.z*5)*100.0f)/100.0f){
//show button for borderTile=1;
tileTop = true;
}else{
//hide button
tileTop = false;
}
}
//Disable surrounding tiles cursors
void CursorsOff(){
tileTop = false;
tileBottom = false;
tileLeft = false;
tileRight = false;
}
//Clamp the camera position
void ClampCam(){
Vector3 tmp = cam.position;
tmp.x = Mathf.Clamp(cam.position.x,
mymap.position.x-(mymap.localScale.x*5)+(mycam.ScreenToWorldPoint(new Vector3(mycam.pixelWidth, 0.5f, cam.position.y)).x-mycam.ScreenToWorldPoint(new Vector3(0, 0.5f, cam.position.y)).x)/2,
mymap.position.x+(mymap.localScale.x*5)-(mycam.ScreenToWorldPoint(new Vector3(mycam.pixelWidth, 0.5f, cam.position.y)).x-mycam.ScreenToWorldPoint(new Vector3(0, 0.5f, cam.position.y)).x)/2 );
tmp.z = Mathf.Clamp(cam.position.z,
mymap.position.z-(mymap.localScale.z*5)+(mycam.ScreenToWorldPoint(new Vector3(0.5f, mycam.pixelHeight, cam.position.y)).z-mycam.ScreenToWorldPoint(new Vector3(0.5f, 0, cam.position.y)).z)/2,
mymap.position.z+(mymap.localScale.z*5)-(mycam.ScreenToWorldPoint(new Vector3(0.5f, mycam.pixelHeight, cam.position.y)).z-mycam.ScreenToWorldPoint(new Vector3(0.5f, 0, cam.position.y)).z)/2 );
cam.position = tmp;
}
}
Those are the screenshots.
Editor and Android device
iOS device
Ran the code in your question and was able to replicate your problem. This is happening due to new restriction on using http connections instead of https on iOS. Just like I mentioned in my comment, replacing WWW with UnityWebRequest solved this problem.
Also, you are unnecessarily creating new textures each time with new Texture2D(1280, 1280, TextureFormat.RGB24, false); is executed. This should be done with Unity's UI Component RawImage. In this case, no unnecessary memory allocation.
All you have to do to the code in your question is to remove the WWW API and use UnityWebRequest. Also remove Renderer or Texture2D and use RawImage to display your map. Below is a simple test script I used to test this. It runs on the both Editor,iOS and possibly all other platforms.
public class Gpsconnect : MonoBehaviour
{
public RawImage imageDisp;
public float fixLat = 42.3627f;
public float fixLon = -71.05686f;
public int zoom = 4;
public string key = "";
public Vector3 iniRef;
public Transform cam;
private Camera mycam;
private string url = "";
//Update Map with the corresponding map images for the current location ============================================
IEnumerator load()
{
yield return null;
mycam = Camera.main;
fixLat = ((360 / Mathf.PI) * Mathf.Atan(Mathf.Exp(0.00001567855943f * (cam.position.z - 3 * mycam.orthographicSize / 2 + iniRef.z)))) - 90;
fixLon = (18000 * (cam.position.x + iniRef.x)) / 20037508.34f;
//MAP ================================================================================
//Build a valid Google Maps tile request for the current location
url = "https://maps.google.com/maps/api/staticmap?center=" + fixLat + "," + fixLon + "&zoom=" + zoom + "&scale=2&size=640x640&style=feature:all|element:geometry|hue:0x00fff0|lightness:0|gamma:0.21|visibility:on&style=feature:all|element:labels|visibility:off&style=feature:landscape.man_made|element:geometry|color:0x133f42|visibility:on&style=feature:landscape.natural|element:geometry.fill|visibility:on|hue:0x00ffd2|saturation:35|lightness:0|gamma:0.5&style=feature:poi|element:geometry.fill|lightness:0|gamma:0.6|visibility:on&style=feature:poi.park|element:geometry|visibility:on|saturation:0|color:0x2e9470&style=feature:road|element:geometry.fill|visibility:on|color:0x05111a&style=feature:road|element:geometry.stroke|visibility:off&style=feature:transit|element:geometry|visibility:off" + "&sensor=false&key=" + key;
UnityWebRequest www = UnityWebRequest.GetTexture(url);
yield return www.Send();
Debug.Log("Done: ");
if (www.isError)
{
Debug.Log("Error while downloading image: " + www.error);
}
else
{
imageDisp.texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
}
}
void Start()
{
StartCoroutine(load());
}
}
Related
I'm writing a unity editor script which draws a preview scene in the inspector GUI. Basically, I instantiate a prefab with a camera component and move it into a temporary scene. Then I try to draw the scene onto a texture using that camera. My current approach doesn't seem to be working, or maybe there's something wrong in my code. I'd appreciate any help.
Below is some of my code that does the drawing:
[CustomEditor(typeof(NPCSpawnConfig))]
public class NPCSpawnEditor : Editor
{
enum SupportedAspects
{
Aspect4by3 = 1,
Aspect5by4 = 2,
Aspect16by10 = 3,
Aspect16by9 = 4
};
Camera _cam = null;
RenderTexture _rt;
Texture2D _tex2d;
Scene _scene;
// preview variables
SupportedAspects _aspectChoiceIdx = SupportedAspects.Aspect16by10;
float _curAspect;
// world space (orthographicSize)
float _worldScreenHeight = 5;
int _renderTextureHeight = 1080;
float ToFloat(SupportedAspects aspects)
{
switch(aspects)
{
case SupportedAspects.Aspect16by10:
return 16 / 10f;
case SupportedAspects.Aspect16by9:
return 16 / 9f;
case SupportedAspects.Aspect4by3:
return 4 / 3f;
case SupportedAspects.Aspect5by4:
return 5 / 4f;
default:
throw new ArgumentException();
}
}
void DrawRefScene()
{
_rt = new RenderTexture(Mathf.RoundToInt(_curAspect * _renderTextureHeight), _renderTextureHeight, 16);
_cam.targetTexture = _rt;
_cam.Render();
_tex2d = new Texture2D(_rt.width, _rt.height, TextureFormat.RGBA32, false);
_tex2d.Apply(false);
Graphics.CopyTexture(_rt, _tex2d);
}
Vector2 GetGUIPreviewSize()
{
Vector2 camSizeWorld = new Vector2(_worldScreenHeight * _curAspect, _worldScreenHeight);
float scaleFactor = EditorGUIUtility.currentViewWidth / camSizeWorld.x;
return new Vector2(EditorGUIUtility.currentViewWidth, scaleFactor * camSizeWorld.y);
}
#region Init
void OnEnable()
{
void OpenSceneDelay()
{
EditorApplication.delayCall -= OpenSceneDelay;
DrawRefScene();
}
_aspectChoiceIdx = SupportedAspects.Aspect16by10;
_scene = EditorSceneManager.NewPreviewScene();
PrefabUtility.LoadPrefabContentsIntoPreviewScene("Assets/Prefabs/Demo/DemoBkg.prefab", _scene);
_cam = _scene.GetRootGameObjects()[0].GetComponentInChildren<Camera>();
_curAspect = ToFloat(_aspectChoiceIdx);
_cam.aspect = _curAspect;
_cam.orthographicSize = _worldScreenHeight;
EditorApplication.delayCall += OpenSceneDelay;
}
void OnDisable()
{
EditorSceneManager.ClosePreviewScene(_scene);
}
#endregion
void OnCamSettingChange()
{
_curAspect = ToFloat(_aspectChoiceIdx);
_cam.aspect = _curAspect;
_cam.orthographicSize = _worldScreenHeight;
DrawRefScene();
}
// GUI states
class GUIControlStates
{
public bool foldout = false;
};
GUIControlStates _guiStates = new GUIControlStates();
public override void OnInspectorGUI()
{
// draw serializedObject fields
// ....
// display options
using (var scope = new EditorGUI.ChangeCheckScope())
{
_aspectChoiceIdx = (SupportedAspects)EditorGUILayout.EnumPopup("label", (Enum)_aspectChoiceIdx);
if (scope.changed)
{
OnCamSettingChange();
}
}
_guiStates.foldout = EditorGUILayout.Foldout(_guiStates.foldout, "label", true);
if(_guiStates.foldout)
{
using (var scope = new EditorGUI.ChangeCheckScope())
{
_worldScreenHeight = EditorGUILayout.FloatField("label", _worldScreenHeight);
_renderTextureHeight = EditorGUILayout.IntField("label", _renderTextureHeight);
if (scope.changed)
{
OnCamSettingChange();
}
}
}
if (_tex2d != null)
{
Vector2 sz = GetGUIPreviewSize();
Rect r = EditorGUILayout.GetControlRect(false,
GUILayout.Height(sz.y),
GUILayout.ExpandHeight(false));
EditorGUI.DrawPreviewTexture(r, _tex2d);
}
}
}
Here is the result: (only clear color is displayed, but the prefab contains a lot of sprites that should be drawn. The camera is also correctly positioned relative to the sprites.)
Solved this by adding the following 2 lines after getting the camera component.
_cam.cameraType = CameraType.Preview;
_cam.scene = _scene;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindMultipleTargets = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if(targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count > 1 && behindMultipleTargets == true)
{
var center = CalculateCenter();
transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindMultipleTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var totalX = 0f;
var totalY = 0f;
foreach (var target in targets)
{
totalX += target.transform.position.x;
totalY += target.transform.position.y;
}
var centerX = totalX / targets.Count;
var centerY = totalY / targets.Count;
center = new Vector3(centerX, centerY);
return center;
}
}
The CalculateCenter function make the targets(objects) to change positions and vanish away far away. Even if there is only one single target.
What I want to do is if there is one object for example one 3d cube position the camera behind the cube. And if there are more cubes for example two or ten and the camera is somewhere else calculate the middle position behind the targets and position the camera in the middle behind them.
To show what I mean in this example the view(like a camera) is behind the two soldiers in the middle position between them from behind.
But what if there are 5 soldiers how can I find the middle position and then position the camera behind them like this example in the screenshot ?
This is my old script version was working fine but only for 1 or 2 targets. But if there are 5 targets(soldiers) how can I position the camera behind them in the middle ? Like in the screenshot example.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindTwoTargets = false;
public string warningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
warningMsgs = "Gettig Camera omponent.";
camera = transform.gameObject;
}
else
{
warningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
camera.transform.Rotate(0, 180, 0);
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count == 2 && behindTwoTargets == true)
{
Vector3 center = ((targets[0].transform.position - targets[1].transform.position) / 2.0f) + targets[1].transform.position;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindTwoTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
}
This is my last version of my working code still using the CalculateCenter function :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraLook : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public float cameraHeight = 2f;
public float rotateTime = 2f;
public bool multipleTargets = false;
public bool changeRandomTarget = false;
public bool behindFront = false;
public bool targetsRandomRot = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
private List<Vector3> vectors = new List<Vector3>();
//Random move rotation timer part
Quaternion qTo;
float speed = 3f;
float timer = 0.0f;
// Use this for initialization
void Start()
{
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if (targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
else
{
foreach(GameObject vector in targets)
{
vectors.Add(vector.transform.position);
}
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
if (targetsRandomRot == true)
{
RotateTargetsRandom();
}
}
}
public void MoveCameraToPosition()
{
Vector3 center = CalculateCenter();
camera.transform.position = center;
if (behindFront == false)
{
camera.transform.rotation = Quaternion.LookRotation(-center, Vector3.up);
}
else
{
camera.transform.rotation = Quaternion.LookRotation(center, Vector3.up);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var x = targets[0].transform.position.x;
var y = targets[0].transform.position.y;
var z = targets[0].transform.position.z;
if (multipleTargets == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
else
{
x += targets[0].transform.position.x;
y += targets[0].transform.position.y;
z += targets[0].transform.position.z;
}
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
x = x / targets.Count;
y = y / targets.Count;
z = z / targets.Count;
if (behindFront == false)
{
center = new Vector3(x, y + cameraHeight, z + cameraDistance);
}
else
{
center = new Vector3(x, y + cameraHeight, z - cameraDistance);
}
return center;
}
private void RotateTargetsRandom()
{
timer += Time.deltaTime;
if (timer > rotateTime)
{ // timer resets at 2, allowing .5 s to do the rotating
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
timer = 0.0f;
}
foreach (var target in targets)
{
target.transform.rotation = Quaternion.Slerp(target.transform.rotation, qTo, Time.deltaTime * speed);
}
}
}
And now I want to add and use the bool flag changeRandomTarget :
But not sure how to do it :
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
I want that each X seconds it will pick a random center and change the camera position according to it. For example the first item in the targets List the last item and all the items so each X seconds the center will be once behind targets[0] or targets1 or targets[i]
Not sure how to do it with my code or with derHugo solution.
Surely you just find the average
so
if (mobcount > 1)
{
var x=mob[0].position.x;
var y=mob[0].position.y;
var z=mob[0].position.z;
for(int i=1; i<mobcount; i++)
{
x += mob[i].position.x;
y += mob[i].position.y;
z += mob[i].position.z;
}
x = x / mobcount;
y = y / mobcount;
z = z / mobcount;
}
therefore the camera should look at the position x,y,z.. and perhaps set the distance to be a fixed distance behind the nearest mob...
Actually you don't even need to do it component wise:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
...
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = Vector3.zero;
foreach(var vector in vectors)
{
average += vector;
}
return average / vectors.Count;
}
}
Or directly using Linq aggregate
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = vectors.Aggregate(Vector3.zero, (current, vector) => current + vector);
return average / vectors.Count;
}
}
Im using Unity and have asked this on there forums however have not had any replies. Ive found this example from a plugin where I am trying to use the kinect to rotate an object using my right hand to rotate it right and the left to rotate left. I have managed to get the object to do this apart from it stops at each side of the object, but cant work out what part of the code is doing this.
Thanks
using UnityEngine;
using System.Collections;
using System;
public class GestureListener : MonoBehaviour, KinectGestures.GestureListenerInterface
{
// GUI Text to display the gesture messages.
public GUIText GestureInfo;
private bool raiselefthand;
private bool raiserighthand;
public bool IsSwipeLeft()
{
if(raiserighthand)
{
raiserighthand = false;
return true;
}
return false;
}
public bool IsSwipeRight()
{
if(raiselefthand)
{
raiselefthand = false;
return true;
}
return false;
}
public void UserDetected(uint userId, int userIndex)
{
// detect these user specific gestures
KinectManager manager = KinectManager.Instance;
manager.DetectGesture(userId, KinectGestures.Gestures.RaiseLeftHand);
manager.DetectGesture(userId, KinectGestures.Gestures.RaiseRightHand);
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = "Swipe left or right to change the slides.";
}
}
public void UserLost(uint userId, int userIndex)
{
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = string.Empty;
}
}
public void GestureInProgress(uint userId, int userIndex, KinectGestures.Gestures gesture,
float progress, KinectWrapper.NuiSkeletonPositionIndex joint, Vector3 screenPos)
{
// don't do anything here
}
public bool GestureCompleted (uint userId, int userIndex, KinectGestures.Gestures gesture,
KinectWrapper.NuiSkeletonPositionIndex joint, Vector3 screenPos)
{
string sGestureText = gesture + " detected";
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = sGestureText;
}
if(gesture == KinectGestures.Gestures.RaiseRightHand)
raiserighthand = true;
else if(gesture == KinectGestures.Gestures.RaiseLeftHand)
raiselefthand = true;
return true;
}
public bool GestureCancelled (uint userId, int userIndex, KinectGestures.Gestures gesture,
KinectWrapper.NuiSkeletonPositionIndex joint)
{
// don't do anything here, just reset the gesture state
return true;
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PresentationScript : MonoBehaviour
{
public bool slideChangeWithGestures = true;
public bool slideChangeWithKeys = true;
public float spinSpeed = 5;
public bool autoChangeAlfterDelay = false;
public float slideChangeAfterDelay = 10;
public List<Texture> slideTextures;
public List<GameObject> horizontalSides;
// if the presentation cube is behind the user (true) or in front of the user (false)
public bool isBehindUser = false;
private int maxSides = 0;
private int maxTextures = 0;
private int side = 0;
private int tex = 0;
private bool isSpinning = false;
private float slideWaitUntil;
private Quaternion targetRotation;
private GestureListener gestureListener;
void Start()
{
// hide mouse cursor
Cursor.visible = false;
// calculate max slides and textures
maxSides = horizontalSides.Count;
maxTextures = slideTextures.Count;
// delay the first slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
targetRotation = transform.rotation;
isSpinning = false;
tex = 0;
side = 0;
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// get the gestures listener
gestureListener = Camera.main.GetComponent<GestureListener>();
}
void Update()
{
// dont run Update() if there is no user
KinectManager kinectManager = KinectManager.Instance;
if(autoChangeAlfterDelay && (!kinectManager || !kinectManager.IsInitialized() || !kinectManager.IsUserDetected()))
return;
if(!isSpinning)
{
if(slideChangeWithKeys)
{
if(Input.GetKeyDown(KeyCode.PageDown))
RotateToNext();
else if(Input.GetKeyDown(KeyCode.PageUp))
RotateToPrevious();
}
if(slideChangeWithGestures && gestureListener)
{
if(gestureListener.IsSwipeLeft())
RotateToNext();
else if(gestureListener.IsSwipeRight())
RotateToPrevious();
}
// check for automatic slide-change after a given delay time
if(autoChangeAlfterDelay && Time.realtimeSinceStartup >= slideWaitUntil)
{
RotateToNext();
}
}
else
{
// spin the presentation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, spinSpeed * Time.deltaTime);
// check if transform reaches the target rotation. If yes - stop spinning
float deltaTargetX = Mathf.Abs(targetRotation.eulerAngles.x - transform.rotation.eulerAngles.x);
float deltaTargetY = Mathf.Abs(targetRotation.eulerAngles.y - transform.rotation.eulerAngles.y);
if(deltaTargetX < 1f && deltaTargetY < 1f)
{
// delay the slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
isSpinning = false;
}
}
}
private void RotateToNext()
{
// set the next texture slide
tex = (tex + 1) % maxTextures;
if(!isBehindUser)
{
side = (side + 1) % maxSides;
}
else
{
if(side <= 0)
side = maxSides - 1;
else
side -= 1;
}
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// rotate the presentation
float yawRotation = !isBehindUser ? 360f / maxSides : -360f / maxSides;
Vector3 rotateDegrees = new Vector3(0f, yawRotation, 0f);
targetRotation *= Quaternion.Euler(rotateDegrees);
isSpinning = true;
}
private void RotateToPrevious()
{
// set the previous texture slide
if(tex <= 0)
tex = maxTextures - 1;
else
tex -= 1;
if(!isBehindUser)
{
if(side <= 0)
side = maxSides - 1;
else
side -= 1;
}
else
{
side = (side + 1) % maxSides;
}
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// rotate the presentation
float yawRotation = !isBehindUser ? -360f / maxSides : 360f / maxSides;
Vector3 rotateDegrees = new Vector3(0f, yawRotation, 0f);
targetRotation *= Quaternion.Euler(rotateDegrees);
isSpinning = true;
}
}
I have managed to get the object to do this apart from it stops at each side of the object, but cant work out what part of the code is doing this.
I understand you ask for help finding which parts are involved in the rotation.
As such, I looked through the scripts and noticed 2 sections in the PresentationScript.
This part in the Update() method. Based on the code and the comments that are part of it.
// spin the presentation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, spinSpeed * Time.deltaTime);
// check if transform reaches the target rotation. If yes - stop spinning
float deltaTargetX = Mathf.Abs(targetRotation.eulerAngles.x - transform.rotation.eulerAngles.x);
float deltaTargetY = Mathf.Abs(targetRotation.eulerAngles.y - transform.rotation.eulerAngles.y);
if(deltaTargetX < 1f && deltaTargetY < 1f)
{
// delay the slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
isSpinning = false;
}
This line in the Start() method is also involved.
targetRotation = transform.rotation;
A transform controls the position, scaling and as is relevant for this case, also the rotation of an object.
Every 5 seconds I need to take a photo and display it in the world. That part is working fine.
Once a photo is taken it need to disappear 1 second after. That's where I'm stuck.
I've gotten it to disappear but then I cant get the new picture to reappear when its function is called again.
Any ideas?
I've tried:
m_CanvasRenderer.enabled = false;
m_CanvasRenderer.enabled = true;
m_Canvas = null;
m_Canvas.setActive(false);
m_Canvas.setActive(true);
With no luck
public class PhotoCaptureExample : MonoBehaviour
{
GestureRecognizer m_GestureRecognizer;
GameObject m_Canvas = null;
Renderer m_CanvasRenderer = null;
PhotoCapture m_PhotoCaptureObj;
CameraParameters m_CameraParameters;
bool m_CapturingPhoto = false;
Texture2D m_Texture = null;
void Start()
{
Initialize();
InvokeRepeating("TakePhoto", 5.0f, 5.0f);
//StartCoroutine(TakePhoto());
}
void TakePhoto()
{
if (m_CapturingPhoto)
{
return;
}
m_CapturingPhoto = true;
m_PhotoCaptureObj.TakePhotoAsync(OnPhotoCaptured);
}
void OnPhotoCaptured(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
// m_CanvasRenderer.enabled = true;
if (m_Canvas == null)
{
m_Canvas = GameObject.CreatePrimitive(PrimitiveType.Quad);
m_Canvas.name = "PhotoCaptureCanvas";
m_CanvasRenderer = m_Canvas.GetComponent<Renderer>() as Renderer;
m_CanvasRenderer.material = new Material(Shader.Find("AR/HolographicImageBlend"));
}
Matrix4x4 cameraToWorldMatrix;
photoCaptureFrame.TryGetCameraToWorldMatrix(out cameraToWorldMatrix);
Matrix4x4 worldToCameraMatrix = cameraToWorldMatrix.inverse;
Matrix4x4 projectionMatrix;
photoCaptureFrame.TryGetProjectionMatrix(out projectionMatrix);
photoCaptureFrame.UploadImageDataToTexture(m_Texture);
m_Texture.wrapMode = TextureWrapMode.Clamp;
m_CanvasRenderer.sharedMaterial.SetTexture("_MainTex", m_Texture);
m_CanvasRenderer.sharedMaterial.SetMatrix("_WorldToCameraMatrix", worldToCameraMatrix);
m_CanvasRenderer.sharedMaterial.SetMatrix("_CameraProjectionMatrix", projectionMatrix);
m_CanvasRenderer.sharedMaterial.SetFloat("_VignetteScale", 1.0f);
// Position the canvas object slightly in front
// of the real world web camera.
Vector3 position = cameraToWorldMatrix.GetColumn(3) - cameraToWorldMatrix.GetColumn(2);
// Rotate the canvas object so that it faces the user.
Quaternion rotation = Quaternion.LookRotation(-cameraToWorldMatrix.GetColumn(2), cameraToWorldMatrix.GetColumn(1));
m_Canvas.transform.position = position;
m_Canvas.transform.rotation = rotation;
m_CapturingPhoto = false;
float counter = 0; float target = 1;
while (counter < target)
{
counter += Time.deltaTime;
}
// m_CanvasRenderer.enabled = false;
}
}
I'm trying to display a simple rectangle right in front of my OVRPlayerController's camera but it seems to be impossible.
I think it might have something to do with the fact that Rect is 2D and my environment is 3D. Does that make sense?
The code is the following (I have ommited the unnecessary stuff):
static int MAX_MENU_OPTIONS = 3;
public GameObject Menu;
private bool showMenu = false;
private float menuIndex = 0;
private bool hasPressedDirectionalPad = false;
public Transform[] buttons = new Transform[MAX_MENU_OPTIONS];
private static Texture2D staticRectTexture;
private static GUIStyle staticRectStyle;
bool DpadIsPressed() {
if (!hasPressedDirectionalPad && Input.GetAxis("DpadY") != 0 && hasPressedDirectionalPad == false){
menuIndex += Mathf.Sign(Input.GetAxis("DpadY")) * (-1);
if (menuIndex < 0) menuIndex = 0;
else if (menuIndex > MAX_MENU_OPTIONS-1) menuIndex = MAX_MENU_OPTIONS-1;
hasPressedDirectionalPad = true;
}
if(Input.GetAxis("DpadY") == 0){
hasPressedDirectionalPad = false;
}
return hasPressedDirectionalPad;
}
void Start() {
Menu.SetActive(false);
staticRectTexture = new Texture2D(1, 1, TextureFormat.RGB24, true);
staticRectStyle = new GUIStyle();
}
void Update() {
if (Input.GetButtonDown("A")) {
DoAction ();
print ("A key was pressed");
}
if (Input.GetButtonDown("Options")) {
showMenu = !showMenu;
if (showMenu) {
Time.timeScale = 0;
menuIndex = 0;
Menu.transform.rotation = this.transform.rotation;
Menu.transform.position = this.transform.position;
} else
Time.timeScale = 1;
}
if (DpadIsPressed ()) {
print ("Dpad key was pressed and menuIndex = " + menuIndex);
}
if (showMenu) {
Menu.SetActive (true);
}
if (!showMenu) {
Menu.SetActive (false);
}
}
void OnGUI() {
if (showMenu) {
Vector3 offset = new Vector3(0, 0, 0.2f);
Vector3 posSelectRectangle = buttons[(int)menuIndex].transform.position + offset;
Rect selectionRectangle = new Rect(posSelectRectangle.x - (float)177/2,
posSelectRectangle.y - (float)43/2,
177.0f, 43.0f);
GUIDrawRect(selectionRectangle, new Color(255.0f, 0, 0));
}
}
void DoAction () {
if (menuIndex == 0)
Salir ();
/*else if (menuIndex == 1)
Guardar ();*/
else if (menuIndex == 2)
Salir ();
}
public static void GUIDrawRect(Rect position, Color color ) {
staticRectTexture.SetPixel( 0, 0, color );
staticRectTexture.Apply();
staticRectStyle.normal.background = staticRectTexture;
GUI.Box( position, GUIContent.none, staticRectStyle );
}
The functions are visited, but the rectangle doesn't show up. Do you see the mistake? Maybe it has something to do with the Oculus Rift?
OnGUI and Screen-space Canvas are not supported in VR mode. This is because there is no way to handle stereoscopic rendering. (Note: They will render to the duplicate display on the user's PC though).
If you want to render in front of the user's camera (like a HUD), you can:
Use a Canvas:
Create a canvas, then add your UI, and set the canvas in world-space. Parent the canvas to the VR Camera game object, and scale it down (it defaults to very very big) and rotate it so it faces the camera.
Or, Use 3D:
Create a 3d Object (Plane, Cube, Quad, whatever!) and parent it to your VR Camera. You can use standard 3d techniques to update it's texture or render texture.