Как настроить или иным образом настроить снимок экрана, чтобы он имел точные размеры определенного спрайта в трехмерном пространстве (например, Gameobject со SpriteRenderer).
Рендер-камера устанавливается прямо над спрайтом, но имеет пустое пространство за пределами границ спрайта. Я не уверен, как точно настроить область просмотра рендеркамеры.
Вот как выглядит сцена. (На самом деле это быстрая и упрощенная версия моей текущей сцены, чтобы продемонстрировать мою конкретную проблему) И да, я пытаюсь сделать конкретный снимок экрана во время выполнения. Основная камера находится под произвольным углом, но камера рендеринга может быть отцентрована по рендереру спрайтов. Другими словами, снимок экрана, который я делаю, выглядит так же, как в окне предварительного просмотра камеры в правом нижнем углу на рисунке ниже. Как обрезать (или настроить область просмотра, чтобы исключить) лишнюю часть, выходящую за пределы размера средства визуализации спрайтов?
Не могли бы вы показать на нескольких скриншотах, что происходит сейчас, и что бы вы хотели, чтобы произошло?
@derHugo не обязательно, так как я пытаюсь обрезать сам спрайт. я пытаюсь сделать снимок экрана в трехмерном мировом пространстве, хотя и с камеры сверху вниз, сосредоточенной на средстве визуализации спрайтов, а не в двухмерном пространстве.
обновлены некоторые скриншоты настройки, которые могут попытаться прояснить эту ситуацию с несколькими камерами
Есть возможность сделать камеру Orthographic
?
в идеале нет, так как объекты 3D-игры выглядят по-разному в ортогональном направлении и в перспективе... но если единственное решение для правильной обрезки состоит в том, чтобы сделать это, я думаю, нам придется это сделать?
Вы пробовали читать границы.экстенты, бороться с Perspective
настоящая головная боль, у меня были эти проблемы несколько месяцев назад и я предпочитал использовать Orthographic
вид...
@ina камера всегда будет располагаться по нормали спрайта от его середины?
@ina, ты нашел хорошее решение?
я не смог заставить ваше решение работать ... вы работали с визуализатором спрайтов вместо квадроцикла?
Вы можете рассчитать размер усеченной пирамиды в мировом пространстве:
float frustumHeight = 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
float frustrumWidth = frustumHeight * camera.aspect;
Затем, если вы знаете высоту и ширину картины в мировых единицах, вы можете рассчитать, какую часть центральной части экрана она занимает:
float widthPortion = paintingWidth / frustrumWidth;
float heightPortion = paintingHeight / frustrumHeight;
Тогда вы знаете, какую часть центра renderTexture нужно скрыть:
float leftRightCrop = (1f-widthPortion)/2f;
float topBottomCrop = (1f-heightPortion)/2f;
Итак, чтобы скопировать его из текстуры рендеринга вашей камеры, вы можете сделать это в OnPostRender
:
RenderTexture currentRT = RenderTexture.active;
RenderTexture.active = Cam.targetTexture;
Cam.Render();
int croppedPixelWidth = widthPortion*camera.pixelWidth;
int croppedPixelHeight = heightPortion*camera.pixelHeight;
int leftPixelPadding = leftRightCrop*camera.pixelWidth;
int bottomPixelPadding = topBottomCrop*camera.pixelHeight;
Texture2D cropped = new Texture2D(croppedPixelWidth, croppedPixelHeight);
cropped.ReadPixels(new Rect(
leftPixelPadding,
bottomPixelPadding,
leftPixelPadding + croppedPixelWidth,
bottomPixelPadding + croppedPixelHeight), 0, 0);
cropped.Apply();
RenderTexture.active = currentRT;
Или, как это использовала @ina,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class SpritePerfectScreenshot : MonoBehaviour
{
bool ScreenshotIt;
float widthPortion; float heightPortion;
float leftRightCrop; float topBottomCrop;
Camera camera;
public void TakeScreencap(Camera c,float distance,float pw,float ph)
{
camera = c;c.enabled = true;
SetItUp(distance, pw, ph);
}
void SetItUp(float distance,float paintingWidth,float paintingHeight)
{
float frustrumHeight = 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
float frustrumWidth = frustrumHeight * camera.aspect;
widthPortion = (paintingWidth / frustrumWidth);
heightPortion = (paintingHeight / frustrumHeight);
leftRightCrop = (1f - widthPortion) / 2f;
topBottomCrop = (1f - heightPortion) / 2f;
ScreenshotIt = true;
print("SetItUp " + distance);
}
private void OnPostRender()
{
if (ScreenshotIt)
{
int croppedPixelWidth =(int) (widthPortion * camera.pixelWidth);
int croppedPixelHeight =(int) (heightPortion * camera.pixelHeight);
int leftPixelPadding =(int)( leftRightCrop * camera.pixelWidth);
int bottomPixelPadding =(int)( topBottomCrop * camera.pixelHeight);
print(croppedPixelWidth + " " + croppedPixelHeight);
Texture2D cropped = new Texture2D(croppedPixelWidth, croppedPixelHeight);
cropped.ReadPixels(new Rect(
leftPixelPadding,
bottomPixelPadding,
leftPixelPadding + croppedPixelWidth,
bottomPixelPadding + croppedPixelHeight), 0, 0);
cropped.Apply();
string uuid = UUID.GetUUID(); string localPath = Application.persistentDataPath + "/" + uuid + ".png";
#if !UNITY_EDITOR
NativeGallery.SaveImageToGallery(cropped.EncodeToPNG(), "A Beautiful Letter",uuid);
#else
File.WriteAllBytes(localPath,cropped.EncodeToPNG());
print(localPath);
#endif
//TODO server (?)
ScreenshotIt = false;camera.enabled = false;
}
}
}
Привет! я думаю, что проблема может быть в том, что квадрат изображения может быть не в правильных единицах масштаба?
на самом деле я не уверен, правильно ли я реализую регион в финальном пикселе чтения.....
Texture2D image = new Texture2D(camera.targetTexture.width, camera.targetTexture.height);
` image.ReadPixels(new Rect(camera.pixelWidth * leftRightCrop * 0,25f, camera.pixelHeight * topBottomCrop*0,25f, leftRightCrop * camera.pixelWidth, topBottomCrop * camera.pixelHeight), 0, 0); `
@ina Я отредактировал свой ответ, указав внизу, как его использовать. Я также изменил переменные ___Crop
, чтобы они были более полезными, поэтому обязательно обратите внимание на эти изменения.
@ina, у тебя были еще какие-то проблемы с этим ответом?
есть ли опечатка в расчетеcroppedPixelHeight
@ina выглядит так. Я думаю, что исправил это
Текстура имеет недопустимую ширину/высоту
Мировые единицы @ina, также известные как метры. Также я только что понял, что в строке ReadPixels
была еще одна опечатка. Попробуйте, если это работает для вас
как перевести размеры фото в метры
вы не знаете. Вы получаете размер spriterenderer/quad в мировых метрах. Размер фото в пикселях значения не имеет.
хммм, а как узнать размер квадрата рендерера спрайтов в мировых метрах (?)
Круто, наконец-то заработало! gist.github.com/yosun/daa166bdac92cfcaba350ec1bb4e6e06
@ina, если это один или два пикселя, это может быть связано с ошибками округления, может быть, увеличить начало прямоугольника на 1-2 пикселя и уменьшить размер вдвое?
кажется, что это зависит от экрана устройства - я обманул его, чтобы он работал в редакторе единства, но на iphone он делает это и т. д.
хм, на самом деле я думаю, что это может быть связано с несколькими камерами и OnPostRender - должен ли сценарий быть на конкретной камере или он может быть на Camera.main?
@ina можно прикрепить к любому игровому объекту. Я думаю, что понимаю проблему, и чтобы ее исправить, я думаю, вам нужно поменять активную текстуру рендеринга на ту, что на камере. Я отредактировал ответ, чтобы включить это. Если это не сработает, лучше задать отдельный вопрос.
OnPostRender должен быть подключен к камере, но правильно
@ina о, да, ты прав. Вероятно, было бы лучше поместить его на камеру, которую вы снимаете для изображения, но на практике (если вы не перемещаете объекты после рендеринга одной камеры и до того, как другая сделает это в том же кадре, что довольно необычно), он, вероятно, выиграл. не имеет значения, и любой игровой объект с активной камерой будет работать так же.
может обрезка текстура до нужного размера поможет? В общем, добавьте свой код, чтобы мы могли воспроизвести проблему.