统一捕获一系列相机渲染

时间:2019-06-14 02:00:10

标签: c# unity3d

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

1 个答案:

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

    }
}