c# - 来自渲染纹理(非主相机)的屏幕截图以完全适合精灵(在 3D 空间中) - Unity
问题描述
您如何调整或以其他方式设置屏幕截图以具有 3D 空间中特定精灵的确切尺寸(因此,带有 SpriteRenderer 的 Gameobject)。
渲染相机直接设置在精灵上方,但在精灵边界之外有一些空白区域。我不确定如何精确调整渲染相机的视口。
这是场景的样子。(实际上这是我当前场景的快速简化版本,以展示我的具体问题)是的,我正在尝试在运行时截取特定的屏幕截图。主相机处于任意角度,但渲染相机可以以精灵渲染器为中心。换句话说,我正在拍摄的屏幕截图看起来像下图中右下角的“相机预览”中的屏幕截图。如何裁剪(或调整视口以排除)超出精灵渲染器大小的额外部分?
解决方案
您可以计算世界空间中截锥体的大小:
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;
}
}
}
推荐阅读
- xdebug - 在 /usr/local/bin/autom4te 第 262 行调用的未定义子例程 &main::open_quote
- swift - Swift .byPreparingThumbnail 异步 API。性能问题
- abp - 如何使用基本主题的 eLayoutType.application 来利用整个窗口宽度?
- sql - 尝试在一个 SQL 语句中使用多个 CTE 时出现问题
- linux - 引导扇区的最终签名是什么?是 0xaa55 还是 0x55aa?
- filebeat - 如何过滤filebeat yml文件中的json数据
- asp.net-mvc - 我无法在 ASP.NET 应用程序上进行客户端验证
- javascript - 使用反应切换钩子在两个组件/按钮之间切换{显示一个组件并隐藏另一个}
- google-apps-script - Google 表格脚本 - 在特定表格上运行的更简洁的代码
- c# - `#nullable disable` 时使用 NotNullWhenAttribute