In my project I'm using a button that enables and disables spatial mapping/awareness. It works quite good, in 7 times out of 10. The following behaviour can be observed in the other 3 times. By disabling the spatial-map-mesh (polygones), they disappear to 90%. But 10% stays where it is. Repeated pressing of my button (dis/enable spatial mapping) does not help, the 10% just stays. Any suggestions what the reason for that behaivour could be?
Code Observer:
public void ToggleObservers()
{
if (SpatialAwarenessSystem == null) return;
// If running → stop "running"
if (_isObserverRunning)
{
SetVisualizationOfSpatialMapping(SpatialAwarenessMeshDisplayOptions.None);
SpatialAwarenessSystem.SuspendObservers();
_isObserverRunning = false;
// Disabling the whole system boosts performance ~+5fps
if (ShouldSpatialSystemBeDisabled)
SpatialAwarenessSystem.Disable();
}// Else start spatial mapping
else
{
SpatialAwarenessSystem.Enable();
SetVisualizationOfSpatialMapping(SpatialAwarenessMeshDisplayOptions.Visible);
SpatialAwarenessSystem.ResumeObservers();
_isObserverRunning = true;
}
}
Code Set Visualtization of Spatial Mapping:
public void SetVisualizationOfSpatialMapping(SpatialAwarenessMeshDisplayOptions option)
{
if (CoreServices.SpatialAwarenessSystem is IMixedRealityDataProviderAccess provider)
{
foreach (var observer in provider.GetDataProviders())
{
if (observer is IMixedRealitySpatialAwarenessMeshObserver meshObs)
{
meshObs.DisplayOption = option;
}
}
}
}
Edit:
Bug Report on Github.
I also hit this issue. Until this is fixed in MRTK, you can patch this.
Edit this file:
MixedRealityToolkit.Providers\WindowsMixedReality\WindowsMixedRealitySpatialMeshObserver.cs
Find the suspend function, and add the code between // Begin Patch and // End Patch:
public override void Suspend()
{
#if UNITY_WSA
if (!IsRunning)
{
Debug.LogWarning("The Windows Mixed Reality spatial observer is currently stopped.");
return;
}
// UpdateObserver keys off of this value to stop observing.
IsRunning = false;
// Clear any pending work.
meshWorkQueue.Clear();
// Begin Patch
if (outstandingMeshObject != null)
{
ReclaimMeshObject(outstandingMeshObject);
outstandingMeshObject = null;
}
// End Patch
#endif // UNITY_WSA
}
This appears to be a race condition where the mesh detected logic does not honor the state of the observer (suspended or resumed). Thanks for the issue #Perazim!
Related
I'm trying to use a cloud TTS within my Unity game.
With the newer versions (I am using 2019.1), they have deprecated WWW in favour of UnityWebRequest(s) within the API.
I have tried the Unity Documentation, but that didn't work for me.
I have also tried other threads and they use WWW which is deprecated for my Unity version.
void Start()
{
StartCoroutine(PlayTTS());
}
IEnumerator PlayTTS()
{
using (UnityWebRequestMultimedia wr = new UnityWebRequestMultimedia.GetAudioClip(
"https://example.com/tts?text=Sample%20Text&voice=Male",
AudioType.OGGVORBIS)
)
{
yield return wr.Send();
if (wr.isNetworkError)
{
Debug.LogWarning(wr.error);
}
else
{
//AudioClip ttsClip = DownloadHandlerAudioClip.GetContent(wr);
}
}
}
The URL in a browser (I used Firefox) successfully loaded the audio clip allowing me to play it.
What I want it to do is play the TTS when something happens in the game, it has been done within the "void Start" for testing purposes.
Where am I going wrong?
Thanks in advance
Josh
UnityWebRequestMultimedia.GetAudioClip automatically adds a default DownloadHandlerAudioClip which has a property streamAudio.
Set this to true and add a check for UnityWebRequest.downloadedBytes in order to delay the playback before starting.
Something like
public AudioSource source;
IEnumerator PlayTTS()
{
using (var wr = new UnityWebRequestMultimedia.GetAudioClip(
"https://example.com/tts?text=Sample%20Text&voice=Male",
AudioType.OGGVORBIS)
)
{
((DownloadHandlerAudioClip)wr.downloadHandler).streamAudio = true;
wr.Send();
while(!wr.isNetworkError && wr.downloadedBytes <= someThreshold)
{
yield return null;
}
if (wr.isNetworkError)
{
Debug.LogWarning(wr.error);
}
else
{
// Here I'm not sure if you would use
source.PlayOneShot(DownloadHandlerAudioClip.GetContent(wr));
// or rather
source.PlayOneShot((DownloadHandlerAudioClip)wr.downloadHandler).audioClip);
}
}
}
Typed on smartphone so no warranty but I hope you get the idea
I followed Brackeys tutorial on how to create a Fruit Ninja Replica (youtube).
When creating the blade, though, the behaviour I got wasn't exactly the same.
Expected behaviour
Actual behaviour
The difference is that in the Actual behaviour, the trail starts where it stopped the last time it was shown. The code responsible for this is exactly the same as the video:
public class BladeController : MonoBehaviour
{
bool isCutting = false;
public GameObject bladeTrailPrefab;
GameObject currentBlade;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0)) {
StartCutting();
} else if (Input.GetMouseButtonUp(0)) {
StopCutting();
}
if (isCutting) {
UpdateCut();
}
}
void UpdateCut()
{
GetComponent<Rigidbody2D>().position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void StartCutting()
{
isCutting = true;
this.currentBlade = Instantiate(bladeTrailPrefab, transform);
}
void StopCutting()
{
isCutting = false;
Destroy(currentBlade, 1f);
}
}
After understanding the code, I thought the problem was that I instantiated the bladeTrail before actually moving the Blade to the new position, but tried moving the Instantiate method to UpdateCut after changing the position and only if this.currentBlade == null.
I've search a lot about this, and even found some other posts with the same problem but no answer.
It seams the Instantiate is using the last mouse position to instiantiate the prefab.
Maybe use:
Instantiate(bladeTrailPrefab, Camera.main.ScreenToWorldPoint(Input.mousePosition), Quaternion.identity)
I ran into this problem following the tutorial as well.
It's a few years later but for those of you who hit this page, I found a solution for me that while isn't fantastic, it's better than having the streaks shown in the post.
Before instantiating the trail vfx, make sure to wait until fixed update is called after you set the position of the parent transform.
I did this with a Coroutine like so:
private IEnumerator StartCutting()
{
// When we begin cutting, move the blade object to the input position
m_isCutting = true;
m_previousPosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
m_rigidBody.position = m_previousPosition;
// Then for positions to be updated so that the vfx doesn't get confused
yield return m_waitForFixedUpdate; // new WaitForFixedUpdate(); <-- cache this
// Instantiate the trail at this new position
m_currentTrail = Instantiate(m_trailPrefab, m_rigidBody.transform);
m_collider.enabled = false;
}
Working on a Unity hybrid VR (cardboard) /2D app. The cardboard side of it works fine. I am having trouble with the 2D/VR switching.
When I am in 2D mode, reticle does not move, although screen taps register. So the app seems unaware of the gyro.
I feel like I am missing something fundamental here. I have a GvrEventSystem prefab that has both an EventSystem and GvrPointerInputModule components.
What obvious thing am I over-looking?
ETA:
I have been asked to add relevant code. Here is the code for 2D-VR switching on-the-fly. This code executes w/out error, and the app switches between VR and 2D mode every 3 seconds:
readonly string NONE_STRING = "";
readonly string CARDBOARD_STRING = "cardboard";
void Start()
{
Invoke("GoPhone", 3.0f);
}
void GoPhone()
{
SetVREnabled(false);
Invoke("GoVR", 3.0f);
}
void GoVR()
{
SetVREnabled(true);
Invoke("GoPhone", 3.0f);
}
void SetVREnabled(bool isEnabled)
{
if (isEnabled)
{
StartCoroutine(LoadDevice(CARDBOARD_STRING));
}
else
{
StartCoroutine(LoadDevice(NONE_STRING));
}
}
IEnumerator LoadDevice(string newDevice)
{
if (String.Compare(XRSettings.loadedDeviceName, newDevice, true) != 0)
{
XRSettings.LoadDeviceByName(newDevice);
yield return null;
if (!XRSettings.loadedDeviceName.Equals(NONE_STRING))
XRSettings.enabled = true;
}
}
Although I feel like my problem is a configuration problem, and not a code problem. In the editor, which does not support VR mode, the app behaves in 2D mode as expected.
Also ETA:
JIC
User error! I did not follow the "Magic Window" instructions as detailed at https://developers.google.com/vr/develop/unity/guides/magic-window... let my folly be a warning to future generations!
I am trying out Area Recognition using Area Learning with predefined ADF files using Project Tango in Unity3d. I use the script from this tutorial as the basis, but for some reason it won't relocalize.
using UnityEngine;
using System.Collections;
using Tango;
public class TestADFFile : MonoBehaviour, ITangoLifecycle
{
private TangoApplication m_tangoApplication;
public UnityEngine.UI.Text statusText;
public string adfName;
public void Start()
{
m_tangoApplication = FindObjectOfType<TangoApplication>();
if (m_tangoApplication != null)
{
m_tangoApplication.Register(this);
m_tangoApplication.RequestPermissions();
}
}
public void OnTangoPermissions(bool permissionsGranted)
{
if (permissionsGranted)
{
if(AreaDescription.ImportFromFile(System.IO.Path.Combine(Application.streamingAssetsPath, "adfs/" + adfName))){
statusText.text = "success!";
}
else{
statusText.text = "fail!";
}
AreaDescription[] list = AreaDescription.GetList();
AreaDescription mostRecent = null;
AreaDescription.Metadata mostRecentMetadata = null;
if (list.Length > 0)
{
// Find and load the most recent Area Description
mostRecent = list[0];
mostRecentMetadata = mostRecent.GetMetadata();
foreach (AreaDescription areaDescription in list)
{
AreaDescription.Metadata metadata = areaDescription.GetMetadata();
if (metadata.m_dateTime > mostRecentMetadata.m_dateTime)
{
mostRecent = areaDescription;
mostRecentMetadata = metadata;
}
}
m_tangoApplication.Startup(mostRecent);
}
else
{
// No Area Descriptions available.
Debug.Log("No area descriptions available.");
}
}
}
public void OnTangoServiceConnected()
{
}
public void OnTangoServiceDisconnected()
{
}
}
The statusText is set to "success" so apparently the ADF is successfully loaded, right?
You're doing it right. Relocalization with area learning mode off works very quick. But relocalization with area learning mode on takes quite a while. You have to walk around up to 3-5 minutes until the relocalization works. Don't give up. I had the same problem. But in the end, it works!
Is not an answer I think, but just a checklist of things I would check.
Check that the ADF to relocalize is the right one, you may be loading an ADF from a different area.
On the TangoManager component check if Enable Area Descriptions is set to true.
Also check if the scene is set up correctly with all tango components required like: RelocalizingOverlay.cs, TangoApplication.cs
Also as a personal note I have noticed that ADF sometimes take quite a while to relocalized and sometimes they don't relocalize at all.
I think the reasons are that the room has change in someway or the lighting is very different, by different I mean maybe the day you recorded that ADF was a very sunny day and the day you are trying to relocalize is cloudy.(Again this are just theories of mine, I got from my testing)
I'm having a bit of trouble with some Unityscript.
What I want to do is have a GUI message appear when certain objects are touched (then vanish after a time). I think I have it mostly worked out, but the message trips automatically.
My attempted solution is to have a conditional part of the GUI message that only allows it to appear when a boolean is true. Then in a different script that is already tripped when the object is touched, the boolean is set to true, so the script can run, and reset the boolean to false.
However I'm getting a "You can only call GUI functions from inside OnGUI. I'm not sure what that means.
Message code:
youdied.js
static var deathMessageShow : boolean = false;
function OnGUI() {
if(deathMessageShow == true){
if(Time.time >= 5 )
GUI.Box(Rect(200,300,275,150),"You Died");
}
deathMessageShow = false;
}
Other code (truncated):
dead.js
function OnTriggerEnter()
{
//code that resets environment
youdied.deathMessageShow = true;
}
Any suggestions on what is going on, or a better solution would be greatly appreciated.
The following code will show GUI message for 5 seconds then hides it:
youdied.js
static var deathMessageShow : boolean = false;
function OnGUI()
{
if(deathMessageShow)
{
GUI.Box(Rect(200,300,275,150),"You Died");
// call the function HideDeathMessage() after five seconds
Invoke("HideDeathMessage", 5.0f);
}
}
function HideDeathMessage()
{
deathMessageShow = false;
}
Other code:
dead.js
function OnTriggerEnter()
{
//code that resets environment
youdied.deathMessageShow = true;
}