Скриншот рендер-текстуры (не основной камеры) для точного соответствия спрайту (в 3D-пространстве) - Unity

Как настроить или иным образом настроить снимок экрана, чтобы он имел точные размеры определенного спрайта в трехмерном пространстве (например, Gameobject со SpriteRenderer).

Рендер-камера устанавливается прямо над спрайтом, но имеет пустое пространство за пределами границ спрайта. Я не уверен, как точно настроить область просмотра рендеркамеры.

Вот как выглядит сцена. (На самом деле это быстрая и упрощенная версия моей текущей сцены, чтобы продемонстрировать мою конкретную проблему) И да, я пытаюсь сделать конкретный снимок экрана во время выполнения. Основная камера находится под произвольным углом, но камера рендеринга может быть отцентрована по рендереру спрайтов. Другими словами, снимок экрана, который я делаю, выглядит так же, как в окне предварительного просмотра камеры в правом нижнем углу на рисунке ниже. Как обрезать (или настроить область просмотра, чтобы исключить) лишнюю часть, выходящую за пределы размера средства визуализации спрайтов?

Скриншот рендер-текстуры (не основной камеры) для точного соответствия спрайту (в 3D-пространстве) - Unity

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

derHugo 29.05.2019 14:18

Не могли бы вы показать на нескольких скриншотах, что происходит сейчас, и что бы вы хотели, чтобы произошло?

HoloLady 29.05.2019 14:26

@derHugo не обязательно, так как я пытаюсь обрезать сам спрайт. я пытаюсь сделать снимок экрана в трехмерном мировом пространстве, хотя и с камеры сверху вниз, сосредоточенной на средстве визуализации спрайтов, а не в двухмерном пространстве.

ina 29.05.2019 14:31

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

ina 29.05.2019 14:38

Есть возможность сделать камеру Orthographic ?

derHugo 29.05.2019 14:43

в идеале нет, так как объекты 3D-игры выглядят по-разному в ортогональном направлении и в перспективе... но если единственное решение для правильной обрезки состоит в том, чтобы сделать это, я думаю, нам придется это сделать?

ina 29.05.2019 14:54

Вы пробовали читать границы.экстенты, бороться с Perspective настоящая головная боль, у меня были эти проблемы несколько месяцев назад и я предпочитал использовать Orthographic вид...

z3nth10n 29.05.2019 16:33

@ina камера всегда будет располагаться по нормали спрайта от его середины?

Ruzihm 29.05.2019 20:06

@ina, ты нашел хорошее решение?

Ruzihm 04.06.2019 23:18

я не смог заставить ваше решение работать ... вы работали с визуализатором спрайтов вместо квадроцикла?

ina 05.06.2019 04:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
1 011
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете рассчитать размер усеченной пирамиды в мировом пространстве:

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;
        }
    }
}

Привет! я думаю, что проблема может быть в том, что квадрат изображения может быть не в правильных единицах масштаба?

ina 05.06.2019 04:17

на самом деле я не уверен, правильно ли я реализую регион в финальном пикселе чтения.....

ina 05.06.2019 04:31
Texture2D image = new Texture2D(camera.targetTexture.width, camera.targetTexture.height);
ina 05.06.2019 04:34

` image.ReadPixels(new Rect(camera.pixelWidth * leftRightCrop * 0,25f, camera.pixelHeight * topBottomCrop*0,25f, leftRightCrop * camera.pixelWidth, topBottomCrop * camera.pixelHeight), 0, 0); `

ina 05.06.2019 04:34

@ina Я отредактировал свой ответ, указав внизу, как его использовать. Я также изменил переменные ___Crop, чтобы они были более полезными, поэтому обязательно обратите внимание на эти изменения.

Ruzihm 05.06.2019 07:40

@ina, у тебя были еще какие-то проблемы с этим ответом?

Ruzihm 10.06.2019 06:19

есть ли опечатка в расчетеcroppedPixelHeight

ina 27.03.2021 07:39

@ina выглядит так. Я думаю, что исправил это

Ruzihm 27.03.2021 14:57

Текстура имеет недопустимую ширину/высоту

ina 27.03.2021 22:46

Мировые единицы @ina, также известные как метры. Также я только что понял, что в строке ReadPixels была еще одна опечатка. Попробуйте, если это работает для вас

Ruzihm 28.03.2021 18:01

как перевести размеры фото в метры

ina 29.03.2021 00:07

вы не знаете. Вы получаете размер spriterenderer/quad в мировых метрах. Размер фото в пикселях значения не имеет.

Ruzihm 29.03.2021 00:16

хммм, а как узнать размер квадрата рендерера спрайтов в мировых метрах (?)

ina 29.03.2021 00:21

@ina попробуй SpriteRenderer.bounds

Ruzihm 29.03.2021 00:56

Круто, наконец-то заработало! gist.github.com/yosun/daa166bdac92cfcaba350ec1bb4e6e06

ina 31.03.2021 09:26

@ina, если это один или два пикселя, это может быть связано с ошибками округления, может быть, увеличить начало прямоугольника на 1-2 пикселя и уменьшить размер вдвое?

Ruzihm 31.03.2021 17:50

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

ina 01.04.2021 07:06

хм, на самом деле я думаю, что это может быть связано с несколькими камерами и OnPostRender - должен ли сценарий быть на конкретной камере или он может быть на Camera.main?

ina 01.04.2021 10:41

@ina можно прикрепить к любому игровому объекту. Я думаю, что понимаю проблему, и чтобы ее исправить, я думаю, вам нужно поменять активную текстуру рендеринга на ту, что на камере. Я отредактировал ответ, чтобы включить это. Если это не сработает, лучше задать отдельный вопрос.

Ruzihm 01.04.2021 15:57

OnPostRender должен быть подключен к камере, но правильно

ina 02.04.2021 00:29

@ina о, да, ты прав. Вероятно, было бы лучше поместить его на камеру, которую вы снимаете для изображения, но на практике (если вы не перемещаете объекты после рендеринга одной камеры и до того, как другая сделает это в том же кадре, что довольно необычно), он, вероятно, выиграл. не имеет значения, и любой игровой объект с активной камерой будет работать так же.

Ruzihm 02.04.2021 00:36

Другие вопросы по теме