using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using com.rfilkov.kinect;
namespace com.rfilkov.components
{
///
/// ForegroundBlendRenderer provides volumetric rendering and lighting of the real environment, filtered by the background-removal manager.
///
public class ForegroundBlendRenderer : MonoBehaviour
{
[Tooltip("Reference to background removal manager. If left to None, it looks up the first available BR-manager in the scene.")]
public BackgroundRemovalManager backgroundRemovalManager = null;
[Tooltip("Depth value in meters, used for invalid depth points.")]
public float invalidDepthValue = 0f;
[Tooltip("Whether to maximize the rendered object on the screen, or not.")]
public bool maximizeOnScreen = true;
[Tooltip("Whether to apply per-pixel lighting on the foreground, or not.")]
public bool applyLighting = false;
[Tooltip("Camera used to scale the mesh, to fill the camera's background. If left empty, it will default to the main camera in the scene.")]
public Camera foregroundCamera;
[Tooltip("Background image (if any) that needs to be overlayed by this blend renderer.")]
public UnityEngine.UI.RawImage backgroundImage;
// references to KM and data
private KinectManager kinectManager = null;
private KinectInterop.SensorData sensorData = null;
private DepthSensorBase sensorInt = null;
private Material matRenderer = null;
// depth image buffer (in depth camera resolution)
private ComputeBuffer depthImageBuffer = null;
// textures
private Texture alphaTex = null;
private Texture colorTex = null;
// lighting
private FragmentLighting lighting = new FragmentLighting();
// saved screen width & height
private int lastScreenW = 0;
private int lastScreenH = 0;
private int lastColorW = 0;
private int lastColorH = 0;
private float lastAnchorPos = 0f;
private Vector3 initialScale = Vector3.one;
// distances
private float distToBackImage = 0f;
private float distToTransform = 0f;
void Start()
{
kinectManager = KinectManager.Instance;
initialScale = transform.localScale;
if (backgroundRemovalManager == null)
{
backgroundRemovalManager = FindObjectOfType();
}
// get distance to back image
if(backgroundImage)
{
Canvas canvas = backgroundImage.canvas;
if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
distToBackImage = canvas.planeDistance;
else
distToBackImage = 0f;
}
// get distance to transform
distToTransform = transform.localPosition.z;
// set renderer material
Renderer meshRenderer = GetComponent();
if (meshRenderer)
{
Shader blendShader = Shader.Find("Kinect/ForegroundBlendShader");
if(blendShader != null)
{
matRenderer = new Material(blendShader);
meshRenderer.material = matRenderer;
}
}
// get sensor data
if (kinectManager && kinectManager.IsInitialized() && backgroundRemovalManager && backgroundRemovalManager.enabled)
{
sensorData = kinectManager.GetSensorData(backgroundRemovalManager.sensorIndex);
sensorInt = sensorData != null ? (DepthSensorBase)sensorData.sensorInterface : null;
}
if (foregroundCamera == null)
{
foregroundCamera = Camera.main;
}
// find scene lights
Light[] sceneLights = GameObject.FindObjectsOfType();
lighting.SetLightsAndBounds(sceneLights, transform.position, new Vector3(20f, 20f, 20f));
//Debug.Log("sceneLights: " + sceneLights.Length);
//for(int i = 0; i < sceneLights.Length; i++)
//{
// Debug.Log(i.ToString() + " - " + sceneLights[i].name + " - " + sceneLights[i].type);
//}
}
void OnDestroy()
{
if (sensorData != null && sensorData.colorDepthBuffer != null)
{
sensorData.colorDepthBuffer.Release();
sensorData.colorDepthBuffer = null;
}
if (depthImageBuffer != null)
{
//depthImageCopy = null;
depthImageBuffer.Release();
depthImageBuffer = null;
}
// release lighting resources
lighting.ReleaseResources();
}
void Update()
{
if (matRenderer == null || sensorData == null || sensorInt == null)
return;
if(alphaTex == null || alphaTex.width != sensorData.colorImageWidth || alphaTex.height != sensorData.colorImageHeight)
{
// alpha texture
alphaTex = backgroundRemovalManager.GetAlphaTex();
if(alphaTex != null)
{
matRenderer.SetTexture("_AlphaTex", alphaTex);
}
}
if(colorTex == null || colorTex.width != sensorData.colorImageWidth || colorTex.height != sensorData.colorImageHeight)
{
// color texture
colorTex = !backgroundRemovalManager.computeAlphaMaskOnly ? backgroundRemovalManager.GetForegroundTex() : alphaTex; // sensorInt.pointCloudColorTexture
if (colorTex != null)
{
matRenderer.SetInt("_TexResX", colorTex.width);
matRenderer.SetInt("_TexResY", colorTex.height);
matRenderer.SetTexture("_ColorTex", colorTex);
}
}
if (colorTex == null || alphaTex == null /**|| foregroundCamera == null*/)
return;
if (sensorInt.pointCloudResolution == DepthSensorBase.PointCloudResolution.DepthCameraResolution)
{
int depthBufferLength = sensorData.depthImageWidth * sensorData.depthImageHeight / 2;
if (depthImageBuffer == null || depthImageBuffer.count != depthBufferLength)
{
//int depthImageLength = sensorData.depthImageWidth * sensorData.depthImageHeight;
//depthImageCopy = new ushort[depthImageLength];
depthImageBuffer = KinectInterop.CreateComputeBuffer(depthImageBuffer, depthBufferLength, sizeof(uint));
matRenderer.SetBuffer("_DepthMap", depthImageBuffer);
//Debug.Log("Created depthImageBuffer with len: " + depthBufferLength);
}
if (depthImageBuffer != null && sensorData.depthImage != null)
{
//KinectInterop.CopyBytes(sensorData.depthImage, sizeof(ushort), depthImageCopy, sizeof(ushort));
KinectInterop.SetComputeBufferData(depthImageBuffer, sensorData.depthImage, depthBufferLength, sizeof(uint));
}
//Debug.Log("ForegroundBlendRenderer DepthFrameTime: " + lastDepthFrameTime);
}
else
{
int bufferLength = sensorData.colorImageWidth * sensorData.colorImageHeight / 2;
if (sensorData.colorDepthBuffer == null || sensorData.colorDepthBuffer.count != bufferLength)
{
sensorData.colorDepthBuffer = new ComputeBuffer(bufferLength, sizeof(uint));
matRenderer.SetBuffer("_DepthMap", sensorData.colorDepthBuffer);
//Debug.Log("Created colorDepthBuffer with len: " + bufferLength);
}
//Debug.Log("ForegroundBlendRenderer ColorDepthBufferTime: " + sensorData.lastColorDepthBufferTime);
}
matRenderer.SetFloat("_DepthDistance", 0f);
matRenderer.SetFloat("_InvDepthVal", invalidDepthValue);
int curScreenW = foregroundCamera ? foregroundCamera.pixelWidth : Screen.width;
int curScreenH = foregroundCamera ? foregroundCamera.pixelHeight : Screen.height;
if (lastScreenW != curScreenW || lastScreenH != curScreenH || lastColorW != sensorData.colorImageWidth || lastColorH != sensorData.colorImageHeight)
{
ScaleRendererTransform(curScreenW, curScreenH);
}
Vector2 anchorPos = backgroundImage ? backgroundImage.rectTransform.anchoredPosition : Vector2.zero;
float curAnchorPos = anchorPos.x + anchorPos.y; // Mathf.Abs(anchorPos.x) + Mathf.Abs(anchorPos.y);
if (Mathf.Abs(curAnchorPos - lastAnchorPos) >= 20f)
{
//Debug.Log("anchorPos: " + anchorPos + ", curAnchorPos: " + curAnchorPos + ", lastAnchorPos: " + lastAnchorPos + ", diff: " + Mathf.Abs(curAnchorPos - lastAnchorPos));
CenterRendererTransform(anchorPos, curAnchorPos);
}
// update lighting parameters
lighting.UpdateLighting(matRenderer, applyLighting);
}
// scales the renderer's transform properly
private void ScaleRendererTransform(int curScreenW, int curScreenH)
{
lastScreenW = curScreenW;
lastScreenH = curScreenH;
lastColorW = sensorData.colorImageWidth;
lastColorH = sensorData.colorImageHeight;
Vector3 localScale = Vector3.one; // transform.localScale;
if (maximizeOnScreen && foregroundCamera)
{
float objectZ = distToTransform; // transform.localPosition.z; // the transform should be a child of the camera
float screenW = foregroundCamera.pixelWidth;
float screenH = foregroundCamera.pixelHeight;
if (backgroundImage)
{
PortraitBackground portraitBack = backgroundImage.gameObject.GetComponent();
if (portraitBack != null)
{
Rect backRect = portraitBack.GetBackgroundRect();
screenW = backRect.width;
screenH = backRect.height;
}
}
Vector3 vLeft = foregroundCamera.ScreenToWorldPoint(new Vector3(0f, screenH / 2f, objectZ));
Vector3 vRight = foregroundCamera.ScreenToWorldPoint(new Vector3(screenW, screenH / 2f, objectZ));
float distLeftRight = (vRight - vLeft).magnitude;
Vector3 vBottom = foregroundCamera.ScreenToWorldPoint(new Vector3(screenW / 2f, 0f, objectZ));
Vector3 vTop = foregroundCamera.ScreenToWorldPoint(new Vector3(screenW / 2f, screenH, objectZ));
float distBottomTop = (vTop - vBottom).magnitude;
localScale.x = distLeftRight / initialScale.x;
localScale.y = distBottomTop / initialScale.y;
//Debug.Log("ForegroundRenderer scale: " + localScale + ", screenW: " + screenW + ", screenH: " + screenH + ", objZ: " + objectZ +
// "\nleft: " + vLeft + ", right: " + vRight + ", bottom: " + vBottom + ", vTop: " + vTop +
// "\ndH: " + distLeftRight + ", dV: " + distBottomTop + ", initialScale: " + initialScale);
}
// scale according to color-tex resolution
//localScale.y = localScale.x * colorTex.height / colorTex.width;
// apply color image scale
Vector3 colorImageScale = kinectManager.GetColorImageScale(backgroundRemovalManager.sensorIndex);
if (colorImageScale.x < 0f)
localScale.x = -localScale.x;
if (colorImageScale.y < 0f)
localScale.y = -localScale.y;
transform.localScale = localScale;
}
// centers the renderer's transform, according to the background image
private void CenterRendererTransform(Vector2 anchorPos, float curAnchorPos)
{
lastAnchorPos = curAnchorPos;
if (foregroundCamera && distToBackImage > 0f)
{
float objectZ = distToTransform; // transform.localPosition.z; // the transform should be a child of the camera
float screenW = sensorData.colorImageWidth; // foregroundCamera.pixelWidth;
float screenH = sensorData.colorImageHeight; // foregroundCamera.pixelHeight;
Vector2 screenCenter = new Vector2(screenW / 2f, screenH / 2f);
Vector2 anchorScaled = new Vector2(anchorPos.x * distToTransform / distToBackImage, anchorPos.y * distToTransform / distToBackImage);
Vector3 vCenter = foregroundCamera.ScreenToWorldPoint(new Vector3(screenCenter.x + anchorScaled.x, screenCenter.y + anchorScaled.y, objectZ));
transform.position = vCenter;
//Vector3 vLocalPos = transform.localPosition;
//string sLocalPos = string.Format("({0:F3}, {1:F3}, {2:F3})", vLocalPos.x, vLocalPos.y, vLocalPos.z);
//Debug.Log("ForegroundRenderer anchor: " + anchorPos + ", screenW: " + screenW + ", screenH: " + screenH + ", objZ: " + objectZ + ", localPos: " + sLocalPos);
}
}
}
}