/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal.Record
{
using UnityEngine;
/// A frame blender.
public class FrameBlender : BlenderBase
{
/// Target camera.
protected Camera m_TargetCamera;
/// The encoder.
protected IEncoder m_Encoder;
/// The blend material.
private Material m_BlendMaterial;
/// The blend mode.
protected BlendMode m_BlendMode;
/// The RGB source.
protected RenderTexture m_RGBSource;
/// The temporary combine tex.
protected Texture2D m_TempCombineTex;
/// The blend texture.
private RenderTexture m_BlendTexture;
/// Gets or sets the blend texture.
/// The blend texture.
public override RenderTexture BlendTexture
{
get
{
return m_BlendTexture;
}
protected set
{
m_BlendTexture = value;
}
}
/// Gets the RGB texture.
/// The RGB texture.
public RenderTexture RGBTexture
{
get
{
return m_RGBSource;
}
}
/// Gets the virtual texture.
/// The virtual texture.
public RenderTexture VirtualTexture
{
get
{
return m_TargetCamera.targetTexture;
}
}
/// Initializes this object.
/// The camera.
/// The encoder.
/// The parameter.
public override void Init(Camera camera, IEncoder encoder, CameraParameters param)
{
Width = param.cameraResolutionWidth;
Height = param.cameraResolutionHeight;
m_BlendMode = param.blendMode;
m_TargetCamera = camera;
m_Encoder = encoder;
// An extra rendering is required when BlendMode is RGBOnly or WidescreenBlend.
switch (m_BlendMode)
{
case BlendMode.RGBOnly:
BlendTexture = UnityExtendedUtility.CreateRenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32, false);
break;
case BlendMode.VirtualOnly:
BlendTexture = UnityExtendedUtility.CreateRenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32, false);
break;
case BlendMode.Blend:
BlendTexture = UnityExtendedUtility.CreateRenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32, false);
break;
case BlendMode.WidescreenBlend:
BlendTexture = UnityExtendedUtility.CreateRenderTexture(2 * Width, Height, 24, RenderTextureFormat.ARGB32, false);
m_RGBSource = UnityExtendedUtility.CreateRenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32, false);
m_TempCombineTex = new Texture2D(2 * Width, Height, TextureFormat.ARGB32, false);
break;
default:
break;
}
m_TargetCamera.enabled = false;
m_TargetCamera.targetTexture = UnityExtendedUtility.CreateRenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32);
}
/// Executes the 'frame' action.
/// The frame.
public override void OnFrame(UniversalTextureFrame frame)
{
Texture2D frametex = frame.textures[0] as Texture2D;
if (m_BlendMode != BlendMode.RGBOnly)
{
m_TargetCamera.Render();
}
if (m_BlendMaterial == null)
{
CreatBlendMaterial(m_BlendMode, frame.textureType);
}
bool isyuv = frame.textureType == TextureType.YUV;
switch (m_BlendMode)
{
case BlendMode.RGBOnly:
const string MainTextureStr = "_MainTex";
if (isyuv)
{
const string UTextureStr = "_UTex";
const string VTextureStr = "_VTex";
m_BlendMaterial.SetTexture(MainTextureStr, frame.textures[0]);
m_BlendMaterial.SetTexture(UTextureStr, frame.textures[1]);
m_BlendMaterial.SetTexture(VTextureStr, frame.textures[2]);
}
else
{
m_BlendMaterial.SetTexture(MainTextureStr, frame.textures[0]);
}
Graphics.Blit(frame.textures[0], BlendTexture, m_BlendMaterial);
break;
case BlendMode.VirtualOnly:
m_BlendMaterial.SetTexture("_MainTex", m_TargetCamera.targetTexture);
Graphics.Blit(m_TargetCamera.targetTexture, BlendTexture, m_BlendMaterial);
break;
case BlendMode.Blend:
m_BlendMaterial.SetTexture("_MainTex", m_TargetCamera.targetTexture);
if (isyuv)
{
m_BlendMaterial.SetTexture("_YTex", frame.textures[0]);
m_BlendMaterial.SetTexture("_UTex", frame.textures[1]);
m_BlendMaterial.SetTexture("_VTex", frame.textures[2]);
}
else
{
m_BlendMaterial.SetTexture("_BcakGroundTex", frame.textures[0]);
}
Graphics.Blit(m_TargetCamera.targetTexture, BlendTexture, m_BlendMaterial);
break;
case BlendMode.WidescreenBlend:
if (isyuv)
{
throw new System.Exception("Not support yuv texture for this mode...");
}
CombineTexture(frametex, m_TargetCamera.targetTexture, m_TempCombineTex, BlendTexture);
break;
default:
break;
}
// Commit frame
m_Encoder.Commit(BlendTexture, frame.timeStamp);
FrameCount++;
}
private void CreatBlendMaterial(BlendMode mode, TextureType texturetype)
{
string shader_name;
if (mode == BlendMode.Blend)
{
shader_name = "Record/Shaders/AlphaBlend{0}";
shader_name = string.Format(shader_name, texturetype == TextureType.RGB ? "" : "YUV");
}
else if (mode == BlendMode.VirtualOnly)
{
shader_name = "Record/Shaders/NormalTexture";
}
else
{
shader_name = "Record/Shaders/NormalBlend{0}";
shader_name = string.Format(shader_name, texturetype == TextureType.RGB ? "" : "YUV");
}
m_BlendMaterial = new Material(Resources.Load(shader_name));
}
/// Combine texture.
/// The bgsource.
/// The foresource.
/// The tempdest.
/// Destination for the.
private void CombineTexture(Texture2D bgsource, RenderTexture foresource, Texture2D tempdest, RenderTexture dest)
{
const string MainTextureStr = "_MainTex";
m_BlendMaterial.SetTexture(MainTextureStr, m_RGBSource);
Graphics.Blit(bgsource, m_RGBSource, m_BlendMaterial);
RenderTexture prev = RenderTexture.active;
RenderTexture.active = m_RGBSource;
tempdest.ReadPixels(new Rect(0, 0, m_RGBSource.width, m_RGBSource.height), 0, 0);
RenderTexture.active = foresource;
tempdest.ReadPixels(new Rect(0, 0, foresource.width, foresource.height), foresource.width, 0);
tempdest.Apply();
RenderTexture.active = prev;
Graphics.Blit(tempdest, dest);
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged
/// resources.
public override void Dispose()
{
m_BlendTexture?.Release();
m_RGBSource?.Release();
GameObject.Destroy(m_TempCombineTex);
m_BlendTexture = null;
m_RGBSource = null;
m_TempCombineTex = null;
}
}
}