void Update() { // Update the indicator location if (placementIndicatorEnabled) { UpdatePlacementPose(); UpdatePlacementIndicator(); } // Context is always facing to the camera if (labelList.Count != 0) { foreach (GameObject t in labelList) { t.transform.LookAt(Camera.main.transform); t.transform.Rotate(new Vector3(0, 180, 0)); } } if (landmarkList.Count != 0) { foreach (GameObject l in landmarkList) { l.transform.LookAt(Camera.main.transform); l.transform.Rotate(new Vector3(0, 180, 0)); } } if (profilePanel.activeSelf) { profilePanel.transform.LookAt(Camera.main.transform); profilePanel.transform.Rotate(new Vector3(0, 180, 0)); } // Detect tapping if ((Input.touchCount > 0) && (Input.GetTouch(0).phase == TouchPhase.Began)) { Ray raycast = Camera.main.ScreenPointToRay(Input.GetTouch(0).position); RaycastHit raycastHit; if (Physics.Raycast(raycast, out raycastHit)) { #region SHOW_CITY_PROFILE // Display city profile if (raycastHit.collider.CompareTag("Pin")) { // Compute the scaling factor float distanceScale = (raycastHit.collider.transform.position - referenceOrigin).magnitude / 1000; // Display the panel before the other sprites by shifting a very small value so that it is not occluded // A. Dynamic distance //profilePanel.transform.position = raycastHit.collider.transform.position * 0.99f; // B. Fixed distance profilePanel.transform.position = Camera.main.transform.position + 1.0f * (raycastHit.point - Camera.main.transform.position).normalized; // Fetch selected landmark information CORE.LocationInfo selectedLocation = CORE.LOCATION_DATABASE[int.Parse(raycastHit.collider.name)]; // Assign information to the panel profilePanel.transform.Find("Label_CityName").GetComponent <Text>().text = selectedLocation.name; profilePanel.transform.Find("Label_CityCountry").GetComponent <Text>().text = selectedLocation.country + ""; profilePanel.transform.Find("Label_CityDescription").GetComponent <Text>().text = selectedLocation.description; profilePanel.transform.Find("Button_Portal").gameObject.SetActive(selectedLocation.panorama); // Reset images just in case the target images are not available profilePanel.transform.Find("Image_CityLandmark").gameObject.GetComponent <Image>().sprite = defaultLandmark; profilePanel.transform.Find("Image_CountryFlag").gameObject.GetComponent <Image>().sprite = defaultFlag; // Load images from local resources StartCoroutine(CORE.LoadImageToSprite(Path.Combine(Application.streamingAssetsPath, CORE.IMAGE_FOLDER_CITY, CORE.FileNameParser(selectedLocation.name) + CORE.IMAGE_FORMAT), (result) => { profilePanel.transform.Find("Image_CityLandmark").gameObject.GetComponent <Image>().sprite = result; })); StartCoroutine(CORE.LoadImageToSprite(Path.Combine(Application.streamingAssetsPath, CORE.IMAGE_FOLDER_FLAG, CORE.FileNameParser(selectedLocation.country) + CORE.IMAGE_FORMAT), (result) => { profilePanel.transform.Find("Image_CountryFlag").gameObject.GetComponent <Image>().sprite = result; })); StartCoroutine(CORE.LoadImageToTexture(Path.Combine(Application.streamingAssetsPath, CORE.IMAGE_FOLDER_PANORAMA, CORE.FileNameParser(selectedLocation.name) + CORE.IMAGE_FORMAT), (result) => { mappedEarth.transform.Find("Portal_Panorama").GetComponent <Renderer>().material.SetTexture("_Texture", result); })); panoramaPanel.transform.Find("Text").GetComponent <Text>().text = selectedLocation.landmark; // Append formatted string to the url url = Path.Combine(CORE.SEARCH_ENGINE_PATH, CORE.FileNameParser(selectedLocation.name)); // Scale the panel // A. Dynamic scale //profilePanel.transform.localScale = Vector3.one * UIPanelScaleDynamic * distanceScale; // B. Fixed scale profilePanel.transform.localScale = Vector3.one * UIPanelScaleFixed; // Rotate the panel to face the user profilePanel.transform.LookAt(Camera.main.transform); profilePanel.transform.Rotate(new Vector3(0, 180, 0)); // Show the panel profilePanel.SetActive(true); } #endregion } } }
public void MapEarth() { profilePanel.SetActive(false); // Clear old variables Destroy(mappedEarth); foreach (GameObject l in landmarkList) { Destroy(l); } landmarkList.Clear(); foreach (GameObject t in labelList) { Destroy(t); } labelList.Clear(); #region EARTH_MAPPING // Initialise the earth object and the horizon // The horizon (range) is 5km x 5km as suggested for a 1.7m human referenceOrigin = placementPose.position; referenceEarth = Instantiate(earthToReference, referenceOrigin, Quaternion.identity); mappedEarth = Instantiate(earthHorizonPrefab, referenceOrigin, Quaternion.identity); Transform pinGroup = referenceEarth.transform.Find("Group_Pins"); Transform refTop = referenceEarth.transform.Find("Ref_Top"); // Scale and reposition the Earth referenceEarth.transform.localScale = Vector3.one * CORE.EARTH_PREFAB_SCALE_TO_REAL; // Rotate the Earth so that the current position is facing up so that we can do the following calculations // Use the pre-calculated value referenceEarth.transform.rotation = CORE.ROTATE_TO_TOP; // Rotate the Earth so that the current north direction is aligned geographically // First, find the current device facing direction (projection on z axis) Vector3 facingDirection = Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up).normalized; Vector3 prefabNorthDirection = Vector3.ProjectOnPlane(refTop.position - referenceEarth.transform.position, Vector3.up).normalized; // Then, compute the degree required to rotate the earth to the facing direction Quaternion rotateToFacingDirection = Quaternion.FromToRotation(prefabNorthDirection, facingDirection); // Lastly, compute the degree required to rotate the earth to the geographical north Quaternion rotateToGeographicalNorth = Quaternion.Euler(0, -Input.compass.trueHeading, 0); // 1. Use ROTATION // Compute the degree required to rotate the north direction to match the facing direction //float degree; //Vector3 axis; //rotateToFacingDirection.ToAngleAxis(out degree, out axis); //mappedEarth.transform.RotateAround(transform.position, Vector3.up, degree); // Then rotate the Earth again according to the heading direction from the GPS so that the north direction is matched both virtually and physically //mappedEarth.transform.Rotate(Vector3.up, -Input.compass.trueHeading, Space.World); // OR 2. Use QUATERNION // Those steps need to be combined backwards to get the correct result referenceEarth.transform.rotation = rotateToGeographicalNorth * rotateToFacingDirection * CORE.ROTATE_TO_TOP; // Fix the floating point imprecision issue due to the large scale Vector3 impreciseRefPosition = pinGroup.GetChild(0).gameObject.transform.position; float preciseScaleFactor = CORE.EARTH_CRUST_RADIUS / impreciseRefPosition.y; foreach (Transform pin in pinGroup) { pin.position *= preciseScaleFactor; } // Shift the mapped earth down so that the y value of current position is the same as the selected surface for mapping referenceEarth.transform.position -= new Vector3(0, CORE.EARTH_CRUST_RADIUS, 0); #endregion mappedEarth.transform.Find("Mapping_Border").rotation = referenceEarth.transform.rotation; #region PIN_ASSIGNMENT Vector3 preciseRefPosition = pinGroup.GetChild(0).gameObject.transform.position; foreach (Transform pin in pinGroup) { // Display landmarks excluding the current position if (pin.position != preciseRefPosition) { CORE.LocationInfo currentPinLocation = CORE.LOCATION_DATABASE[int.Parse(pin.gameObject.name)]; float geoDistance = CORE.DistanceBetweenLatLong(currentPinLocation.coord, CORE.USER_LATLONG); float distanceScale = (pin.position - referenceOrigin).magnitude / 1000; #region CITY_LANDMARK_IMAGE // Instantiate the landmark prefab GameObject landmark = Instantiate(landmarkPrefab, pin.position, Quaternion.identity, canvasWorld.transform); // Set the landmark image Transform landmarkImage = landmark.transform.Find("UI_Landmark_Image"); landmarkImage.name = pin.name; // Rescale the landmark landmark.transform.localScale *= distanceScale; // Change the sprite based on the geographical distance if (geoDistance > 5) { landmarkImage.GetComponent <Image>().sprite = spriteFarPin; } else { landmarkImage.GetComponent <Image>().sprite = spriteNearPin; } // Fill the color landmarkImage.GetComponent <Image>().color = new Color32(0, 255, 0, 255); landmarkList.Add(landmark); #endregion #region CITY_INFO_LABEL // Place hovering labels GameObject label = Instantiate(labelPrefab, pin.position, Quaternion.identity, canvasWorld.transform); label.transform.Find("Label_LandmarkName").GetComponent <Text>().text = currentPinLocation.name + ", " + currentPinLocation.country; // Display the indicator based on the geographical distance if (geoDistance > 5) { label.transform.Find("Label_LandmarkDistance").GetComponent <Text>().text = "▽ "; } else { label.transform.Find("Label_LandmarkDistance").GetComponent <Text>().text = "▲ "; } // Display the geographical distance label.transform.Find("Label_LandmarkDistance").GetComponent <Text>().text += (geoDistance.ToString() + "km"); // Rescale the label label.transform.localScale = Vector3.one * UILabelScale * distanceScale; labelList.Add(label); #endregion } else { pin.gameObject.SetActive(false); } } profilePanel.transform.SetAsLastSibling(); #endregion legendPanel.SetActive(true); // Destroy it since it is no longer needed Destroy(referenceEarth); }