1475 lines
54 KiB
C#
1475 lines
54 KiB
C#
//======= Copyright (c) Stereolabs Corporation, All rights reserved. ===============
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
|
|
/// <summary>
|
|
/// Responsible for actually mixing the real and virtual images, and displaying them in a
|
|
/// Frame object within the camera rig.
|
|
/// First, it displays the image of the ZED into a quad.
|
|
/// Then, it inserts the depth and normals inside the pipeline
|
|
/// Third, it computes the data for the light and send it to the shaders.
|
|
/// Finally, it post-processes the image, if post-processing is enabled.
|
|
/// </summary>
|
|
[RequireComponent(typeof(Camera))]
|
|
public class ZEDRenderingPlane : MonoBehaviour
|
|
{
|
|
/// <summary>
|
|
/// The rendering mode accepted.
|
|
/// </summary>
|
|
enum ZED_RENDERING_MODE
|
|
{
|
|
FORWARD,
|
|
DEFERRED,
|
|
LAST
|
|
};
|
|
|
|
/// <summary>
|
|
/// Which side of the camera (left/right) and whether or not this can be overridden by the camera's stereoTargetEye.
|
|
/// </summary>
|
|
public enum ZED_CAMERA_SIDE
|
|
{
|
|
/// <summary>
|
|
/// Feed from the ZED's left camera. Can be overridden by the camera's stereoTargetEye value.
|
|
/// </summary>
|
|
LEFT,
|
|
/// <summary>
|
|
/// Feed from the ZED's right camera. Can be overridden by the camera's stereoTargetEye value.
|
|
/// </summary>
|
|
RIGHT,
|
|
/// <summary>
|
|
/// Feed from the ZED's left camera. Won't be overridden.
|
|
/// </summary>
|
|
LEFT_FORCE,
|
|
/// <summary>
|
|
/// Feed from the ZED's right camera. Won't be overridden.
|
|
/// </summary>
|
|
RIGHT_FORCE
|
|
}
|
|
|
|
/// <summary>
|
|
/// The GameGbject that displays the final textures.
|
|
/// In the ZED_Rig_Mono and ZED_Rig_Stereo prefabs, this is the Frame object that's a child of each camera.
|
|
/// </summary>
|
|
[Tooltip("The GameGbject that displays the final textures. " +
|
|
"In the ZED_Rig_Mono and ZED_Rig_Stereo prefabs, this is the Frame object that's a child of each camera.")]
|
|
public GameObject canvas;
|
|
|
|
/// <summary>
|
|
/// Which camera on the ZED the image/depth/etc. comes from.
|
|
/// If set to LEFT or RIGHT, this may be overridden by the camera's stereoTargetEye.
|
|
/// If set to LEFT_FORCE or RIGHT_FORCE, it will not be changed.
|
|
/// </summary>
|
|
[Tooltip("Which camera on the ZED the image/depth/etc. comes from.\r\n" +
|
|
"If set to LEFT or RIGHT, this may be overridden by the camera's stereoTargetEye.\r\n" +
|
|
"If set to LEFT_FORCE or RIGHT_FORCE, it will not be changed.")]
|
|
public ZED_CAMERA_SIDE viewSide = ZED_CAMERA_SIDE.LEFT;
|
|
|
|
/// <summary>
|
|
/// The main material, set to the one on the canvas's MeshRenderer. Used to set the color and depth.
|
|
/// </summary>
|
|
private Material matRGB;
|
|
|
|
/// <summary>
|
|
/// Aspect ratio of the textures. All the textures displayed should be in 16:9.
|
|
/// </summary>
|
|
private float aspect = 16.0f / 9.0f;
|
|
|
|
/// <summary>
|
|
/// The Camera component representing an 'eye' of the ZED. Must be on the same GameObject as this component.
|
|
/// </summary>
|
|
private Camera cam;
|
|
|
|
/// <summary>
|
|
/// zedCamera controlled by ZEDManager (one manager controls one camera)
|
|
/// </summary>
|
|
private sl.ZEDCamera zedCamera = null;
|
|
|
|
/// <summary>
|
|
/// ZED Manager that controls the zed Camera
|
|
/// </summary>
|
|
private ZEDManager zedManager = null;
|
|
|
|
|
|
/// <summary>
|
|
/// Texture of the real world generated from the ZED. It may be the from the left or right 'eye.'
|
|
/// Once created, the ZED SDK automatically updates it with each frame/image the ZED captures.
|
|
/// </summary>
|
|
private Texture2D textureEye;
|
|
public Texture2D TextureEye { get { return textureEye; } }
|
|
|
|
/// <summary>
|
|
/// Depth generated by the ZEDCamera.
|
|
/// Once created, the ZED SDK automatically updates it whenever the ZED captures new frames/images.
|
|
/// </summary>
|
|
Texture2D depth;
|
|
|
|
/// <summary>
|
|
/// Normals generated by the ZEDCamera.
|
|
/// Once created, the ZED SDK automatically updates it whenever the ZED captures new frames/images.
|
|
/// </summary>
|
|
Texture2D normals;
|
|
|
|
/// <summary>
|
|
/// CommandBuffer to integrate the depth into Unity's forward or deferred pipeline.
|
|
/// </summary>
|
|
CommandBuffer[] buffer = new CommandBuffer[(int)ZED_RENDERING_MODE.LAST];
|
|
|
|
/// <summary>
|
|
/// CommandBuffer to create a mask for the virtual objects in forward and deferred rendering.
|
|
/// </summary>
|
|
CommandBuffer[] postProcessBuffer = new CommandBuffer[(int)ZED_RENDERING_MODE.LAST];
|
|
|
|
/// <summary>
|
|
/// The material used to integrate the depth in forward mode after the depth texture is created. Mainly used to get the shadows. Not needed for lighting otherwise.
|
|
/// </summary>
|
|
public Material forwardMat { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The material used to integrate the depth in deferred mode. Always used in deferred regardless of lighting/shadows.
|
|
/// </summary>
|
|
public Material deferredMat { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The actual rendering path used.
|
|
/// To change this, change the settings in Project Settings -> Graphics within the Unity editor.
|
|
/// </summary>
|
|
private RenderingPath actualRenderingPath = RenderingPath.VertexLit;
|
|
public RenderingPath ActualRenderingPath
|
|
{
|
|
get { return actualRenderingPath; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The MeshFilter component of the canvas object. Used to draw the depth buffer.
|
|
/// </summary>
|
|
MeshFilter meshCanvas;
|
|
|
|
/// <summary>
|
|
/// A lower resolution of the depth and normals textures from the ZED.
|
|
/// </summary>
|
|
private sl.Resolution resolution = new sl.Resolution(384, 192);
|
|
|
|
/***LIGHTS definitions***/
|
|
/// <summary>
|
|
/// Point light structure for virtual lights on the real world.
|
|
/// Gets sent to the shader via a compute buffer.
|
|
/// </summary>
|
|
[SerializeField]
|
|
public struct PointLight
|
|
{
|
|
/// <summary>
|
|
/// The color, times the intensity.
|
|
/// </summary>
|
|
public Vector4 color;
|
|
/// <summary>
|
|
/// The range of the light.
|
|
/// </summary>
|
|
public float range;
|
|
/// <summary>
|
|
/// The position of the light.
|
|
/// </summary>
|
|
public Vector3 position;
|
|
}
|
|
/// <summary>
|
|
/// Maximum number of point lights accepted.
|
|
/// </summary>
|
|
const int NUMBER_POINT_LIGHT_MAX = 8;
|
|
|
|
/// <summary>
|
|
/// Holds a slot for all point lights that should be cast on the real world.
|
|
/// </summary>
|
|
[SerializeField]
|
|
public PointLight[] pointLights = new PointLight[NUMBER_POINT_LIGHT_MAX];
|
|
/// <summary>
|
|
/// The size, or 'stride', of each PointLight in bytes. Needed to construct computeBufferPointLight.
|
|
/// </summary>
|
|
const int SIZE_POINT_LIGHT_BYTES = 32;
|
|
|
|
/// <summary>
|
|
/// Used to pass the pointLights array into matRGB's shader as a buffer.
|
|
/// </summary>
|
|
ComputeBuffer computeBufferPointLight;
|
|
|
|
/// <summary>
|
|
/// Structure of the spotlight send to the shader
|
|
/// </summary>
|
|
[SerializeField]
|
|
public struct SpotLight
|
|
{
|
|
/// <summary>
|
|
/// The color, times the intensity.
|
|
/// </summary>
|
|
public Vector4 color;
|
|
/// <summary>
|
|
/// The position of the light.
|
|
/// </summary>
|
|
public Vector3 position;
|
|
/// <summary>
|
|
/// The light's normalized direction and angle.
|
|
/// </summary>
|
|
public Vector4 direction;
|
|
/// <summary>
|
|
/// The parameters for the light's falloff.
|
|
/// </summary>
|
|
public Vector4 parameters;
|
|
}
|
|
/// <summary>
|
|
/// Maximum number of spotlights accepted.
|
|
/// </summary>
|
|
const int NUMBER_SPOT_LIGHT_MAX = 8;
|
|
|
|
/// <summary>
|
|
/// Holds a slot for all spotlights that should be cast on the real world.
|
|
/// </summary>
|
|
[SerializeField]
|
|
public SpotLight[] spotLights = new SpotLight[NUMBER_SPOT_LIGHT_MAX];
|
|
|
|
/// <summary>
|
|
/// The size, or 'stride', of each SpotLight in bytes. Needed to construct computeBufferSpotLight.
|
|
/// </summary>
|
|
const int SIZE_SPOT_LIGHT_BYTES = 60;
|
|
|
|
/// <summary>
|
|
/// Maximum number of total lights rendered (point and spot combined).
|
|
/// </summary>
|
|
const int NUMBER_LIGHTS_MAX = NUMBER_POINT_LIGHT_MAX / 2 + NUMBER_SPOT_LIGHT_MAX / 2;
|
|
|
|
/// <summary>
|
|
/// Data from a directional light. [0] is its direction and [1] is its color.
|
|
/// Only one directional light is allowed at once.
|
|
/// </summary>
|
|
private Vector4[] directionalLightData = new Vector4[2];
|
|
|
|
/// <summary>
|
|
/// Used to pass the spotLights array into matRGB's shader as a buffer.
|
|
/// </summary>
|
|
ComputeBuffer computeBufferSpotLight;
|
|
|
|
//Forward ID shader caches.
|
|
/// <summary>
|
|
/// Property ID of the number of point lights in the ZED_Lighting shader include file.
|
|
/// </summary>
|
|
private int numberPointLightsID;
|
|
|
|
/// <summary>
|
|
/// Property ID of the number of spotlights in the ZED_Lighting shader include file.
|
|
/// </summary>
|
|
private int numberSpotLightsID;
|
|
|
|
/// <summary>
|
|
/// Cached property id for _IsTextured. use isTexturedID property instead.
|
|
/// </summary>
|
|
private int? _istexturedid;
|
|
/// <summary>
|
|
/// Property id for _IsTextured, which is whether the rendered image has a texture overlay.
|
|
/// </summary>
|
|
private int isTexturedID
|
|
{
|
|
get
|
|
{
|
|
if (_istexturedid == null) _istexturedid = Shader.PropertyToID("_IsTextured");
|
|
return (int)_istexturedid;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cached property id for _Mask. use maskPropID property instead.
|
|
/// </summary>
|
|
private int? _maskpropid;
|
|
/// <summary>
|
|
/// Property id for _Mask, which is the RenderTexture property for an overlay texture.
|
|
/// </summary>
|
|
private int maskPropID
|
|
{
|
|
get
|
|
{
|
|
if (_maskpropid == null) _maskpropid = Shader.PropertyToID("_Mask");
|
|
return (int)_maskpropid;
|
|
}
|
|
}
|
|
|
|
/*** Post-process definitions***/
|
|
|
|
/// <summary>
|
|
/// The mask used for post-processing. Filled at runtime and updated each frame.
|
|
/// </summary>
|
|
private RenderTexture mask;
|
|
|
|
/// <summary>
|
|
/// The post process material, used to add noise and change the color.
|
|
/// </summary>
|
|
private Material postprocessMaterial;
|
|
|
|
/// <summary>
|
|
/// Activate/deactivate post-processing. If false, the mask will not be generated.
|
|
/// Set by ZEDManager.setRenderingSettings() based on a checkbox in ZEDManager's custom editor.
|
|
/// </summary>
|
|
private bool ARpostProcessing = true;
|
|
|
|
/// <summary>
|
|
/// Used to blur the mask.
|
|
/// </summary>
|
|
private Material blurMaterial;
|
|
|
|
/// <summary>
|
|
/// Used to load a source image's alpha channel into all channels of a destination image.
|
|
/// Used during post-processing.
|
|
/// </summary>
|
|
private Material blitMaterial;
|
|
|
|
/// <summary>
|
|
/// Used to convert the stencil buffer of a rendertexture into a regular texture.
|
|
/// </summary>
|
|
private Material matStencilToMask;
|
|
|
|
/// <summary>
|
|
/// Used to compose the virtual mask from different textures.
|
|
/// </summary>
|
|
private Material matComposeMask;
|
|
|
|
/// <summary>
|
|
/// Used to blend the textures from ZEDMeshRenderer, when present.
|
|
/// This adds the wireframe effect seen from 3D scanning or plane detection.
|
|
/// </summary>
|
|
private Material blender;
|
|
|
|
/// <summary>
|
|
/// What kind of image the final result will display. Usually set to View.
|
|
/// Set this to VIEW_DEPTH or VIEW_NORMAL to see the live depth or normal maps.
|
|
/// </summary>
|
|
public sl.VIEW_MODE viewMode = sl.VIEW_MODE.VIEW_IMAGE;
|
|
|
|
/// <summary>
|
|
/// Which side of the camera we render. Left = 0, Right ==1.
|
|
/// </summary>
|
|
private int side
|
|
{
|
|
get
|
|
{
|
|
if (viewSide == ZED_CAMERA_SIDE.LEFT || viewSide == ZED_CAMERA_SIDE.LEFT_FORCE) return 0;
|
|
else return 1;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Default near plane value. Overrides camera's settings on start but will update if camera values change at runtime.
|
|
/// </summary>
|
|
private float nearplane = 0.1f;
|
|
/// <summary>
|
|
/// Default far plane value. Overrides camera's settings on start but will update if camera values change at runtime.
|
|
/// </summary>
|
|
private float farplane = 500.0f;
|
|
|
|
/// <summary>
|
|
/// The target RenderTexture we'll render to if in AR mode.
|
|
/// </summary>
|
|
[HideInInspector]
|
|
private RenderTexture renderTextureTarget;
|
|
public RenderTexture target
|
|
{
|
|
get { return renderTextureTarget; }
|
|
}
|
|
|
|
void Awake()
|
|
{
|
|
//Get the current camera and set the aspect ratio.
|
|
zedManager = gameObject.transform.parent.GetComponent<ZEDManager> ();
|
|
cam = GetComponent<Camera>();
|
|
cam.aspect = aspect;
|
|
cam.renderingPath = RenderingPath.UsePlayerSettings; //Assigns the camera's rendering path to be consistent with the project's settings.
|
|
|
|
//Make the canvas allow rendering this camera.
|
|
HideFromWrongCameras.RegisterZEDCam(cam); //Makes all objects with a HideFromWrongCamera hide from this, unless set to this specifc one.
|
|
HideFromWrongCameras hider = canvas.GetComponent<HideFromWrongCameras>();
|
|
if(!hider)
|
|
{
|
|
hider = canvas.AddComponent<HideFromWrongCameras>();
|
|
}
|
|
|
|
hider.SetRenderCamera(cam); //This canvas will allow this camera to render it.
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether or not post-processing effects are applied.
|
|
/// Usually set by ZEDManager based on the selection in its Inspector.
|
|
/// </summary>
|
|
/// <param name="c"></param>
|
|
public void SetPostProcess(bool c)
|
|
{
|
|
ARpostProcessing = c;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The object that forces the ZED image to be shown at 16:9 aspect ratio, regardless of the target window's resolution.
|
|
/// </summary>
|
|
private WindowAspectRatio aspectRatio;
|
|
|
|
/// <summary>
|
|
/// Changes the scene's global lighting settings to prevent global illumnation from causing
|
|
/// lighting that doesn't match the real world.
|
|
/// </summary>
|
|
private void SetUpGI()
|
|
{
|
|
//Only do this if "Hide Skybox" is enabled in ZEDManager, which is is by default.
|
|
if (zedManager)
|
|
{
|
|
if (zedManager.greySkybox)
|
|
{
|
|
RenderSettings.skybox = null;
|
|
Color c;
|
|
ColorUtility.TryParseHtmlString("#999999", out c);
|
|
RenderSettings.ambientLight = c;
|
|
DynamicGI.UpdateEnvironment();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configures materials/values/settings needed for post-processing and displaying in proper aspect ratio.
|
|
/// </summary>
|
|
private void Start()
|
|
{
|
|
//No environmental lighting per default
|
|
Shader.SetGlobalFloat("_ZEDExposure", -1);
|
|
//Load the materials.
|
|
matStencilToMask = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Stencil2Mask") as Material);
|
|
matComposeMask = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_MaskCompositor") as Material);
|
|
|
|
//Load and configure the post-process material.
|
|
postprocessMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_PostProcessing") as Material);
|
|
postprocessMaterial.SetFloat("_gamma", 1.0f / (0.87f * 0.9f));
|
|
postprocessMaterial.SetFloat("_MinBlack", 15.0f / 255.0f);
|
|
postprocessMaterial.SetInt("_NoiseSize", 2);
|
|
|
|
//Configure the weights for the blur effect.
|
|
float[] weights;
|
|
float[] offsets;
|
|
ZEDPostProcessingTools.ComputeWeights(0.3f, out weights, out offsets);
|
|
|
|
//Set the blur config to the shader, should be constant
|
|
blurMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Blur") as Material);
|
|
blurMaterial.SetFloatArray("weights", weights);
|
|
blurMaterial.SetFloatArray("offset", offsets);
|
|
//blurMaterial.SetTexture("_Mask", mask);
|
|
blurMaterial.SetTexture(maskPropID, mask);
|
|
|
|
|
|
//Force Unity into 16:9 mode to match the ZED's output.
|
|
#if UNITY_EDITOR
|
|
UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect16by9, true);
|
|
UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect16by10, false);
|
|
UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect4by3, false);
|
|
UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect5by4, false);
|
|
#endif
|
|
CreateRenderTexture();
|
|
|
|
//Load the blender for the zedmesher
|
|
blender = new Material(Resources.Load("Materials/SpatialMapping/Mat_ZED_PostProcess_Blend") as Material);
|
|
|
|
//Set the bounds around the camera, used to detect if a point/spotlight is close enough to be applied.
|
|
bounds = new Bounds(transform.position, new Vector3(20, 20, 20));
|
|
|
|
//IF AR REMOVE
|
|
aspectRatio = new WindowAspectRatio(cam);
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Configures numerous settings that can't be set until the ZED is fully initialized.
|
|
/// Subscribed to ZEDManager.OnZEDReady in OnEnable().
|
|
/// </summary>
|
|
void ZEDReady()
|
|
{
|
|
//Add the fade-in effect for when the camera first becomes visible.
|
|
if (zedManager.fadeInOnStart)
|
|
gameObject.AddComponent<LoadingFade>();
|
|
|
|
//This cannot happen but just in case...
|
|
if (zedManager == null)
|
|
return;
|
|
|
|
zedCamera = zedManager.zedCamera;
|
|
SetTextures(zedCamera,viewMode);
|
|
canvas.SetActive(true);
|
|
canvas.transform.SetParent (cam.transform);
|
|
ConfigureLightAndShadow(cam.actualRenderingPath);
|
|
|
|
//Move the plane with the optical centers.
|
|
float plane_distance =0.15f;
|
|
Vector4 opticalCenters = zedCamera.ComputeOpticalCenterOffsets(plane_distance);
|
|
|
|
if (side==0)
|
|
canvas.transform.localPosition = new Vector3(opticalCenters.x, -1.0f * opticalCenters.y,plane_distance);
|
|
else if (side==1)
|
|
canvas.transform.localPosition = new Vector3(opticalCenters.z, -1.0f * opticalCenters.w,plane_distance);
|
|
|
|
|
|
//Set the camera's parameters based on the ZED's, and scale the screen based on its distance.
|
|
if (zedCamera.IsCameraReady)
|
|
{
|
|
cam.fieldOfView = zedCamera.VerticalFieldOfView * Mathf.Rad2Deg;
|
|
//mainCamera.projectionMatrix = zedCamera.Projection;
|
|
SetProjection(nearplane, farplane);
|
|
cam.nearClipPlane = nearplane;
|
|
cam.farClipPlane = farplane;
|
|
//mainCamera.nearClipPlane = 0.1f;
|
|
//mainCamera.farClipPlane = 500.0f;
|
|
scale(canvas.gameObject, GetFOVYFromProjectionMatrix(cam.projectionMatrix));
|
|
}
|
|
else //Just scale the screen.
|
|
{
|
|
scale(canvas.gameObject, cam.fieldOfView);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hides the canvas. Called when the ZED is disconnected via the ZEDManager.OnZEDDisconnected event.
|
|
/// </summary>
|
|
void ZEDDisconnected()
|
|
{
|
|
canvas.SetActive(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fixes GI, enables the canvas and subscribes to events from the ZED.
|
|
/// </summary>
|
|
private void OnEnable()
|
|
{
|
|
SetUpGI();
|
|
|
|
meshCanvas = gameObject.transform.GetChild(0).GetComponent<MeshFilter>();
|
|
canvas.SetActive(false);
|
|
|
|
//iterate until we found the ZED Manager parent...
|
|
Transform ObjParent = gameObject.transform;
|
|
int tries = 0;
|
|
while (zedManager == null && tries<5) {
|
|
if (ObjParent!=null)
|
|
zedManager= ObjParent.GetComponent<ZEDManager> ();
|
|
if (zedManager == null && ObjParent!=null)
|
|
ObjParent = ObjParent.parent;
|
|
tries++;
|
|
}
|
|
|
|
if (zedManager != null) {
|
|
zedManager.OnZEDReady += ZEDReady;
|
|
zedManager.OnZEDDisconnected += ZEDDisconnected;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disables the canvas and unsubscribes from events from the ZED.
|
|
/// </summary>
|
|
private void OnDisable()
|
|
{
|
|
if (zedManager != null) {
|
|
zedManager.OnZEDReady -= ZEDReady;
|
|
zedManager.OnZEDDisconnected -= ZEDDisconnected;
|
|
}
|
|
canvas.SetActive(false);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Invisible object used to force Unity to render a shadow map.
|
|
/// </summary>
|
|
GameObject forceShadowObject = null;
|
|
|
|
/// <summary>
|
|
/// Configure the canvas to get and light and shadow.
|
|
/// </summary>
|
|
/// <param name="renderingPath">The current rendering path used</param>
|
|
private void ConfigureLightAndShadow(RenderingPath renderingPath)
|
|
{
|
|
RenderingPath current = actualRenderingPath;
|
|
actualRenderingPath = renderingPath;
|
|
|
|
if (renderingPath == RenderingPath.Forward)
|
|
{
|
|
canvas.SetActive(true);
|
|
SetForward();
|
|
|
|
}
|
|
else if (renderingPath == RenderingPath.DeferredShading)
|
|
{
|
|
SetDeferred();
|
|
}
|
|
else //We're using an unknown rendering path. Log an error.
|
|
{
|
|
actualRenderingPath = current;
|
|
Debug.LogError(" [ ZED Plugin ] : The rendering path " + cam.actualRenderingPath.ToString() + " is not compatible with the ZED");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear the depth buffer used.
|
|
/// Called when configuring this script for the given rendering path (forward or deferred).
|
|
/// </summary>
|
|
private void ClearDepthBuffers()
|
|
{
|
|
if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
{
|
|
buffer[(int)ZED_RENDERING_MODE.FORWARD].Dispose();
|
|
buffer[(int)ZED_RENDERING_MODE.FORWARD] = null;
|
|
}
|
|
|
|
if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
{
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED].Dispose();
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED] = null;
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configure the materials and buffer for the forward rendering path.
|
|
/// </summary>
|
|
private void SetForward()
|
|
{
|
|
// cam.RemoveAllCommandBuffers ();
|
|
ghasShadows = false;
|
|
|
|
blitMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Blit") as Material);
|
|
|
|
Shader.SetGlobalInt("_HasShadows", 0);
|
|
|
|
gameObject.transform.GetChild(0).GetComponent<MeshRenderer>().enabled = true;
|
|
|
|
//Set the canvas's material to the material for forward rendering.
|
|
matRGB = canvas.GetComponent<Renderer>().material;
|
|
matRGB.SetInt("_isLinear", System.Convert.ToInt32(QualitySettings.activeColorSpace));
|
|
|
|
forwardMat = new Material(Resources.Load("Materials/Lighting/Mat_ZED_Forward") as Material);
|
|
|
|
|
|
// Configure the invisible object that forces Unity to calculate shadows.
|
|
if (forceShadowObject == null)
|
|
{
|
|
ConfigureForceShadowObject();
|
|
}
|
|
|
|
//Set the textures in the materials to the proper ones.
|
|
matRGB.SetTexture("_MainTex", textureEye);
|
|
matRGB.SetTexture("_CameraTex", textureEye);
|
|
matRGB.SetTexture("_DepthXYZTex", depth);
|
|
matRGB.SetTexture("_NormalsTex", normals);
|
|
|
|
forwardMat.SetTexture("_MainTex", textureEye);
|
|
forwardMat.SetTexture("_DepthXYZTex", depth);
|
|
|
|
//Clear the buffers.
|
|
if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
|
|
if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
|
|
ClearDepthBuffers();
|
|
|
|
if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
|
|
if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
{
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].Dispose();
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] = null;
|
|
}
|
|
|
|
//Set the depth buffer.
|
|
buffer[(int)ZED_RENDERING_MODE.FORWARD] = new CommandBuffer();
|
|
buffer[(int)ZED_RENDERING_MODE.FORWARD].name = "ZED_DEPTH";
|
|
buffer[(int)ZED_RENDERING_MODE.FORWARD].SetRenderTarget(BuiltinRenderTextureType.CurrentActive);
|
|
buffer[(int)ZED_RENDERING_MODE.FORWARD].DrawMesh(meshCanvas.mesh, gameObject.transform.GetChild(0).transform.localToWorldMatrix, forwardMat);
|
|
|
|
if (mask == null || !mask.IsCreated())
|
|
{
|
|
mask = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.R8);
|
|
}
|
|
|
|
//Set up the post-processing material.
|
|
postprocessMaterial.SetTexture("ZEDMaskPostProcess", mask);
|
|
postprocessMaterial.SetTexture("ZEDTex", textureEye);
|
|
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] = new CommandBuffer();
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].name = "ZED_FORWARD_POSTPROCESS";
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].Blit(BuiltinRenderTextureType.CameraTarget, mask, blitMaterial, 0);
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].SetGlobalTexture("_ZEDMaskVirtual", mask);
|
|
|
|
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
cam.AddCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
|
|
//Configure the light containers.
|
|
if (computeBufferPointLight == null)
|
|
{
|
|
computeBufferPointLight = new ComputeBuffer(NUMBER_POINT_LIGHT_MAX, SIZE_POINT_LIGHT_BYTES);
|
|
computeBufferPointLight.SetData(pointLights);
|
|
|
|
matRGB.SetBuffer("pointLights", computeBufferPointLight);
|
|
}
|
|
|
|
if (computeBufferSpotLight == null)
|
|
{
|
|
computeBufferSpotLight = new ComputeBuffer(NUMBER_SPOT_LIGHT_MAX, SIZE_SPOT_LIGHT_BYTES);
|
|
computeBufferSpotLight.SetData(spotLights);
|
|
matRGB.SetBuffer("spotLights", computeBufferSpotLight);
|
|
}
|
|
|
|
//Register the property IDs to improve performance. (Setting properties by string is slower)
|
|
numberPointLightsID = Shader.PropertyToID("numberPointLights");
|
|
numberSpotLightsID = Shader.PropertyToID("numberSpotLights");
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configure the materials and buffer for the deferred rendering path.
|
|
/// </summary>
|
|
private void SetDeferred()
|
|
{
|
|
//Disable MSSA as it's not supported with deferred.
|
|
#if UNITY_5_6_OR_NEWER
|
|
cam.allowMSAA = false;
|
|
#endif
|
|
|
|
ghasShadows = false;
|
|
deferredMat = new Material(Resources.Load("Materials/Lighting/Mat_ZED_Deferred") as Material);
|
|
blitMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Blit") as Material);
|
|
|
|
//Sets the custom shader for the deferred pipeline.
|
|
GraphicsSettings.SetCustomShader(BuiltinShaderType.DeferredShading, (Resources.Load("Materials/Lighting/Mat_ZED_Deferred_Lighting") as Material).shader);
|
|
|
|
deferredMat.SetMatrix("_Model", canvas.transform.localToWorldMatrix.transpose);
|
|
deferredMat.SetMatrix("_Projection", cam.projectionMatrix);
|
|
|
|
deferredMat.SetTexture("_MainTex", textureEye);
|
|
deferredMat.SetTexture("_DepthXYZTex", depth);
|
|
deferredMat.SetTexture("_NormalsTex", normals);
|
|
|
|
|
|
//Clear the buffers.
|
|
if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
|
|
if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
|
|
if (postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterForwardAlpha, postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
|
|
if (postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
{
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].Dispose();
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] = null;
|
|
}
|
|
|
|
ClearDepthBuffers();
|
|
|
|
//Set the depths buffer. This buffer will be changed if the camera is set to allow HDR.
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED] = new CommandBuffer();
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED].name = "ZED_DEPTH";
|
|
|
|
if (cam.allowHDR)
|
|
{
|
|
RenderTargetIdentifier[] mrt = { BuiltinRenderTextureType.GBuffer0, BuiltinRenderTextureType.GBuffer1, BuiltinRenderTextureType.GBuffer2, BuiltinRenderTextureType.CameraTarget };
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED].SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget);
|
|
}
|
|
else
|
|
{
|
|
RenderTargetIdentifier[] mrt = { BuiltinRenderTextureType.GBuffer0, BuiltinRenderTextureType.GBuffer1, BuiltinRenderTextureType.GBuffer2, BuiltinRenderTextureType.GBuffer3 };
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED].SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget);
|
|
}
|
|
buffer[(int)ZED_RENDERING_MODE.DEFERRED].DrawMesh(meshCanvas.mesh, gameObject.transform.GetChild(0).transform.localToWorldMatrix, deferredMat);
|
|
|
|
if (mask == null || !mask.IsCreated())
|
|
{
|
|
mask = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.R8);
|
|
}
|
|
//Set the post process buffer
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] = new CommandBuffer();
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].name = "ZED_FORWARD_POSTPROCESS";
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].Blit(BuiltinRenderTextureType.GBuffer0, mask, blitMaterial, 0);
|
|
postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].SetGlobalTexture("_ZEDMaskVirtual", mask);
|
|
postprocessMaterial.SetTexture("ZEDMaskPostProcess", mask);
|
|
postprocessMaterial.SetTexture("ZEDTex", textureEye);
|
|
|
|
|
|
|
|
cam.AddCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
cam.AddCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
|
|
//Congigure the invisible object
|
|
if (forceShadowObject == null)
|
|
{
|
|
ConfigureForceShadowObject();
|
|
}
|
|
transform.GetChild(0).GetComponent<MeshRenderer>().enabled = false;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up the invisible shadow GameObject that forces Unity to draw shadows.
|
|
/// </summary>
|
|
private void ConfigureForceShadowObject()
|
|
{
|
|
forceShadowObject = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
|
forceShadowObject.name = "ZED_FORCE_SHADOW";
|
|
forceShadowObject.transform.parent = transform;
|
|
|
|
forceShadowObject.transform.localPosition = new Vector3(0, 0, cam.nearClipPlane);
|
|
forceShadowObject.GetComponent<MeshRenderer>().sharedMaterial = Resources.Load("Materials/Lighting/Mat_ZED_Hide") as Material;
|
|
Destroy(forceShadowObject.GetComponent<MeshCollider>());
|
|
forceShadowObject.hideFlags = HideFlags.HideInHierarchy;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The bounds around the camera that filter out point/spotlights that are too far away to be rendered.
|
|
/// </summary>
|
|
private Bounds bounds;
|
|
|
|
/// <summary>
|
|
/// Sets the camera's local pos/rot to origin/identity and sets up the RenderTexture if in stereo mode.
|
|
/// This RenderTexture is then displayed in hidden planes handled by ZEDMixedRealityPlugin where the final
|
|
/// output to the HMD is rendered.
|
|
/// </summary>
|
|
private void CreateRenderTexture()
|
|
{
|
|
transform.localRotation = Quaternion.identity;
|
|
transform.localPosition = new Vector3(0, 0, 0);
|
|
if (cam.stereoTargetEye != StereoTargetEyeMask.None && zedManager.IsStereoRig == true)
|
|
{
|
|
if (zedCamera != null && zedCamera.IsCameraReady)
|
|
{
|
|
renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32);
|
|
cam.targetTexture = renderTextureTarget;
|
|
}
|
|
else if(sl.ZEDCamera.CheckPlugin())
|
|
{
|
|
renderTextureTarget = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
|
|
cam.targetTexture = renderTextureTarget;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and sets the textures from the ZED, including image, depth and normals as needed.
|
|
/// Once created, the ZED SDK updates the textures automatically when the ZED sends new frames, so they don't need to be updated here.
|
|
/// </summary>
|
|
/// <param name="zedCamera"></param>
|
|
private void SetTextures(sl.ZEDCamera zedCamera, sl.VIEW_MODE view_mode)
|
|
{
|
|
float baseline = zedCamera.Baseline;
|
|
canvas.transform.localRotation = Quaternion.identity;
|
|
canvas.transform.localPosition = new Vector3(0, 0, 0);
|
|
|
|
if(zedManager.IsStereoRig == true && cam.stereoTargetEye != StereoTargetEyeMask.None)
|
|
{
|
|
if (zedCamera != null && zedCamera.IsCameraReady)
|
|
{
|
|
renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32);
|
|
cam.targetTexture = renderTextureTarget;
|
|
}
|
|
|
|
//Set the camera to match the target stereo eye, unless force otherwise.
|
|
switch(cam.stereoTargetEye)
|
|
{
|
|
case StereoTargetEyeMask.Left:
|
|
if (viewSide == ZED_CAMERA_SIDE.RIGHT) viewSide = ZED_CAMERA_SIDE.LEFT;
|
|
break;
|
|
case StereoTargetEyeMask.Right:
|
|
if (viewSide == ZED_CAMERA_SIDE.LEFT) viewSide = ZED_CAMERA_SIDE.RIGHT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (viewSide) //Set up textures from the left camera or right camera, depending.
|
|
{
|
|
case ZED_CAMERA_SIDE.LEFT:
|
|
case ZED_CAMERA_SIDE.LEFT_FORCE:
|
|
default:
|
|
switch (view_mode) //Which kind of texture we view.
|
|
{
|
|
case sl.VIEW_MODE.VIEW_IMAGE:
|
|
textureEye = zedCamera.CreateTextureImageType(sl.VIEW.LEFT);
|
|
break;
|
|
case sl.VIEW_MODE.VIEW_DEPTH:
|
|
textureEye = zedCamera.CreateTextureImageType(sl.VIEW.DEPTH);
|
|
break;
|
|
case sl.VIEW_MODE.VIEW_NORMALS:
|
|
textureEye = zedCamera.CreateTextureImageType(sl.VIEW.NORMALS);
|
|
break;
|
|
}
|
|
normals = zedCamera.CreateTextureMeasureType(sl.MEASURE.NORMALS, resolution);
|
|
depth = zedCamera.CreateTextureMeasureType(sl.MEASURE.DEPTH, resolution);
|
|
break;
|
|
case ZED_CAMERA_SIDE.RIGHT:
|
|
case ZED_CAMERA_SIDE.RIGHT_FORCE:
|
|
switch (view_mode)//Which kind of texture we view.
|
|
{
|
|
case sl.VIEW_MODE.VIEW_IMAGE:
|
|
textureEye = zedCamera.CreateTextureImageType(sl.VIEW.RIGHT);
|
|
break;
|
|
case sl.VIEW_MODE.VIEW_DEPTH:
|
|
textureEye = zedCamera.CreateTextureImageType(sl.VIEW.DEPTH_RIGHT);
|
|
break;
|
|
case sl.VIEW_MODE.VIEW_NORMALS:
|
|
textureEye = zedCamera.CreateTextureImageType(sl.VIEW.NORMALS_RIGHT);
|
|
break;
|
|
}
|
|
normals = zedCamera.CreateTextureMeasureType(sl.MEASURE.NORMALS_RIGHT, resolution);
|
|
depth = zedCamera.CreateTextureMeasureType(sl.MEASURE.DEPTH_RIGHT, resolution);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables/disables keywords for the material used in the first pass, when in forward rendering.
|
|
/// </summary>
|
|
/// <param name="enable">New state of the keyword.</param>
|
|
/// <param name="name">Keyword's name.</param>
|
|
/// <returns></returns>
|
|
public bool ManageKeywordForwardMat(bool enable, string name)
|
|
{
|
|
if (forwardMat)
|
|
{
|
|
if (enable)
|
|
{
|
|
forwardMat.EnableKeyword(name);
|
|
}
|
|
else
|
|
{
|
|
forwardMat.DisableKeyword(name);
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables/disables keywords for the material used in the first pass, when in deferred rendering.
|
|
/// </summary>
|
|
/// <param name="enable">New state of the keyword.</param>
|
|
/// <param name="name">Keyword's name.</param>
|
|
/// <returns></returns>
|
|
public bool ManageKeywordDeferredMat(bool enable, string name)
|
|
{
|
|
if (deferredMat)
|
|
{
|
|
if (enable)
|
|
{
|
|
deferredMat.EnableKeyword(name);
|
|
}
|
|
else
|
|
{
|
|
deferredMat.DisableKeyword(name);
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables/disables keywords for the final display material.
|
|
/// </summary>
|
|
/// <param name="enable">New state of the keyword.</param>
|
|
/// <param name="name">Keyword's name.</param>
|
|
/// <returns></returns>
|
|
public bool ManageKeywordPipe(bool enable, string name)
|
|
{
|
|
if (matRGB)
|
|
{
|
|
if (enable)
|
|
{
|
|
matRGB.EnableKeyword(name);
|
|
}
|
|
else
|
|
{
|
|
matRGB.DisableKeyword(name);
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//Variables to get information about the lights.
|
|
|
|
/// <summary>
|
|
/// How many point lights are currently being rendered on the real world by this camera. Excludes ones filtered out by distance.
|
|
/// </summary>
|
|
[HideInInspector]
|
|
public int numberPointLights;
|
|
|
|
/// <summary>
|
|
/// How many spotlights are currently being rendered on the real world by this camera. Excludes ones filtered out by distance.
|
|
/// </summary>
|
|
[HideInInspector]
|
|
public int numberSpotLights;
|
|
bool ghasShadows = false;
|
|
|
|
/// <summary>
|
|
/// Updates lighting information, packages them into ComputeBuffers and sends them to the shader.
|
|
/// </summary>
|
|
void UpdateLights()
|
|
{
|
|
bool hasShadows = false;
|
|
|
|
int pointLightIndex = 0;
|
|
int spotLightIndex = 0;
|
|
bounds.center = transform.position;
|
|
|
|
foreach (ZEDLight zed_light in ZEDLight.s_lights)
|
|
{
|
|
Light light = zed_light.cachedLight;
|
|
|
|
if (light.type == LightType.Directional || Vector3.Distance(bounds.center, light.transform.position) < (light.range + bounds.extents.x))
|
|
{
|
|
|
|
//Deactivate all shadows from point light and spotlights as they are not currently supported.
|
|
if (light.type != LightType.Directional)
|
|
{
|
|
light.shadows = LightShadows.None;
|
|
}
|
|
if (zed_light.IsEnabled() && ((pointLightIndex + spotLightIndex) < NUMBER_LIGHTS_MAX || light.type == LightType.Directional))
|
|
{
|
|
if (light.type == LightType.Point)
|
|
{
|
|
|
|
if (pointLightIndex < NUMBER_POINT_LIGHT_MAX)
|
|
{
|
|
pointLights[pointLightIndex].color = light.color * light.intensity;
|
|
pointLights[pointLightIndex].position = light.gameObject.transform.position;
|
|
pointLights[pointLightIndex].range = light.range;
|
|
|
|
pointLightIndex++;
|
|
}
|
|
|
|
}
|
|
|
|
else if (light.type == LightType.Spot)
|
|
{
|
|
|
|
if (spotLightIndex < NUMBER_SPOT_LIGHT_MAX)
|
|
{
|
|
spotLights[spotLightIndex].color = light.color * light.intensity;
|
|
spotLights[spotLightIndex].position = light.gameObject.transform.position;
|
|
spotLights[spotLightIndex].direction = new Vector4(light.gameObject.transform.forward.normalized.x, light.gameObject.transform.forward.normalized.y, light.gameObject.transform.forward.normalized.z, Mathf.Cos((light.spotAngle / 2.0f) * Mathf.Deg2Rad));
|
|
spotLights[spotLightIndex].parameters = new Vector4(light.spotAngle, light.intensity, 1.0f / light.range, zed_light.interiorCone);
|
|
spotLightIndex++;
|
|
}
|
|
}
|
|
else if (light.type == LightType.Directional)
|
|
{
|
|
hasShadows = light.shadows != LightShadows.None && QualitySettings.shadows != ShadowQuality.Disable;
|
|
directionalLightData[0] = new Vector4(light.gameObject.transform.forward.normalized.x, light.gameObject.transform.forward.normalized.y, light.gameObject.transform.forward.normalized.z, 0);
|
|
directionalLightData[1] = light.color * light.intensity;
|
|
// Copy the shadows from the directional light. If not, no shadows in transparent mode.
|
|
if (light.commandBufferCount == 0)
|
|
{
|
|
forwardMat.SetInt("_HasShadows", System.Convert.ToInt32(light.shadows != LightShadows.None));
|
|
|
|
// Copy the shadows from the directional light. If not, no shadows in transparent mode.
|
|
if (light.commandBufferCount == 0)
|
|
{
|
|
CommandBuffer lightBuffer = new CommandBuffer();
|
|
lightBuffer.name = "ZED_Copy_ShadowMap";
|
|
lightBuffer.SetGlobalTexture("_DirectionalShadowMap", BuiltinRenderTextureType.CurrentActive);
|
|
|
|
light.AddCommandBuffer(LightEvent.AfterScreenspaceMask, lightBuffer);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Send the new light data to the final display material.
|
|
if (computeBufferPointLight != null)
|
|
{
|
|
computeBufferPointLight.SetData(pointLights);
|
|
}
|
|
if (computeBufferSpotLight != null)
|
|
{
|
|
computeBufferSpotLight.SetData(spotLights);
|
|
}
|
|
|
|
numberPointLights = pointLightIndex;
|
|
numberSpotLights = spotLightIndex;
|
|
|
|
if (matRGB != null)
|
|
{
|
|
//Add the command buffer to get shadows only if a directional light creates shadows.
|
|
if (hasShadows != ghasShadows)
|
|
{
|
|
ghasShadows = hasShadows;
|
|
Shader.SetGlobalInt("_HasShadows", System.Convert.ToInt32(ghasShadows));
|
|
cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
if (hasShadows)
|
|
{
|
|
cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
}
|
|
|
|
}
|
|
//Send the number of point lights/spotlights to the shader.
|
|
matRGB.SetInt(numberPointLightsID, pointLightIndex);
|
|
matRGB.SetInt(numberSpotLightsID, spotLightIndex);
|
|
}
|
|
matRGB.SetVectorArray("ZED_directionalLight", directionalLightData);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets the vertical field of view from the given projection matrix, to bypass a round number.
|
|
/// </summary>
|
|
/// <param name="projection">Projection matrix from a camera.</param>
|
|
/// <returns></returns>
|
|
float GetFOVYFromProjectionMatrix(Matrix4x4 projection)
|
|
{
|
|
return Mathf.Atan(1 / projection[1, 1]) * 2.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the horizontal field of view from the given projection matrix.
|
|
/// </summary>
|
|
/// <param name="projection">Projection matrix from a camera.</param>
|
|
/// <returns></returns>
|
|
float GetFOVXFromProjectionMatrix(Matrix4x4 projection)
|
|
{
|
|
return Mathf.Atan(1 / projection[0, 0]) * 2.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scales the canvas in front of the camera so that it fills the whole screen exactly.
|
|
/// </summary>
|
|
/// <param name="screen">Canvas object.</param>
|
|
/// <param name="fov">Camera's vertical field of view. </param>
|
|
private void scale(GameObject screen, float fov)
|
|
{
|
|
float height = Mathf.Tan(0.5f * fov) * Vector3.Distance(screen.transform.localPosition, Vector3.zero) * 2;
|
|
screen.transform.localScale = new Vector3((height*aspect), height, 1);
|
|
}
|
|
|
|
private void scaleXY(GameObject screen, float fovH,float fovV)
|
|
{
|
|
float height = Mathf.Tan(0.5f * fovV) * Vector3.Distance(screen.transform.localPosition, Vector3.zero) * 2;
|
|
float width = Mathf.Tan(0.5f * fovH) * Vector3.Distance(screen.transform.localPosition,Vector3.zero) * 2;
|
|
screen.transform.localScale = new Vector3(width, height, 1);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
|
|
if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]);
|
|
|
|
if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
|
|
if (postProcessBuffer [(int)ZED_RENDERING_MODE.FORWARD] != null)
|
|
cam.RemoveCommandBuffer (CameraEvent.AfterForwardAlpha, postProcessBuffer [(int)ZED_RENDERING_MODE.FORWARD]);
|
|
|
|
if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null)
|
|
cam.RemoveCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]);
|
|
|
|
|
|
ClearDepthBuffers();
|
|
|
|
}
|
|
|
|
void OnApplicationQuit()
|
|
{
|
|
if (computeBufferPointLight != null)
|
|
{
|
|
computeBufferPointLight.Release();
|
|
}
|
|
|
|
if (computeBufferSpotLight != null)
|
|
{
|
|
computeBufferSpotLight.Release();
|
|
}
|
|
|
|
if (mask != null)
|
|
{
|
|
mask.Release();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the output size to fit the window at 16:9 and the bounds for light filtering, and calculates the lighting.
|
|
/// </summary>
|
|
void Update()
|
|
{
|
|
if (zedManager == null)
|
|
return;
|
|
|
|
if(aspectRatio != null)
|
|
{
|
|
aspectRatio.Update();
|
|
}
|
|
|
|
if (actualRenderingPath == RenderingPath.Forward)
|
|
{
|
|
bounds.center = transform.position;
|
|
UpdateLights();
|
|
}
|
|
|
|
if(zedManager.IsZEDReady && (cam.nearClipPlane != nearplane || cam.farClipPlane != farplane))
|
|
{
|
|
SetProjection(nearplane, farplane); //If the camera's near/far planes changed, update the matrix.
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
if (actualRenderingPath != RenderingPath.VertexLit && cam.actualRenderingPath != actualRenderingPath)
|
|
{
|
|
ConfigureLightAndShadow(cam.actualRenderingPath);
|
|
}
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used by the ZEDMeshRenderer/ZEDPlaneRenderer to draw chunks/planes onto the final images.
|
|
/// </summary>
|
|
private RenderTexture textureMapping;
|
|
|
|
/// <summary>
|
|
/// Sets the RenderTexture that gets blended into the final result, if using Plane Detection or Spatial Mapping.
|
|
/// ZEDPlaneRenderer and ZEDMeshRenderer call this with the RenderTextures to which they render each frame.
|
|
/// </summary>
|
|
/// <param name="texture"></param>
|
|
public void SetTextureOverlayMapping(RenderTexture texture)
|
|
{
|
|
textureMapping = texture;
|
|
blender.SetTexture("_ZEDMeshTex", textureMapping);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Where the post-processing occurs.
|
|
/// Called by Unity whenever the attached Camera renders an image.
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="destination"></param>
|
|
private void OnRenderImage(RenderTexture source, RenderTexture destination)
|
|
{
|
|
if (zedManager.GetSpatialMapping.display) //If displaying a mesh from spatial mapping, blend the wireframe into the image.
|
|
{
|
|
RenderTexture tmpSource = RenderTexture.GetTemporary (source.width, source.height, source.depth, source.format, RenderTextureReadWrite.sRGB);
|
|
Graphics.Blit (source, tmpSource);
|
|
|
|
//blender.SetInt ("_IsTextured", 0);
|
|
blender.SetInt (isTexturedID, 0);
|
|
|
|
Graphics.Blit (tmpSource, destination, blender);
|
|
RenderTexture.ReleaseTemporary (tmpSource);
|
|
}
|
|
else
|
|
{
|
|
if (ARpostProcessing && mask != null && zedCamera.IsCameraReady) //Apply post-processing, if enabled.
|
|
{
|
|
|
|
if (actualRenderingPath == RenderingPath.DeferredShading)
|
|
{
|
|
|
|
RenderTexture bluredMask = RenderTexture.GetTemporary(mask.width, mask.height, mask.depth, mask.format);
|
|
RenderTexture buffer = RenderTexture.GetTemporary(source.width, source.height, 24);
|
|
|
|
Graphics.SetRenderTarget(buffer);
|
|
GL.Clear(false, true, new Color(0, 0, 0, 0)); // clear the full RT
|
|
|
|
//To keep the stencil in post-processing, since Graphics.Blit normally clears it.
|
|
Graphics.SetRenderTarget(buffer.colorBuffer, source.depthBuffer);
|
|
Graphics.Blit(source, matStencilToMask);
|
|
|
|
//Compose the second mask retrieved in the forward pass. The shader should set the stencil to 148.
|
|
Graphics.Blit(mask, bluredMask);
|
|
//matComposeMask.SetTexture("_Mask", bluredMask);
|
|
matComposeMask.SetTexture(maskPropID, bluredMask);
|
|
Graphics.Blit(buffer, mask, matComposeMask);
|
|
|
|
ApplyPostProcess(source, destination, bluredMask);
|
|
|
|
RenderTexture.ReleaseTemporary(buffer);
|
|
RenderTexture.ReleaseTemporary(bluredMask);
|
|
}
|
|
else //Forward path.
|
|
{
|
|
RenderTexture bluredMask = RenderTexture.GetTemporary(mask.width, mask.height, mask.depth, mask.format);
|
|
ApplyPostProcess(source, destination, bluredMask);
|
|
RenderTexture.ReleaseTemporary(bluredMask);
|
|
}
|
|
}
|
|
else //Not using post-processing.
|
|
{
|
|
Graphics.Blit(source, destination);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apply post-processing effects to the given RenderTexture.
|
|
/// </summary>
|
|
/// <param name="source">Source RenderTexture.</param>
|
|
/// <param name="destination">Destination RenderTexture.</param>
|
|
/// <param name="bluredMask">Mask used to apply blurring effects.</param>
|
|
private void ApplyPostProcess(RenderTexture source, RenderTexture destination, RenderTexture bluredMask)
|
|
{
|
|
RenderTexture tempDestination = RenderTexture.GetTemporary(source.width, source.height, source.depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
|
|
|
|
Graphics.Blit(source, tempDestination, postprocessMaterial);
|
|
ZEDPostProcessingTools.Blur(mask, bluredMask, blurMaterial, 3, 1, 1);
|
|
|
|
//blurMaterial.SetTexture("_Mask", bluredMask);
|
|
blurMaterial.SetTexture(maskPropID, bluredMask);
|
|
ZEDPostProcessingTools.Blur(tempDestination, destination, blurMaterial, 2, 1, 1);
|
|
mask.SetGlobalShaderProperty("_ZEDMaskVirtual");
|
|
RenderTexture.ReleaseTemporary(tempDestination);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assigns the projection matrix from the ZED to this camera with the specified near/far planes.
|
|
/// </summary><remarks>
|
|
/// Adjusts the matrix values from a copy rather than reassigning them in ZEDCamera to avoid getting applied
|
|
/// to all copies of the camera.
|
|
///</remarks>
|
|
///<param name="near">Desired near plane distance.</param>
|
|
///<param name="far">Desired far plane distance.</param>
|
|
private void SetProjection(float near = 0.1f, float far = 500f)
|
|
{
|
|
//float near = mainCamera.nearClipPlane;
|
|
//float far = mainCamera.farClipPlane;
|
|
|
|
Matrix4x4 newmat = zedCamera.Projection;
|
|
newmat[2, 2] = -(far + near) / (far - near);
|
|
newmat[2, 3] = -(2.0f * far * near) / (far - near);
|
|
cam.projectionMatrix = newmat;
|
|
|
|
nearplane = near;
|
|
farplane = far;
|
|
}
|
|
|
|
/// Forces the ZED's image to be displayed at a 16:9 ratio, regardless of the window's aspect ratio.
|
|
/// This is why the image doesn't stretch when the Game window in the editor is set to Free Aspet.
|
|
/// </summary>
|
|
public class WindowAspectRatio
|
|
{
|
|
/// <summary>
|
|
/// Current screen width.
|
|
/// </summary>
|
|
private int ScreenSizeX = 0;
|
|
|
|
/// <summary>
|
|
/// Current screen height.
|
|
/// </summary>
|
|
private int ScreenSizeY = 0;
|
|
|
|
/// <summary>
|
|
/// Camera to set to 16:9.
|
|
/// </summary>
|
|
private Camera cam;
|
|
|
|
/// <summary>
|
|
/// Aspect ratio targeted.
|
|
/// </summary>
|
|
private const float TARGET_ASPECT = 16.0f / 9.0f;
|
|
|
|
|
|
public WindowAspectRatio(Camera camera)
|
|
{
|
|
cam = camera;
|
|
RescaleCamera();
|
|
CreateCamera();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a custom hidden camera to render black bars in the background.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private GameObject CreateCamera()
|
|
{
|
|
GameObject o = new GameObject("CameraBlackBackground");
|
|
Camera cam = o.AddComponent<Camera>();
|
|
cam.backgroundColor = Color.black;
|
|
cam.cullingMask = 0;
|
|
cam.clearFlags = CameraClearFlags.SolidColor;
|
|
cam.depth = -int.MaxValue;
|
|
cam.useOcclusionCulling = false;
|
|
#if UNITY_5_6_OR_NEWER
|
|
cam.allowHDR = false;
|
|
cam.allowMSAA = false;
|
|
#endif
|
|
cam.stereoTargetEye = StereoTargetEyeMask.None;
|
|
cam.renderingPath = RenderingPath.Forward;
|
|
o.hideFlags = HideFlags.HideInHierarchy;
|
|
return o;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rescale the view port of the current camera to keep the 16:9 aspect ratio.
|
|
/// This is called on start and updated each frame.
|
|
/// </summary>
|
|
private void RescaleCamera()
|
|
{
|
|
//If no change, then return
|
|
if (Screen.width == ScreenSizeX && Screen.height == ScreenSizeY) return;
|
|
|
|
float windowaspect = (float)Screen.width / (float)Screen.height;
|
|
float scaleheight = windowaspect / TARGET_ASPECT;
|
|
|
|
if (scaleheight < 1.0f) //Height is too large. Shrink it, adding letterboxes to the top and bottom.
|
|
{
|
|
Rect rect = cam.rect;
|
|
|
|
rect.width = 1.0f;
|
|
rect.height = scaleheight;
|
|
rect.x = 0;
|
|
rect.y = (1.0f - scaleheight) / 2.0f;
|
|
|
|
//cam.rect = rect;
|
|
}
|
|
else //Height is too small. Reduce width, adding pillarboxes to the sides.
|
|
{
|
|
float scalewidth = 1.0f / scaleheight;
|
|
|
|
Rect rect = cam.rect;
|
|
|
|
rect.width = scalewidth;
|
|
rect.height = 1.0f;
|
|
rect.x = (1.0f - scalewidth) / 2.0f;
|
|
rect.y = 0;
|
|
|
|
cam.rect = rect;
|
|
}
|
|
|
|
ScreenSizeX = Screen.width;
|
|
ScreenSizeY = Screen.height;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Calls RescaleCamera(). Called in ZEDRenderingPlane's Update() function.
|
|
/// </summary>
|
|
public void Update()
|
|
{
|
|
RescaleCamera();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|