首页 > 解决方案 > 来自渲染纹理(非主相机)的屏幕截图以完全适合精灵(在 3D 空间中) - Unity

问题描述

您如何调整或以其他方式设置屏幕截图以具有 3D 空间中特定精灵的确切尺寸(因此,带有 SpriteRenderer 的 Gameobject)。

渲染相机直接设置在精灵上方,但在精灵边界之外有一些空白区域。我不确定如何精确调整渲染相机的视口。

这是场景的样子。(实际上这是我当前场景的快速简化版本,以展示我的具体问题)是的,我正在尝试在运行时截取特定的屏幕截图。主相机处于任意角度,但渲染相机可以以精灵渲染器为中心。换句话说,我正在拍摄的屏幕截图看起来像下图中右下角的“相机预览”中的屏幕截图。如何裁剪(或调整视口以排除)超出精灵渲染器大小的额外部分?

在此处输入图像描述

标签: c#unity3d

解决方案


您可以计算世界空间中截锥体的大小:

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

推荐阅读