在Unity中,我有以下方法可以拍摄相机并创建透明图像(效果很好)。 RenderTexture rt
是在此方法之外构建和创建的。
Texture2D reallyTakeShot() {
camera.backgroundColor = Color.white;
Texture2D texWhite = new Texture2D(width, height, TextureFormat.RGB24, mipmap: false);
DoCameraRender(camera, shader);
RenderTexture.active = rt;
texWhite.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
texWhite.Apply();
camera.backgroundColor = Color.black;
DoCameraRender(camera, shader);
Texture2D texBlack = new Texture2D(width, height, TextureFormat.RGB24, mipmap: false);
texBlack.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
texBlack.Apply();
Texture2D transparentTexture = new Texture2D(width, height, TextureFormat.ARGB32, mipmap: false);
for (int y = 0; y < transparentTexture.height; ++y)
{
for (int x = 0; x < transparentTexture.width; ++x)
{
float alpha = 1.0f - (texWhite.GetPixel(x, y).r - texBlack.GetPixel(x, y).r);
Color color;
if ((int)(alpha * 100) == 0)
{
color = Color.clear;
}
else
{
color = texBlack.GetPixel(x, y) / alpha;
color.a = alpha;
}
transparentTexture.SetPixel(x, y, color);
}
}
return transparentTexture;
我想要做的是拍摄一系列照片,但并不一定要100%平滑,但是我运气并不好。在30个捕获中,大多数看起来相同。
我最近做的一个循环是调用
具有以下方法(输出0ms进行捕获,所以我猜它很快)
private IEnumerator TakeShotNoWrite()
{
shooting = CaptureStates.Capturing;
Stopwatch sw = new Stopwatch();
bool useJpeg = ModPrefs.GetBool("HomeShot", "use_jpeg");
int outputWidth = ModPrefs.GetInt("HomeShot", "output_width");
Texture2D tex = TakeShotToTexture2(!useJpeg);
caps.Add(tex);
shooting = CaptureStates.NormalCapture;
Console.WriteLine("capture took " + sw.Elapsed.TotalMilliseconds + "ms");
yield return new WaitForFixedUpdate();
// tried these too
// yield return 0;
// yield return WaitForNextFrame();
}
我在FixedUpdate()
上触发了相机(这是我唯一一次可以使对象看起来正确的LateUpdate()
无效)
private void FixedUpdate()
{
if (shooting == CaptureStates.Capturing)
{
return;
}
if (shooting != CaptureStates.NotCapturing)
{
// Extra StopWatch logic so I can increase the minimum time
// before next screen shot I set it to 30ms.
StartCoroutine(TakeShotNoWrite()); // the render to texture code is above.
// when stopwatch reaches 15 seconds start writing the files
}
}
答案 0 :(得分:0)
这是我的实现。以1080p的分辨率保存10秒(约20fps)的200张照片。但这会在4K时减少10秒的60帧。我认为这是双重渲染,但这暂时满足了我的需求。
public class BurstShooter : MonoBehaviour
{
private Camera camera;
private Texture2D[] blacks;
private Texture2D[] whites;
/**
* Number of captures
*/
private int caps;
private int width;
private int height;
private int burstSeconds;
private int burstInterval;
private Stopwatch burstWatch = new Stopwatch();
private Color backgroundColor;
private RenderTexture rt;
private double lastBurstMillis;
private void Start()
{
}
public void Shoot()
{
if (!burstWatch.IsRunning)
{
StartCoroutine(TakeBurstShotCoroutine());
}
}
private IEnumerator<YieldInstruction> TakeBurstShotCoroutine()
{
StartTakeBurstShot();
while (burstWatch.Elapsed.TotalSeconds < burstSeconds && caps < blacks.Length)
{
yield return new WaitForEndOfFrame();
if (burstWatch.Elapsed.TotalMilliseconds - lastBurstMillis > burstInterval)
{
lastBurstMillis = burstWatch.Elapsed.TotalMilliseconds;
TakeBurstShot();
}
}
burstWatch.Stop();
RenderTexture.ReleaseTemporary(rt);
yield return new WaitForEndOfFrame();
// Flush Caps takes the Texture2Ds and
// converts them to PNG. Not going to
// bother with this as it is outside
//the scope of the question.
FlushCaps();
}
private void StartTakeBurstShot()
{
// these can be larger than the screen
width = 1920;
height = 1080;
rt = getRenderTexture();
SelectCamera();
backgroundColor = camera.backgroundColor;
burstInterval = 15;
burstSeconds = 15;
// assume 60 frames per second max
blacks = new Texture2D[60 * burstSeconds];
whites = new Texture2D[60 * burstSeconds];
caps = 0;
burstWatch.Reset();
burstWatch.Start();
lastBurstMillis = -burstInterval;
}
private void TakeBurstShot()
{
Stopwatch sw = new Stopwatch();
sw.Reset();
sw.Start();
try
{
camera.targetTexture = rt;
RenderTexture.active = rt;
Texture2D texWhite = new Texture2D(width, height, TextureFormat.RGB24, mipmap: false);
texWhite.filterMode = FilterMode.Point;
texWhite.wrapMode = TextureWrapMode.Clamp;
Texture2D texBlack = new Texture2D(width, height, TextureFormat.RGB24, mipmap: false);
texBlack.filterMode = FilterMode.Point;
texBlack.wrapMode = TextureWrapMode.Clamp;
camera.backgroundColor = Color.white;
camera.Render();
texWhite.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
texWhite.Apply();
camera.backgroundColor = Color.black;
camera.Render();
texBlack.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
texBlack.Apply();
blacks[caps] = texBlack;
whites[caps] = texWhite;
++caps;
}
finally
{
camera.backgroundColor = backgroundColor;
RenderTexture.active = null;
camera.targetTexture = null;
}
}
}