как я могу синхронизировать между снимком экрана и извлечением местоположения gameObject в Unity? - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь создать данные для обнаружения.

не на андроиде.

Я перемещаю объект на экране и каждые X секунд сохраняю снимок экрана и координаты объекта в файле json.

Проблема в том, что снимок экрана не появляется в то время, когда я его запрашиваю, а в поиске координат и создании файла json.

Мне удалось решить эту проблему, подождав фиксированный номер кадра между каждой операцией.

public static class WaitFor
{
    public static IEnumerator Frames(int frameCount)
    {
        while (frameCount > 0)
        {
            frameCount--;
            yield return null;
        }
    }
}

public IEnumerator CoroutineAction()
{
    yield return StartCoroutine(WaitFor.Frames(3)); 
}

public void Save()
{
    ScreenCapture.CaptureScreenshot(@".\" + counter + ".png");

    CoroutineAction();        

    Vector3 location = Camera.main.WorldToScreenPoint(gameObject.transform.position);

    System.IO.File.WriteAllText(@".\" + counter + ".json", toJson(location));

    counter++;
}

Это решение несколько работает, но оно все еще не является точным местоположением узлов, и я был бы признателен, если бы кто-то знал лучшее и более чистое решение.

Другая проблема, с которой я столкнулся, заключается в том, что если я попытаюсь использовать опцию суперразрешения

Пример:

ScreenCapture.CaptureScreenshot(@".\" + counter + ".png" , 4);

И умножьте вектор местоположения на 4.

Места расположения не будут находиться в местоположении объекта на 2D-изображении, даже близко не будут. Что не имеет никакого смысла, и мне бы очень помогло, если бы я мог создать увеличенное изображение без использования внешних библиотек, чтобы увеличить изображение на 4 (что прекрасно работает).

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Возможно, я пока не отвечаю на ваш вопрос, но что я имел в виду под комментарием:

в настоящее время вы 1. неправильно используете сопрограмму ожидания и 2. она ничего не делает

К 1.:

public void Save()
{
    ScreenCapture.CaptureScreenshot(@".\" + counter + ".png");

    CoroutineAction();        

    Vector3 location = Camera.main.WorldToScreenPoint(gameObject.transform.position);

    System.IO.File.WriteAllText(@".\" + counter + ".json", toJson(location));

    counter++;
}

Что происходит на самом деле:

ScreenCapture.CaptureScreenshot(@".\" + counter + ".png");
Vector3 location = Camera.main.WorldToScreenPoint(gameObject.transform.position);
System.IO.File.WriteAllText(@".\" + counter + ".json", toJson(location));
counter++;

выполняется немедленно. Чем «параллель» (не совсем конечно) сопрограмма будет работать, если вы используете StartCoroutine(CoroutineAction());

Но теперь до 2.:

рутина

public IEnumerator CoroutineAction()
{
    yield return StartCoroutine(WaitFor.Frames(3)); 
}

абсолютно ничего не делает, кроме как ждать 3 кадра ...


Полагаю, вы хотели сделать что-то вроде

// actually start a coroutine
public void Save()
{
    StartCoroutine(SaveRoutine());
}

// optional parameter superSize => if not provided uses 1
private IEnumerator SaveRoutine(int superSize = 1)
{
    // makes sure the factor is always >= 1
    var sizeFactor = Mathf.Max(1,superSize);

    ScreenCapture.CaptureScreenshot(@".\" + counter + ".png", sizeFactor);

    //Wait for 3 frames
    // I think this makes more sense than your dedicated class with the static method
    for (int i = 0; i < 4; i++)
    {
        yield return null;
    }

    Vector3 location = Camera.main.WorldToScreenPoint(gameObject.transform.position) * sizeFactor;

    System.IO.File.WriteAllText(@".\" + counter + ".json", toJson(location));

    counter++;
}

Кроме того, как я уже сказал, я не уверен, потому что я не могу сказать, следует ли вам получить местоположение в кадре, где вы начинаете захват, или в кадре, где вы заканчиваете. Но я полагаю, вам лучше заранее узнать местоположение, чем начинать захват:

// optional parameter superSize => if not provided uses 1
private IEnumerator SaveRoutine(int superSize = 1)
{
    // make sure the factor is always at least 1
    var sizeFactor = Mathf.Max(1,superSize);
    var location = Camera.main.WorldToScreenPoint(gameObject.transform.position) * sizeFactor;

    ScreenCapture.CaptureScreenshot(@".\" + counter + ".png", sizeFactor);

     //Wait for 3 frames
    // I think this makes more sense than your dedicated class with the static method
    for (int i = 0; i < 4; i++)
    {
        yield return null;
    }    

    System.IO.File.WriteAllText(@".\" + counter + ".json", toJson(location));

    counter++;
}

Также обратите внимание, что, как упоминалось в , связанный дубликат

CaptureScreenshot немедленно возвращается на Android. Снимок экрана продолжается в фоновом режиме. Полученный снимок экрана сохраняется в файловой системе через несколько секунд .

Вы ожидаете 3 кадра ... это обычно даже не 1/10 секунды (очевидно, в зависимости от частоты кадров).

Вам следует подождать реальные секунды, используя WaitForSeconds, например,

yield return new WaitForSeconds(3);

ждать например 3 секунды НО также обратите внимание, что это не будет работать в сочетании с предложенным Time.timeScale, поскольку WaitForSecodns также зависит от timeScale.


Я думаю, что вы также не должны / не должны использовать

@".\" + counter + ".png"

в имени файла, но просто

counter + ".png"

с

На мобильных платформах имя файла добавляется к постоянному пути данных. См. Application.persistentDataPath для получения дополнительной информации.

0 голосов
/ 10 января 2019

Попробуйте приостановить ваши движения следующим образом:

Time.timeScale = 0;

(цикл игры продолжается)

Вы можете подождать несколько кадров / время или посмотреть, получите ли вы какой-либо отзыв, когда снимок экрана будет сделан.

Это работает лучше всего, если вы используете Time.deltaTime в вашем Update() методе, который все равно рекомендуется.

...