Во многих играх, особенно сетевых, очень часто разработчики добавляют возможность игрокам делится друг с другом достигнутыми результатами в игре. Одним из таких способов является выполнение скриншота, когда можно сделать снимок экрана, результата или особенного момента в игре.
В Unity также не обошли стороной эту возможность и предоставили разработчикам необходимый функционал – выполнять снимки экрана без особых усилий. Для этого существует два способа, давайте рассмотрим их подробнее.
- Выполнение снимка экрана через метод ScreenCapture.CaptureScreenshot.
- Выполнение снимка с камеры через RenderTexture.
В первом случае с помощью метода ScreenCapture.CaptureScreenshot выполняется просто снимок экрана. Использовать его достаточно просто: при вызове метода, необходимо указать имя снимка и его масштабирование. На ПК этот метод аналогичен выполнению скриншота с помощью сочетания кнопок Ctrl+Print. Этот метод удобен своей простотой выполнения снимка – “как есть”, без каких либо условий.
Для примера – используем простую заготовку для игры с готовым меню.
Здесь по нажатию кнопки “сделать снимок” выполняется скриншот через метод ScreenCapture.CaptureScreenshot в скрипте PhotoCapture.
- public class PhotoCapture : MonoBehaviour {
- public void MakeScrenshot() {
- ScreenCapture.CaptureScreenshot(“Screenshot01”, 1);
- }
- }
Добавляем этот скрипт на камеру и добавляем кнопке “сделать снимок” нужное действие в поле OnClick.
После выполнения скриншота, мы получим точную копию снимка экрана со всеми элементами – все достаточно просто. Но здесь есть одно неудобство, само меню закрывает почти весь экран и мы не видим, что конкретно происходит на сцене в игре. Чтобы получить “чистое” изображение – только с теми элементами, которые нам бы хотелось показать другим игрокам, необходимо воспользоваться вторым способом выполнения снимка с помощью RenderTexture. Для этого нам понадобится еще одна камера и немножко поработать со слоями.
У каждой камеры в настройках есть параметр Texture Target, куда можно поместить RenderTexture и тем самым получить в виде текстуры именно то изображение, которое сейчас “видит” камера.
RenderTexture, как понятно из названия, тоже текстура, отличается она только большим числом настроек и возможностью сохранять изображение с камеры. Это именно то, что нам необходимо, для выделения объектов на скриншоте.
Переходим на сцену где создадим новую камеру. Для удобства можно поместить новую камеру внутри старой, чтобы они занимали одну и ту же позицию.
Теперь укажем новой камере слои, которые необходимо отображать новой камере. Здесь достаточно просто убрать слой UI, чтобы скрыть меню в новой камере. Далее уменьшаем глубину рендера Depth так, чтобы она была меньше, чем у главной камеры. Это необходимо, чтобы новая камера не работала поверх главной.
Переходим к скрипту PhotoCapture. Для начала сотрем все, что было в методе MakeScrenshot и объявим переменную Camera для новой камеры.
public class PhotoCapture : MonoBehaviour {
public Camera captureCamera;
public void MakeScrenshot() {
}
}
В переменной captureCamera будет хранится ссылка на новую камеру. Теперь переходим в метод MakeScrenshot, где первым действием создадим новую текстуру Texture2D. Так как изображение в RenderTexture постоянно обновляется, необходимо будет перенести полученное изображение с камеры в отдельную текстуру, которую в дальнейшем мы сможем использовать как угодно: сохранить, редактировать или поделится с другими игроками.
- public void MakeScrenshot() {
- int width = this.captureCamera.pixelWidth;
- int height = this.captureCamera.pixelHeight;
- Texture2D texture = new Texture2D(width, height);
- }
Далее необходимо получить текущую RenderTexture из “архива”, для этого воспользуемся статическим методом GetTemporary класса RenderTexture.
- public void MakeScrenshot() {
- int width = this.captureCamera.pixelWidth;
- int height = this.captureCamera.pixelHeight;
- Texture2D texture = new Texture2D(width, height);
- RenderTexture targetTexture = RenderTexture.GetTemporary(width, height);
- }
Эта текстура targetTexture будет целевой, куда новая камера будет “рендерить” изображение со сцены.
- public void MakeScrenshot() {
- int width = this.captureCamera.pixelWidth;
- int height = this.captureCamera.pixelHeight;
- Texture2D texture = new Texture2D(width, height);
- RenderTexture targetTexture = RenderTexture.GetTemporary(width, height);
- this.captureCamera.targetTexture = targetTexture;
- this.captureCamera.Render();
- }
Указываем камере текстуру, в которую необходимо поместить изображение и вызываем метод Render, который “заставит” камеру произвести единоразовый снимок сцены.
Теперь необходимо поместить целевую текстуру targetTexture, которую мы брали из архива, обратно, так как теперь очередь главной камеры “рендерить” сцену.
- public void MakeScrenshot() {
- int width = this.captureCamera.pixelWidth;
- int height = this.captureCamera.pixelHeight;
- Texture2D texture = new Texture2D(width, height);
- RenderTexture targetTexture = RenderTexture.GetTemporary(width, height);
- this.captureCamera.targetTexture = targetTexture;
- this.captureCamera.Render();
- RenderTexture.active = targetTexture;
- }
Готово. В переменной targetTexture хранится изображение с новой камеры, пока главная камера еще не успела поместить в эту же переменную свое изображение, необходимо перенести изображение из RenderTexture в обычную текстуру Texture2D.
- public void MakeScrenshot() {
- int width = this.captureCamera.pixelWidth;
- int height = this.captureCamera.pixelHeight;
- Texture2D texture = new Texture2D(width, height);
- RenderTexture targetTexture = RenderTexture.GetTemporary(width, height);
- this.captureCamera.targetTexture = targetTexture;
- this.captureCamera.Render();
- RenderTexture.active = targetTexture;
- Rect rect = new Rect(0, 0, width, height);
- texture.ReadPixels(rect, 0, 0);
- texture.Apply();
- }
Чтобы скопировать содержимое одной текстуры в другую, необходимо воспользоваться методом ReadPixels и указать какую область (Rect) с пикселями необходимо скопировать. Теперь у нас имеется полное изображение в новой текстуре, с которым можно дальше работать. К примеру, вывести его на экран сразу после выполнения снимка с помощью того же UI.
Новой камере можно указать любые параметры отображения, или добавить эффекты и получать уже отредактированное изображение сразу после снимка.
Заключение
Такой подход “рендера в текстуру” можно использовать для создания миникарты, разных эффектов с камерами или создания камер которые будут показывать изображения на любых поверхностях.
а как делать это на AR камере?
Как у вас так быстро делается и выводится снимок.? У меня почему-то это операция занимает больше времени иногда просто не успевает сохраниться изображение и поэтому не получается его вывести сразу же. Приходится делать все операции с задержкой через корутины.
Возможно у вас слишком большое разрешение стоит на камере, поэтому требуется больше времени, чтобы сделать снимок. Попробуйте уменьшить разрешение на камере и сделать снимок еще раз.