mirror of
https://github.com/xiaopeng12138/MaiDXR.git
synced 2024-11-24 03:50:10 +01:00
Add LIV SDK
This commit is contained in:
parent
732045d109
commit
67d911847b
90
Assets/LIV/Resources/Shaders/LIV_ClipPlaneComplex.shader
Normal file
90
Assets/LIV/Resources/Shaders/LIV_ClipPlaneComplex.shader
Normal file
@ -0,0 +1,90 @@
|
||||
Shader "Hidden/LIV_ClipPlaneComplex"
|
||||
{
|
||||
Properties{
|
||||
_LivClipPlaneHeightMap("Clip Plane Height Map", 2D) = "black" {}
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Overlay" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass {
|
||||
Name "CLIP_PLANE_COMPLEX"
|
||||
Cull Off
|
||||
ZWrite On
|
||||
Blend Off
|
||||
Fog{ Mode Off }
|
||||
ColorMask[_LivColorMask]
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma target 4.6
|
||||
|
||||
#pragma vertex TessellationVertexProgram
|
||||
#pragma fragment FragmentProgram
|
||||
#pragma hull HullProgram
|
||||
#pragma domain DomainProgram
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
sampler2D _LivClipPlaneHeightMap;
|
||||
float _LivTessellation;
|
||||
|
||||
struct VertexData {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct TessellationFactors {
|
||||
float edge[4] : SV_TessFactor;
|
||||
float inside[2] : SV_InsideTessFactor;
|
||||
};
|
||||
|
||||
struct TessellationControlPoint {
|
||||
float4 vertex : INTERNALTESSPOS;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
[domain("quad")]
|
||||
[outputcontrolpoints(4)]
|
||||
[outputtopology("triangle_cw")]
|
||||
[partitioning("fractional_odd")]
|
||||
[patchconstantfunc("PatchConstantFunction")]
|
||||
TessellationControlPoint HullProgram(InputPatch<TessellationControlPoint, 4> patch, uint id : SV_OutputControlPointID) {
|
||||
return patch[id];
|
||||
}
|
||||
|
||||
TessellationFactors PatchConstantFunction(InputPatch<TessellationControlPoint, 4> patch) {
|
||||
TessellationFactors f;
|
||||
float t = _LivTessellation;
|
||||
f.edge[0] = f.edge[1] = f.edge[2] = f.edge[3] = f.inside[0] = f.inside[1] = t;
|
||||
return f;
|
||||
}
|
||||
|
||||
[domain("quad")]
|
||||
VertexData DomainProgram(TessellationFactors factors, OutputPatch<TessellationControlPoint, 4> patch, float2 uv : SV_DomainLocation) {
|
||||
VertexData data;
|
||||
|
||||
data.uv = lerp(lerp(patch[0].uv, patch[1].uv, uv.x), lerp(patch[3].uv, patch[2].uv, uv.x), uv.y);
|
||||
float4 vertex = lerp(lerp(patch[0].vertex, patch[1].vertex, uv.x), lerp(patch[3].vertex, patch[2].vertex, uv.x), uv.y);
|
||||
vertex.z += tex2Dlod(_LivClipPlaneHeightMap, float4(data.uv, 0, 0)).r;
|
||||
data.vertex = UnityObjectToClipPos(vertex);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
TessellationControlPoint TessellationVertexProgram(VertexData v) {
|
||||
TessellationControlPoint p;
|
||||
p.vertex = v.vertex;
|
||||
p.uv = v.uv;
|
||||
return p;
|
||||
}
|
||||
|
||||
fixed4 FragmentProgram(TessellationControlPoint i) : SV_Target{
|
||||
return fixed4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
120
Assets/LIV/Resources/Shaders/LIV_ClipPlaneComplexDebug.shader
Normal file
120
Assets/LIV/Resources/Shaders/LIV_ClipPlaneComplexDebug.shader
Normal file
@ -0,0 +1,120 @@
|
||||
Shader "Hidden/LIV_ClipPlaneComplexDebug"
|
||||
{
|
||||
Properties{
|
||||
_LivClipPlaneHeightMap("Clip Plane Height Map", 2D) = "black" {}
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Background" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass {
|
||||
Name "CLIP_PLANE_COMPLEX_DEBUG"
|
||||
Cull Off ZWrite On
|
||||
Fog{ Mode Off }
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma target 4.6
|
||||
|
||||
#pragma vertex TessellationVertexProgram
|
||||
#pragma fragment FragmentProgram
|
||||
#pragma hull HullProgram
|
||||
#pragma domain DomainProgram
|
||||
#pragma geometry GeometryProgram
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
sampler2D _LivClipPlaneHeightMap;
|
||||
float _LivTessellation;
|
||||
|
||||
struct VertexData {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 worldPos : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct GeomToFragData {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 barycentric : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct TessellationFactors {
|
||||
float edge[4] : SV_TessFactor;
|
||||
float inside[2] : SV_InsideTessFactor;
|
||||
};
|
||||
|
||||
struct TessellationControlPoint {
|
||||
float4 vertex : INTERNALTESSPOS;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
[domain("quad")]
|
||||
[outputcontrolpoints(4)]
|
||||
[outputtopology("triangle_cw")]
|
||||
[partitioning("fractional_odd")]
|
||||
[patchconstantfunc("PatchConstantFunction")]
|
||||
TessellationControlPoint HullProgram(InputPatch<TessellationControlPoint, 4> patch, uint id : SV_OutputControlPointID) {
|
||||
return patch[id];
|
||||
}
|
||||
|
||||
TessellationFactors PatchConstantFunction(InputPatch<TessellationControlPoint, 4> patch) {
|
||||
TessellationFactors f;
|
||||
float t = _LivTessellation;
|
||||
f.edge[0] = f.edge[1] = f.edge[2] = f.edge[3] = f.inside[0] = f.inside[1] = t;
|
||||
return f;
|
||||
}
|
||||
|
||||
[domain("quad")]
|
||||
VertexData DomainProgram(TessellationFactors factors, OutputPatch<TessellationControlPoint, 4> patch, float2 uv : SV_DomainLocation) {
|
||||
VertexData data;
|
||||
|
||||
data.uv = lerp(lerp(patch[0].uv, patch[1].uv, uv.x), lerp(patch[3].uv, patch[2].uv, uv.x), uv.y);
|
||||
float4 vertex = lerp(lerp(patch[0].vertex, patch[1].vertex, uv.x), lerp(patch[3].vertex, patch[2].vertex, uv.x), uv.y);
|
||||
vertex.z += tex2Dlod(_LivClipPlaneHeightMap, float4(data.uv, 0, 0)).r;
|
||||
data.vertex = UnityObjectToClipPos(vertex);
|
||||
data.worldPos = mul(unity_ObjectToWorld, vertex);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
TessellationControlPoint TessellationVertexProgram(VertexData v) {
|
||||
TessellationControlPoint p;
|
||||
p.vertex = v.vertex;
|
||||
p.uv = v.uv;
|
||||
return p;
|
||||
}
|
||||
|
||||
[maxvertexcount(3)]
|
||||
void GeometryProgram(triangle VertexData p[3], inout TriangleStream<GeomToFragData> triStream) {
|
||||
GeomToFragData pIn;
|
||||
|
||||
pIn.vertex = p[0].vertex;
|
||||
pIn.uv = p[0].uv;
|
||||
pIn.barycentric.xyz = float3(1.0, 0, 0);
|
||||
triStream.Append(pIn);
|
||||
|
||||
pIn.vertex = p[1].vertex;
|
||||
pIn.uv = p[1].uv;
|
||||
pIn.barycentric.xyz = float3(0, 1.0, 0);
|
||||
triStream.Append(pIn);
|
||||
|
||||
pIn.vertex = p[2].vertex;
|
||||
pIn.uv = p[2].uv;
|
||||
pIn.barycentric.xyz = float3(0, 0, 1.0);
|
||||
triStream.Append(pIn);
|
||||
}
|
||||
|
||||
fixed4 FragmentProgram(GeomToFragData i) : SV_Target {
|
||||
float3 barys;
|
||||
barys.xy = i.barycentric;
|
||||
barys.z = 1 - barys.x - barys.y;
|
||||
barys = smoothstep(0.0, 0.0 + fwidth(barys), barys);
|
||||
return lerp(float4(0.0, 0.0, 0.0, 0.5), float4(0.0, 1.0, 0.0, 0.5), min(barys.x, min(barys.y, barys.z)));
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
47
Assets/LIV/Resources/Shaders/LIV_ClipPlaneSimple.shader
Normal file
47
Assets/LIV/Resources/Shaders/LIV_ClipPlaneSimple.shader
Normal file
@ -0,0 +1,47 @@
|
||||
Shader "Hidden/LIV_ClipPlaneSimple"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Overlay" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass {
|
||||
Name "CLIP_PLANE_SIMPLE"
|
||||
Cull Off
|
||||
ZWrite On
|
||||
Blend Off
|
||||
Fog{ Mode Off }
|
||||
ColorMask[_LivColorMask]
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma target 4.6
|
||||
|
||||
#pragma vertex VertexProgram
|
||||
#pragma fragment FragmentProgram
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct VertexData {
|
||||
float4 vertex : POSITION;
|
||||
};
|
||||
|
||||
struct VertexToFragData {
|
||||
float4 vertex : POSITION;
|
||||
};
|
||||
|
||||
VertexToFragData VertexProgram(VertexData v)
|
||||
{
|
||||
VertexToFragData o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 FragmentProgram(VertexToFragData i) : SV_Target
|
||||
{
|
||||
return fixed4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
79
Assets/LIV/Resources/Shaders/LIV_ClipPlaneSimpleDebug.shader
Normal file
79
Assets/LIV/Resources/Shaders/LIV_ClipPlaneSimpleDebug.shader
Normal file
@ -0,0 +1,79 @@
|
||||
Shader "Hidden/LIV_ClipPlaneSimpleDebug"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Overlay" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass {
|
||||
Name "CLIP_PLANE_SIMPLE_DEBUG"
|
||||
Cull Off
|
||||
ZWrite On
|
||||
Fog{ Mode Off }
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma target 4.6
|
||||
|
||||
#pragma vertex VertexProgram
|
||||
#pragma fragment FragmentProgram
|
||||
#pragma geometry GeometryProgram
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct VertexData {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VertexToGeomData {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct GeomToFragData {
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 barycentric : TEXCOORD1;
|
||||
};
|
||||
|
||||
VertexToGeomData VertexProgram(VertexData v)
|
||||
{
|
||||
VertexToGeomData o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = v.uv;
|
||||
return o;
|
||||
}
|
||||
|
||||
[maxvertexcount(3)]
|
||||
void GeometryProgram(triangle VertexToGeomData p[3], inout TriangleStream<GeomToFragData> triStream) {
|
||||
GeomToFragData pIn;
|
||||
|
||||
pIn.vertex = p[0].vertex;
|
||||
pIn.uv = p[0].uv;
|
||||
pIn.barycentric.xyz = float3(1.0, 0, 0);
|
||||
triStream.Append(pIn);
|
||||
|
||||
pIn.vertex = p[1].vertex;
|
||||
pIn.uv = p[1].uv;
|
||||
pIn.barycentric.xyz = float3(0, 1.0, 0);
|
||||
triStream.Append(pIn);
|
||||
|
||||
pIn.vertex = p[2].vertex;
|
||||
pIn.uv = p[2].uv;
|
||||
pIn.barycentric.xyz = float3(0, 0, 1.0);
|
||||
triStream.Append(pIn);
|
||||
}
|
||||
|
||||
fixed4 FragmentProgram(GeomToFragData i) : SV_Target
|
||||
{
|
||||
float3 barys;
|
||||
barys.xy = i.barycentric;
|
||||
barys.z = 1 - barys.x - barys.y;
|
||||
barys = smoothstep(0.0, 0.0 + fwidth(barys), barys);
|
||||
return lerp(float4(0.0, 0.0, 0.0, 0.5), float4(0.0, 1.0, 0.0, 0.5), min(barys.x, min(barys.y, barys.z)));
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
58
Assets/LIV/Resources/Shaders/LIV_CombineAlpha.shader
Normal file
58
Assets/LIV/Resources/Shaders/LIV_CombineAlpha.shader
Normal file
@ -0,0 +1,58 @@
|
||||
Shader "Hidden/LIV_CombineAlpha"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Texture", 2D) = "black" {}
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Overlay" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "COMBINE_ALPHA"
|
||||
Blend One OneMinusSrcAlpha
|
||||
Ztest Always
|
||||
Zwrite Off
|
||||
Cull Off
|
||||
ColorMask[_LivColorMask]
|
||||
Fog{ Mode Off }
|
||||
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 vertex : SV_POSITION;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
return tex2D(_MainTex, i.uv).a;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
Shader "Hidden/LIV_ForceForwardRendering"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Geometry" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "FORCE_FORWARD_RENDERING"
|
||||
ZTest Always ZWrite Off ColorMask 0
|
||||
Fog{ Mode Off }
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
55
Assets/LIV/Resources/Shaders/LIV_Write.shader
Normal file
55
Assets/LIV/Resources/Shaders/LIV_Write.shader
Normal file
@ -0,0 +1,55 @@
|
||||
Shader "Hidden/LIV_Write"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex("Texture", 2D) = "black" {}
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Background" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "WRITE"
|
||||
ZTest Always ZWrite Off
|
||||
ColorMask [_LivColorMask]
|
||||
Fog{ Mode Off }
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = v.uv;
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target
|
||||
{
|
||||
return tex2D(_MainTex, i.uv);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
47
Assets/LIV/Resources/Shaders/LIV_WriteOpaqueToAlpha.shader
Normal file
47
Assets/LIV/Resources/Shaders/LIV_WriteOpaqueToAlpha.shader
Normal file
@ -0,0 +1,47 @@
|
||||
Shader "Hidden/LIV_WriteOpaqueToAlpha"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Overlay" "LightMode" = "Always" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True"}
|
||||
|
||||
Pass {
|
||||
Name "CLIP_PLANE_FIX_ALPHA"
|
||||
Blend Off
|
||||
ZTest Greater
|
||||
ZWrite Off
|
||||
Cull Off
|
||||
ColorMask A
|
||||
Fog{ Mode Off }
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma target 4.6
|
||||
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
};
|
||||
|
||||
v2f vert(appdata_base v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex.xy = v.vertex.xy * 2.0;
|
||||
o.vertex.z = 0;
|
||||
o.vertex.w = 1;
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
278
Assets/LIV/Scripts/Editor/LIVEditor.cs
Normal file
278
Assets/LIV/Scripts/Editor/LIVEditor.cs
Normal file
@ -0,0 +1,278 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
[CustomEditor(typeof(LIV))]
|
||||
public class LIVEditor : Editor
|
||||
{
|
||||
const string EXCLUDE_BEHAVIOURS_FOLDOUT_KEY = "liv_excludeBehavioursfoldout";
|
||||
|
||||
const string STAGE_PROPERTY = "_stage";
|
||||
const string STAGE_TRANSFORM_PROPERTY = "_stageTransform";
|
||||
const string HMD_CAMERA_PROPERTY = "_HMDCamera";
|
||||
const string MR_CAMERA_PREFAB_PROPERTY = "_MRCameraPrefab";
|
||||
const string DISABLE_STANDARD_ASSETS_PROPERTY = "_disableStandardAssets";
|
||||
const string SPECTATOR_LAYER_MASK_PROPERTY = "_spectatorLayerMask";
|
||||
const string EXCLUDE_BEHAVIOURS_PROPERTY = "_excludeBehaviours";
|
||||
const string FIX_POST_EFFECTS_ALPHA_PROPERTY = "_fixPostEffectsAlpha";
|
||||
|
||||
static GUIContent REQUIRED_FOLDOUT_GUICONTENT = new GUIContent("Required");
|
||||
static GUIContent OPTIONAL_FOLDOUT_GUICONTENT = new GUIContent("Optional");
|
||||
|
||||
static GUIContent STAGE_GUICONTENT = new GUIContent("Stage");
|
||||
static GUIContent STAGE_INFO_GUICONTENT = new GUIContent(
|
||||
"The origin of tracked space.\n" +
|
||||
"This is the object that you use to move the player around."
|
||||
);
|
||||
|
||||
static GUIContent STAGE_TRANSFORM_GUICONTENT = new GUIContent("Stage Transform");
|
||||
static GUIContent STAGE_TRANSFORM_INFO_GUICONTENT = new GUIContent(
|
||||
"This transform defines the stage transform."
|
||||
);
|
||||
|
||||
static GUIContent HMD_CAMERA_GUICONTENT = new GUIContent("HMD Camera");
|
||||
static GUIContent HMD_CAMERA_INFO_GUICONTENT = new GUIContent(
|
||||
"Set this to the camera used to render the HMD's point of view."
|
||||
);
|
||||
|
||||
static GUIContent MR_CAMERA_PREFAB_GUICONTENT = new GUIContent("MR Camera Prefab");
|
||||
static GUIContent MR_CAMERA_PREFAB_INFO_GUICONTENT = new GUIContent(
|
||||
"Set custom camera prefab."
|
||||
);
|
||||
|
||||
static GUIContent DISABLE_STANDARD_ASSETS_GUICONTENT = new GUIContent("Disable Standard Assets");
|
||||
static GUIContent DISABLE_STANDARD_INFO_ASSETS_GUICONTENT = new GUIContent(
|
||||
"If you're using Unity's standard effects and they're interfering with MR rendering, check this box."
|
||||
);
|
||||
|
||||
static GUIContent SPECTATOR_LAYER_MASK_GUICONTENT = new GUIContent("Spectator Layer Mask");
|
||||
static GUIContent SPECTATOR_LAYER_MASK_INFO_GUICONTENT = new GUIContent(
|
||||
"By default, we'll show everything on the spectator camera. If you want to disable certain objects from showing, update this mask property."
|
||||
);
|
||||
|
||||
static GUIContent FIX_POST_EFFECTS_ALPHA_GUICONTENT = new GUIContent("Fix Post-Effects alpha channel");
|
||||
static GUIContent FIX_POST_EFFECTS_ALPHA_INFO_GUICONTENT = new GUIContent(
|
||||
"Some post-effects corrupt the alpha channel, this fix tries to recover it."
|
||||
);
|
||||
|
||||
|
||||
static GUIContent EXCLUDE_BEHAVIOURS_GUICONTENT = new GUIContent("Exclude Behaviours");
|
||||
|
||||
static GUIStyle VERSION_STYLE {
|
||||
get {
|
||||
GUIStyle g = new GUIStyle(EditorStyles.label);
|
||||
g.alignment = TextAnchor.LowerLeft;
|
||||
g.normal.textColor = Color.white;
|
||||
g.fontStyle = FontStyle.Bold;
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
||||
static GUIStyle LIV_BUTTON_STYLE {
|
||||
get {
|
||||
GUIStyle g = new GUIStyle();
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
||||
static Color darkBGColor {
|
||||
get {
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
return new Color(0f, 0f, 0f, 0.5f);
|
||||
} else
|
||||
{
|
||||
return new Color(1f, 1f, 1f, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
static Color lightRedBGColor {
|
||||
get {
|
||||
return new Color(1f, 0.5f, 0.5f, 1f);
|
||||
}
|
||||
}
|
||||
static Color lightBGColor {
|
||||
get {
|
||||
return new Color(1f, 1, 1, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
ReorderableList excludeBehavioursList;
|
||||
|
||||
static bool excludeBehavioursFoldoutValue {
|
||||
get {
|
||||
if (!EditorPrefs.HasKey(EXCLUDE_BEHAVIOURS_FOLDOUT_KEY)) return false;
|
||||
return EditorPrefs.GetBool(EXCLUDE_BEHAVIOURS_FOLDOUT_KEY);
|
||||
}
|
||||
set {
|
||||
EditorPrefs.SetBool(EXCLUDE_BEHAVIOURS_FOLDOUT_KEY, value);
|
||||
}
|
||||
}
|
||||
|
||||
SerializedProperty stageProperty = null;
|
||||
SerializedProperty stageTransformProperty = null;
|
||||
SerializedProperty hmdCameraProperty = null;
|
||||
SerializedProperty mrCameraPrefabProperty = null;
|
||||
SerializedProperty disableStandardAssetsProperty = null;
|
||||
SerializedProperty SpectatorLayerMaskProperty = null;
|
||||
SerializedProperty ExcludeBehavioursProperty = null;
|
||||
SerializedProperty FixPostEffectsAlphaProperty = null;
|
||||
|
||||
static Texture2D _livLogo;
|
||||
void OnEnable()
|
||||
{
|
||||
string[] livLogoGUID = AssetDatabase.FindAssets("LIVLogo t:texture2D");
|
||||
if (livLogoGUID.Length > 0)
|
||||
{
|
||||
_livLogo = AssetDatabase.LoadAssetAtPath<Texture2D>(AssetDatabase.GUIDToAssetPath(livLogoGUID[0]));
|
||||
}
|
||||
|
||||
stageProperty = serializedObject.FindProperty(STAGE_PROPERTY);
|
||||
stageTransformProperty = serializedObject.FindProperty(STAGE_TRANSFORM_PROPERTY);
|
||||
hmdCameraProperty = serializedObject.FindProperty(HMD_CAMERA_PROPERTY);
|
||||
mrCameraPrefabProperty = serializedObject.FindProperty(MR_CAMERA_PREFAB_PROPERTY);
|
||||
disableStandardAssetsProperty = serializedObject.FindProperty(DISABLE_STANDARD_ASSETS_PROPERTY);
|
||||
SpectatorLayerMaskProperty = serializedObject.FindProperty(SPECTATOR_LAYER_MASK_PROPERTY);
|
||||
ExcludeBehavioursProperty = serializedObject.FindProperty(EXCLUDE_BEHAVIOURS_PROPERTY);
|
||||
FixPostEffectsAlphaProperty = serializedObject.FindProperty(FIX_POST_EFFECTS_ALPHA_PROPERTY);
|
||||
|
||||
excludeBehavioursList = new ReorderableList(serializedObject, ExcludeBehavioursProperty, true, true, true, true);
|
||||
excludeBehavioursList.drawElementCallback = DrawListItems;
|
||||
excludeBehavioursList.headerHeight = 2;
|
||||
}
|
||||
|
||||
void DrawListItems(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
EditorGUI.PropertyField(rect, excludeBehavioursList.serializedProperty.GetArrayElementAtIndex(index), new GUIContent(""), false);
|
||||
}
|
||||
|
||||
void DrawList(SerializedProperty property, GUIContent guiContent)
|
||||
{
|
||||
EditorGUILayout.PropertyField(property, guiContent);
|
||||
while (true)
|
||||
{
|
||||
if(!property.Next(true))
|
||||
{
|
||||
break;
|
||||
}
|
||||
EditorGUILayout.PropertyField(property);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawProperty(SerializedProperty property, GUIContent label, GUIContent content, Color color)
|
||||
{
|
||||
Color lastAccentColor = GUI.color;
|
||||
GUI.color = darkBGColor;
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
GUI.color = lastAccentColor;
|
||||
GUILayout.Space(2);
|
||||
EditorGUILayout.PropertyField(property, label);
|
||||
Color lastBackgroundColor = GUI.backgroundColor;
|
||||
GUI.backgroundColor = color;
|
||||
EditorGUILayout.LabelField(content, EditorStyles.helpBox);
|
||||
GUI.backgroundColor = lastBackgroundColor;
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
void RenderStageField()
|
||||
{
|
||||
Color color = lightBGColor;
|
||||
GUIContent content = new GUIContent(STAGE_INFO_GUICONTENT);
|
||||
if (stageProperty.objectReferenceValue == null)
|
||||
{
|
||||
color = lightRedBGColor;
|
||||
content.text += "\nThe stage has to be set!";
|
||||
content.image = EditorGUIUtility.IconContent("console.erroricon").image;
|
||||
}
|
||||
|
||||
DrawProperty(stageProperty, STAGE_GUICONTENT, content, color);
|
||||
}
|
||||
|
||||
void RenderHMDField()
|
||||
{
|
||||
Color color = lightBGColor;
|
||||
GUIContent content = new GUIContent(HMD_CAMERA_INFO_GUICONTENT);
|
||||
if (hmdCameraProperty.objectReferenceValue == null)
|
||||
{
|
||||
color = lightRedBGColor;
|
||||
content.text += "\nThe camera has to be set!";
|
||||
content.image = EditorGUIUtility.IconContent("console.erroricon").image;
|
||||
}
|
||||
|
||||
DrawProperty(hmdCameraProperty, HMD_CAMERA_GUICONTENT, content, color);
|
||||
}
|
||||
|
||||
void RenderSpectatorLayerMaskField()
|
||||
{
|
||||
Color color = lightBGColor;
|
||||
GUIContent content = new GUIContent(SPECTATOR_LAYER_MASK_INFO_GUICONTENT);
|
||||
if (SpectatorLayerMaskProperty.intValue == 0)
|
||||
{
|
||||
color = lightRedBGColor;
|
||||
content.text += "\nAre you sure you want to render nothing?";
|
||||
content.image = EditorGUIUtility.IconContent("console.warnicon").image;
|
||||
}
|
||||
|
||||
DrawProperty(SpectatorLayerMaskProperty, SPECTATOR_LAYER_MASK_GUICONTENT, content, color);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
if (_livLogo != null)
|
||||
{
|
||||
Color lastBackgroundColor = GUI.color;
|
||||
GUI.color = new Color(0f, 0f, 0f, 0.5f);
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
GUI.color = lastBackgroundColor;
|
||||
Rect originalRect = EditorGUILayout.GetControlRect(GUILayout.Height(_livLogo.height));
|
||||
Rect imageRect = originalRect;
|
||||
imageRect.x = (originalRect.width - _livLogo.width);
|
||||
imageRect.width = _livLogo.width;
|
||||
GUI.DrawTexture(imageRect, _livLogo);
|
||||
GUI.Label(originalRect, "v" + SDKConstants.SDK_VERSION, VERSION_STYLE);
|
||||
if(GUI.Button(originalRect, new GUIContent(), LIV_BUTTON_STYLE)) {
|
||||
Application.OpenURL("https://liv.tv/");
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField(REQUIRED_FOLDOUT_GUICONTENT, EditorStyles.boldLabel);
|
||||
RenderStageField();
|
||||
RenderHMDField();
|
||||
DrawProperty(disableStandardAssetsProperty, DISABLE_STANDARD_ASSETS_GUICONTENT, DISABLE_STANDARD_INFO_ASSETS_GUICONTENT, lightBGColor);
|
||||
|
||||
RenderSpectatorLayerMaskField();
|
||||
|
||||
Color lastAccentColor = GUI.color;
|
||||
GUI.color = darkBGColor;
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
GUI.color = lastAccentColor;
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
excludeBehavioursFoldoutValue = EditorGUILayout.Foldout(excludeBehavioursFoldoutValue, EXCLUDE_BEHAVIOURS_GUICONTENT);
|
||||
EditorGUI.indentLevel--;
|
||||
if (excludeBehavioursFoldoutValue)
|
||||
{
|
||||
excludeBehavioursList.DoLayoutList();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.LabelField(OPTIONAL_FOLDOUT_GUICONTENT, EditorStyles.boldLabel);
|
||||
DrawProperty(stageTransformProperty, STAGE_TRANSFORM_GUICONTENT, STAGE_TRANSFORM_INFO_GUICONTENT, lightBGColor);
|
||||
DrawProperty(mrCameraPrefabProperty, MR_CAMERA_PREFAB_GUICONTENT, MR_CAMERA_PREFAB_INFO_GUICONTENT, lightBGColor);
|
||||
DrawProperty(FixPostEffectsAlphaProperty, FIX_POST_EFFECTS_ALPHA_GUICONTENT, FIX_POST_EFFECTS_ALPHA_INFO_GUICONTENT, lightBGColor);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
GUIContent helpContent = new GUIContent(EditorGUIUtility.IconContent("_Help"));
|
||||
helpContent.text = "Help";
|
||||
if (GUILayout.Button(helpContent))
|
||||
{
|
||||
Application.OpenURL(@"https://liv.tv/sdk-unity-docs");
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
}
|
BIN
Assets/LIV/Scripts/Editor/LIVLogo.png
Normal file
BIN
Assets/LIV/Scripts/Editor/LIVLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
522
Assets/LIV/Scripts/LIV.cs
Normal file
522
Assets/LIV/Scripts/LIV.cs
Normal file
@ -0,0 +1,522 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
using UnityEngine.XR;
|
||||
#endif
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
[System.Flags]
|
||||
public enum INVALIDATION_FLAGS : uint
|
||||
{
|
||||
NONE = 0,
|
||||
HMD_CAMERA = 1,
|
||||
STAGE = 2,
|
||||
MR_CAMERA_PREFAB = 4,
|
||||
EXCLUDE_BEHAVIOURS = 8
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The LIV SDK provides a spectator view of your application.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>It contextualizes what the user feels & experiences by capturing their body directly inside your world!</para>
|
||||
/// <para>Thanks to our software, creators can film inside your app and have full control over the camera.</para>
|
||||
/// <para>With the power of out-of-engine compositing, a creator can express themselves freely without limits;</para>
|
||||
/// <para>as a real person or an avatar!</para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class StartFromScriptExample : MonoBehaviour
|
||||
/// {
|
||||
/// [SerializeField] Camera _hmdCamera;
|
||||
/// [SerializeField] Transform _stage;
|
||||
/// [SerializeField] Transform _stageTransform;
|
||||
/// [SerializeField] Camera _mrCameraPrefab;
|
||||
|
||||
/// LIV.SDK.Unity.LIV _liv;
|
||||
|
||||
/// private void OnEnable()
|
||||
/// {
|
||||
/// _liv = gameObject.AddComponent<LIV.SDK.Unity.LIV>();
|
||||
/// _liv.HMDCamera = _hmdCamera;
|
||||
/// _liv.stage = _stage;
|
||||
/// _liv.stageTransform = _stageTransform;
|
||||
/// _liv.MRCameraPrefab = _mrCameraPrefab;
|
||||
/// }
|
||||
|
||||
/// private void OnDisable()
|
||||
/// {
|
||||
/// if (_liv == null) return;
|
||||
/// Destroy(_liv);
|
||||
/// _liv = null;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
[HelpURL("https://liv.tv/sdk-unity-docs")]
|
||||
[AddComponentMenu("LIV/LIV")]
|
||||
public class LIV : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// triggered when the LIV SDK is activated by the LIV App and enabled by the game.
|
||||
/// </summary>
|
||||
public System.Action onActivate = null;
|
||||
/// <summary>
|
||||
/// triggered before the Mixed Reality camera is about to render.
|
||||
/// </summary>
|
||||
public System.Action<SDKRender> onPreRender = null;
|
||||
/// <summary>
|
||||
/// triggered before the LIV SDK starts rendering background image.
|
||||
/// </summary>
|
||||
public System.Action<SDKRender> onPreRenderBackground = null;
|
||||
/// <summary>
|
||||
/// triggered after the LIV SDK starts rendering background image.
|
||||
/// </summary>
|
||||
public System.Action<SDKRender> onPostRenderBackground = null;
|
||||
/// <summary>
|
||||
/// triggered before the LIV SDK starts rendering the foreground image.
|
||||
/// </summary>
|
||||
public System.Action<SDKRender> onPreRenderForeground = null;
|
||||
/// <summary>
|
||||
/// triggered after the LIV SDK starts rendering the foreground image.
|
||||
/// </summary>
|
||||
public System.Action<SDKRender> onPostRenderForeground = null;
|
||||
/// <summary>
|
||||
/// triggered after the Mixed Reality camera has finished rendering.
|
||||
/// </summary>
|
||||
public System.Action<SDKRender> onPostRender = null;
|
||||
/// <summary>
|
||||
/// triggered when the LIV SDK is deactivated by the LIV App or disabled by the game.
|
||||
/// </summary>
|
||||
public System.Action onDeactivate = null;
|
||||
|
||||
[Tooltip("This is the topmost transform of your VR rig.")]
|
||||
[FormerlySerializedAs("TrackedSpaceOrigin")]
|
||||
[SerializeField] Transform _stage = null;
|
||||
/// <summary>
|
||||
/// This is the topmost transform of your VR rig.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When implementing VR locomotion(teleporting, joystick, etc),</para>
|
||||
/// <para>this is the GameObject that you should move around your scene.</para>
|
||||
/// <para>It represents the centre of the user’s playspace.</para>
|
||||
/// </remarks>
|
||||
public Transform stage {
|
||||
get {
|
||||
return _stage == null ? transform.parent : _stage;
|
||||
}
|
||||
set {
|
||||
if (value == null)
|
||||
{
|
||||
Debug.LogWarning("LIV: Stage cannot be null!");
|
||||
}
|
||||
|
||||
if (_stage != value)
|
||||
{
|
||||
_stageCandidate = value;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.STAGE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use stage instead")]
|
||||
public Transform trackedSpaceOrigin {
|
||||
get {
|
||||
return stage;
|
||||
}
|
||||
set {
|
||||
stage = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix4x4 stageLocalToWorldMatrix {
|
||||
get {
|
||||
return (stage != null) ? stage.localToWorldMatrix : Matrix4x4.identity;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix4x4 stageWorldToLocalMatrix {
|
||||
get {
|
||||
return (stage != null) ? stage.worldToLocalMatrix : Matrix4x4.identity;
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("This transform is an additional wrapper to the user’s playspace.")]
|
||||
[FormerlySerializedAs("StageTransform")]
|
||||
[SerializeField] Transform _stageTransform = null;
|
||||
/// <summary>
|
||||
/// This transform is an additional wrapper to the user’s playspace.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>It allows for user-controlled transformations for special camera effects & transitions.</para>
|
||||
/// <para>If a creator is using a static camera, this transformation can give the illusion of camera movement.</para>
|
||||
/// </remarks>
|
||||
public Transform stageTransform {
|
||||
get {
|
||||
return _stageTransform;
|
||||
}
|
||||
set {
|
||||
_stageTransform = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("This is the camera responsible for rendering the user’s HMD.")]
|
||||
[FormerlySerializedAs("HMDCamera")]
|
||||
[SerializeField] Camera _HMDCamera = null;
|
||||
/// <summary>
|
||||
/// This is the camera responsible for rendering the user’s HMD.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The LIV SDK, by default clones this object to match your application’s rendering setup.</para>
|
||||
/// <para>You can use your own camera prefab should you want to!</para>
|
||||
/// </remarks>
|
||||
public Camera HMDCamera {
|
||||
get {
|
||||
return _HMDCamera;
|
||||
}
|
||||
set {
|
||||
if (value == null)
|
||||
{
|
||||
Debug.LogWarning("LIV: HMD Camera cannot be null!");
|
||||
}
|
||||
|
||||
if (_HMDCamera != value)
|
||||
{
|
||||
_HMDCameraCandidate = value;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.HMD_CAMERA, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("Camera prefab for customized rendering.")]
|
||||
[FormerlySerializedAs("MRCameraPrefab")]
|
||||
[SerializeField] Camera _MRCameraPrefab = null;
|
||||
/// <summary>
|
||||
/// Camera prefab for customized rendering.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>By default, LIV uses the HMD camera as a reference for the Mixed Reality camera.</para>
|
||||
/// <para>It is cloned and set up as a Mixed Reality camera.This approach works for most apps.</para>
|
||||
/// <para>However, some games can experience issues because of custom MonoBehaviours attached to this camera.</para>
|
||||
/// <para>You can use a custom camera prefab for those cases.</para>
|
||||
/// </remarks>
|
||||
public Camera MRCameraPrefab {
|
||||
get {
|
||||
return _MRCameraPrefab;
|
||||
}
|
||||
set {
|
||||
if (_MRCameraPrefab != value)
|
||||
{
|
||||
_MRCameraPrefabCandidate = value;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.MR_CAMERA_PREFAB, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("This option disables all standard Unity assets for the Mixed Reality rendering.")]
|
||||
[FormerlySerializedAs("DisableStandardAssets")]
|
||||
[SerializeField] bool _disableStandardAssets = false;
|
||||
/// <summary>
|
||||
/// This option disables all standard Unity assets for the Mixed Reality rendering.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Unity’s standard assets can interfere with the alpha channel that LIV needs to composite MR correctly.</para>
|
||||
/// </remarks>
|
||||
public bool disableStandardAssets {
|
||||
get {
|
||||
return _disableStandardAssets;
|
||||
}
|
||||
set {
|
||||
_disableStandardAssets = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("The layer mask defines exactly which object layers should be rendered in MR.")]
|
||||
[FormerlySerializedAs("SpectatorLayerMask")]
|
||||
[SerializeField] LayerMask _spectatorLayerMask = ~0;
|
||||
/// <summary>
|
||||
/// The layer mask defines exactly which object layers should be rendered in MR.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>You should use this to hide any in-game avatar that you’re using.</para>
|
||||
/// <para>LIV is meant to include the user’s body for you!</para>
|
||||
/// <para>Certain HMD-based effects should be disabled here too.</para>
|
||||
/// <para>Also, this can be used to render special effects or additional UI only to the MR camera.</para>
|
||||
/// <para>Useful for showing the player’s health, or current score!</para>
|
||||
/// </remarks>
|
||||
public LayerMask spectatorLayerMask {
|
||||
get {
|
||||
return _spectatorLayerMask;
|
||||
}
|
||||
set {
|
||||
_spectatorLayerMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("This is for removing unwanted scripts from the cloned MR camera.")]
|
||||
[FormerlySerializedAs("ExcludeBehaviours")]
|
||||
[SerializeField]
|
||||
string[] _excludeBehaviours = new string[] {
|
||||
"AudioListener",
|
||||
"Collider",
|
||||
"SteamVR_Camera",
|
||||
"SteamVR_Fade",
|
||||
"SteamVR_ExternalCamera"
|
||||
};
|
||||
/// <summary>
|
||||
/// This is for removing unwanted scripts from the cloned MR camera.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>By default, we remove the AudioListener, Colliders and SteamVR scripts, as these are not necessary for rendering MR!</para>
|
||||
/// <para>The excluded string must match the name of the MonoBehaviour.</para>
|
||||
/// </remarks>
|
||||
public string[] excludeBehaviours {
|
||||
get {
|
||||
return _excludeBehaviours;
|
||||
}
|
||||
set {
|
||||
if (_excludeBehaviours != value)
|
||||
{
|
||||
_excludeBehavioursCandidate = value;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.EXCLUDE_BEHAVIOURS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Recovers corrupted alpha channel when using post-effects.
|
||||
/// </summary>
|
||||
///
|
||||
[Tooltip("Recovers corrupted alpha channel when using post-effects.")]
|
||||
[FormerlySerializedAs("FixPostEffectsAlpha")]
|
||||
[SerializeField]
|
||||
private bool _fixPostEffectsAlpha = false;
|
||||
public bool fixPostEffectsAlpha {
|
||||
get {
|
||||
return _fixPostEffectsAlpha;
|
||||
}
|
||||
set {
|
||||
_fixPostEffectsAlpha = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the curret LIV SDK setup valid.
|
||||
/// </summary>
|
||||
public bool isValid {
|
||||
get {
|
||||
if (_invalidate != INVALIDATION_FLAGS.NONE) return false;
|
||||
|
||||
if (_HMDCamera == null)
|
||||
{
|
||||
Debug.LogError("LIV: HMD Camera is a required parameter!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_stage == null)
|
||||
{
|
||||
Debug.LogWarning("LIV: Tracked space origin should be assigned!");
|
||||
}
|
||||
|
||||
if (_spectatorLayerMask == 0)
|
||||
{
|
||||
Debug.LogWarning("LIV: The spectator layer mask is set to not show anything. Is this correct?");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isActive = false;
|
||||
/// <summary>
|
||||
/// Is the LIV SDK currently active.
|
||||
/// </summary>
|
||||
public bool isActive {
|
||||
get {
|
||||
return _isActive;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isReady {
|
||||
get {
|
||||
return isValid && _enabled && SDKBridge.IsActive;
|
||||
}
|
||||
}
|
||||
|
||||
private SDKRender _render = null;
|
||||
|
||||
/// <summary>
|
||||
/// Script responsible for the MR rendering.
|
||||
/// </summary>
|
||||
public SDKRender render { get { return _render; } }
|
||||
|
||||
private bool _wasReady = false;
|
||||
|
||||
private INVALIDATION_FLAGS _invalidate = INVALIDATION_FLAGS.NONE;
|
||||
private Transform _stageCandidate = null;
|
||||
private Camera _HMDCameraCandidate = null;
|
||||
private Camera _MRCameraPrefabCandidate = null;
|
||||
private string[] _excludeBehavioursCandidate = null;
|
||||
|
||||
private bool _enabled = false;
|
||||
private Coroutine _waitForEndOfFrameCoroutine;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_enabled = true;
|
||||
UpdateSDKReady();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
UpdateSDKReady();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
_enabled = false;
|
||||
UpdateSDKReady();
|
||||
}
|
||||
|
||||
IEnumerator WaitForUnityEndOfFrame()
|
||||
{
|
||||
while (Application.isPlaying && enabled)
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
if (isActive)
|
||||
{
|
||||
_render.Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateSDKReady()
|
||||
{
|
||||
bool ready = _isReady;
|
||||
if (ready != _wasReady)
|
||||
{
|
||||
OnSDKReadyChanged(ready);
|
||||
_wasReady = ready;
|
||||
}
|
||||
}
|
||||
|
||||
void OnSDKReadyChanged(bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
OnSDKActivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnSDKDeactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void OnSDKActivate()
|
||||
{
|
||||
Debug.Log("LIV: Compositor connected, setting up Mixed Reality!");
|
||||
SubmitSDKOutput();
|
||||
CreateAssets();
|
||||
StartRenderCoroutine();
|
||||
_isActive = true;
|
||||
if (onActivate != null) onActivate.Invoke();
|
||||
}
|
||||
|
||||
void OnSDKDeactivate()
|
||||
{
|
||||
Debug.Log("LIV: Compositor disconnected, cleaning up Mixed Reality.");
|
||||
if (onDeactivate != null) onDeactivate.Invoke();
|
||||
StopRenderCoroutine();
|
||||
DestroyAssets();
|
||||
_isActive = false;
|
||||
}
|
||||
|
||||
void CreateAssets()
|
||||
{
|
||||
DestroyAssets();
|
||||
_render = new SDKRender(this);
|
||||
}
|
||||
|
||||
void DestroyAssets()
|
||||
{
|
||||
if (_render != null)
|
||||
{
|
||||
_render.Dispose();
|
||||
_render = null;
|
||||
}
|
||||
}
|
||||
|
||||
void StartRenderCoroutine()
|
||||
{
|
||||
StopRenderCoroutine();
|
||||
_waitForEndOfFrameCoroutine = StartCoroutine(WaitForUnityEndOfFrame());
|
||||
}
|
||||
|
||||
void StopRenderCoroutine()
|
||||
{
|
||||
if (_waitForEndOfFrameCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_waitForEndOfFrameCoroutine);
|
||||
_waitForEndOfFrameCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
void SubmitSDKOutput()
|
||||
{
|
||||
SDKApplicationOutput output = SDKApplicationOutput.empty;
|
||||
output.supportedFeatures = FEATURES.BACKGROUND_RENDER |
|
||||
FEATURES.FOREGROUND_RENDER |
|
||||
FEATURES.OVERRIDE_POST_PROCESSING |
|
||||
FEATURES.FIX_FOREGROUND_ALPHA;
|
||||
|
||||
output.sdkID = SDKConstants.SDK_ID;
|
||||
output.sdkVersion = SDKConstants.SDK_VERSION;
|
||||
output.engineName = SDKConstants.ENGINE_NAME;
|
||||
output.engineVersion = Application.unityVersion;
|
||||
output.applicationName = Application.productName;
|
||||
output.applicationVersion = Application.version;
|
||||
output.graphicsAPI = SystemInfo.graphicsDeviceType.ToString();
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
output.xrDeviceName = XRSettings.loadedDeviceName;
|
||||
#endif
|
||||
SDKBridge.SubmitApplicationOutput(output);
|
||||
}
|
||||
|
||||
void Invalidate()
|
||||
{
|
||||
if (SDKUtils.ContainsFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.STAGE))
|
||||
{
|
||||
_stage = _stageCandidate;
|
||||
_stageCandidate = null;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.STAGE, false);
|
||||
}
|
||||
|
||||
if (SDKUtils.ContainsFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.HMD_CAMERA))
|
||||
{
|
||||
_HMDCamera = _HMDCameraCandidate;
|
||||
_HMDCameraCandidate = null;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.HMD_CAMERA, false);
|
||||
}
|
||||
|
||||
if (SDKUtils.ContainsFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.MR_CAMERA_PREFAB))
|
||||
{
|
||||
_MRCameraPrefab = _MRCameraPrefabCandidate;
|
||||
_MRCameraPrefabCandidate = null;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.MR_CAMERA_PREFAB, false);
|
||||
}
|
||||
|
||||
if (SDKUtils.ContainsFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.EXCLUDE_BEHAVIOURS))
|
||||
{
|
||||
_excludeBehaviours = _excludeBehavioursCandidate;
|
||||
_excludeBehavioursCandidate = null;
|
||||
_invalidate = (INVALIDATION_FLAGS)SDKUtils.SetFlag((uint)_invalidate, (uint)INVALIDATION_FLAGS.EXCLUDE_BEHAVIOURS, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
366
Assets/LIV/Scripts/SDKBridge.cs
Normal file
366
Assets/LIV/Scripts/SDKBridge.cs
Normal file
@ -0,0 +1,366 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public static class SDKBridge
|
||||
{
|
||||
#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) && UNITY_64
|
||||
#region Interop
|
||||
|
||||
[DllImport("LIV_Bridge")]
|
||||
static extern IntPtr GetRenderEventFunc();
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "LivCaptureIsActive")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
static extern bool GetIsCaptureActive();
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "LivCaptureWidth")]
|
||||
static extern int GetTextureWidth();
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "LivCaptureHeight")]
|
||||
static extern int GetTextureHeight();
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "LivCaptureSetTextureFromUnity")]
|
||||
static extern void SetTexture(IntPtr texture);
|
||||
|
||||
//// Acquire a frame from the compositor, allowing atomic access to its properties - most current one by default
|
||||
[DllImport("LIV_Bridge", EntryPoint = "AcquireCompositorFrame")]
|
||||
public static extern int AcquireCompositorFrame(ulong timestamp);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "ReleaseCompositorFrame")]
|
||||
public static extern int ReleaseCompositorFrame();
|
||||
|
||||
// Get timestamp of SDK2 object (C# timestamp) - must be an object in the bridge, not a copy.
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetObjectTimeStamp")]
|
||||
public static extern ulong GetObjectTimeStamp(IntPtr obj);
|
||||
|
||||
// Get current time in C# ticks
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetCurrentTimeTicks")]
|
||||
static extern ulong GetCurrentTimeTicks();
|
||||
|
||||
// Get object tag of SDK2 object - must be an object in the bridge, not a copy.
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetObjectTag")]
|
||||
public static extern ulong GetObjectTag(IntPtr obj);
|
||||
|
||||
// Get a frame object from the compositor
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetCompositorFrameObject")]
|
||||
public static extern IntPtr GetCompositorFrameObject(ulong tag);
|
||||
|
||||
// Get a frame object from the compositor
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetViewportTexture")]
|
||||
public static extern IntPtr GetViewportTexture();
|
||||
|
||||
// Get a channel object from the compositor
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetCompositorChannelObject")]
|
||||
public static extern IntPtr GetCompositorChannelObject(int slot, ulong tag, ulong timestamp);
|
||||
|
||||
// Get a channel object from our own source channel
|
||||
[DllImport("LIV_Bridge", EntryPoint = "GetChannelObject")]
|
||||
public static extern IntPtr GetChannelObject(int slot, ulong tag, ulong timestamp);
|
||||
|
||||
// Write an object to our channel
|
||||
[DllImport("LIV_Bridge", EntryPoint = "AddObjectToChannel")]
|
||||
public static extern int AddObjectToChannel(int slot, IntPtr obj, int objectsize, ulong tag);
|
||||
|
||||
// Write an object to the compostor's channel
|
||||
[DllImport("LIV_Bridge", EntryPoint = "AddObjectToCompositorChannel")]
|
||||
public static extern int AddObjectToCompositorChannel(int slot, IntPtr obj, int objectsize, ulong tag);
|
||||
|
||||
// Add a structure/object to the current frame / Considering if its simpler to combine with AddObjectToChannel with 0 being the frame
|
||||
[DllImport("LIV_Bridge", EntryPoint = "AddObjectToFrame")]
|
||||
public static extern int AddObjectToFrame(IntPtr obj, int objectsize, ulong tag);
|
||||
|
||||
// Helper to add strings
|
||||
[DllImport("LIV_Bridge", EntryPoint = "AddObjectToFrame")]
|
||||
public static extern int AddStringToFrame(IntPtr str, ulong tag);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "AddStringToChannel")]
|
||||
public static extern int AddStringToChannel(int slot, IntPtr str, int length, ulong tag);
|
||||
|
||||
// Create a new frame for rendering / native code does this already - so probably don't use
|
||||
[DllImport("LIV_Bridge", EntryPoint = "NewFrame")]
|
||||
public static extern int NewFrame();
|
||||
|
||||
// Commit the frame early - not recommended - best to let the next NewFrame commit the frame to avoid pipeline stalls
|
||||
[DllImport("LIV_Bridge", EntryPoint = "CommitFrame")]
|
||||
public static extern IntPtr CommitFrame();
|
||||
|
||||
// Add a copy of a unity texture to the bridge
|
||||
[DllImport("LIV_Bridge", EntryPoint = "addsharedtexture")]
|
||||
public static extern int addsharedtexture(int width, int height, int format, IntPtr sourcetexture, ulong tag);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "addtexture")]
|
||||
public static extern int addtexture(IntPtr sourcetexture, ulong tag);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "PublishTextures")]
|
||||
public static extern void PublishTextures();
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "updateinputframe")]
|
||||
public static extern IntPtr updatinputframe(IntPtr InputFrame);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "setinputframe")]
|
||||
public static extern IntPtr setinputframe(float x, float y, float z, float q0, float q1, float q2, float q3, float fov, int priority);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "setfeature")]
|
||||
public static extern ulong setfeature(ulong feature);
|
||||
|
||||
[DllImport("LIV_Bridge", EntryPoint = "clearfeature")]
|
||||
public static extern ulong clearfeature(ulong feature);
|
||||
#endregion
|
||||
#else
|
||||
public static int AddStringToChannel(int slot, IntPtr str, int length, ulong tag) { return -2; }
|
||||
public static int addtexture(IntPtr sourcetexture, ulong tag) { return -2; }
|
||||
public static ulong GetObjectTimeStamp(IntPtr obj) { return 0; }
|
||||
public static ulong GetCurrentTimeTicks() { return 0; }
|
||||
static bool GetIsCaptureActive() { return false; }
|
||||
public static IntPtr GetRenderEventFunc() { return IntPtr.Zero; }
|
||||
public static IntPtr GetCompositorChannelObject(int slot, ulong tag, ulong timestamp) { return IntPtr.Zero; }
|
||||
public static int AddObjectToCompositorChannel(int slot, IntPtr obj, int objectsize, ulong tag) { return -2; }
|
||||
public static int AddObjectToFrame(IntPtr obj, int objectsize, ulong tag) { return -2; }
|
||||
public static IntPtr updatinputframe(IntPtr InputFrame) { return IntPtr.Zero; }
|
||||
public static IntPtr GetViewportTexture() { return IntPtr.Zero; }
|
||||
public static IntPtr GetChannelObject(int slot, ulong tag, ulong timestamp) { return IntPtr.Zero; }
|
||||
public static int AddObjectToChannel(int slot, IntPtr obj, int objectsize, ulong tag) { return -2; }
|
||||
#endif
|
||||
|
||||
public struct SDKInjection<T>
|
||||
{
|
||||
public bool active;
|
||||
public System.Action action;
|
||||
public T data;
|
||||
}
|
||||
|
||||
static SDKInjection<SDKInputFrame> _injection_SDKInputFrame = new SDKInjection<SDKInputFrame>()
|
||||
{
|
||||
active = false,
|
||||
action = null,
|
||||
data = SDKInputFrame.empty
|
||||
};
|
||||
|
||||
static SDKInjection<SDKResolution> _injection_SDKResolution = new SDKInjection<SDKResolution>()
|
||||
{
|
||||
active = false,
|
||||
action = null,
|
||||
data = SDKResolution.zero
|
||||
};
|
||||
|
||||
static SDKInjection<bool> _injection_IsActive = new SDKInjection<bool>()
|
||||
{
|
||||
active = false,
|
||||
action = null,
|
||||
data = false
|
||||
};
|
||||
|
||||
static bool _injection_DisableSubmit = false;
|
||||
static bool _injection_DisableSubmitApplicationOutput = false;
|
||||
static bool _injection_DisableAddTexture = false;
|
||||
static bool _injection_DisableCreateFrame = false;
|
||||
|
||||
// Get the tag code for a string - won't win any awards - pre-compute these and use constants.
|
||||
public static ulong Tag(string str)
|
||||
{
|
||||
ulong tag = 0;
|
||||
for (int i = 0; i < str.Length; i++)
|
||||
{
|
||||
if (i == 8) break;
|
||||
char c = str[i];
|
||||
tag |= (((ulong)(c & 255)) << (i * 8));
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static void AddString(string tag, string value, int slot)
|
||||
{
|
||||
var utf8 = Encoding.UTF8;
|
||||
byte[] utfBytes = utf8.GetBytes(value);
|
||||
GCHandle gch = GCHandle.Alloc(utfBytes, GCHandleType.Pinned);
|
||||
AddStringToChannel(slot, Marshal.UnsafeAddrOfPinnedArrayElement(utfBytes, 0), utfBytes.Length, Tag(tag));
|
||||
gch.Free();
|
||||
}
|
||||
|
||||
public static void AddTexture(SDKTexture texture, ulong tag)
|
||||
{
|
||||
GCHandle gch = GCHandle.Alloc(texture, GCHandleType.Pinned);
|
||||
addtexture(gch.AddrOfPinnedObject(), tag);
|
||||
gch.Free();
|
||||
}
|
||||
|
||||
public static ulong GetObjectTime(IntPtr objectptr)
|
||||
{
|
||||
return GetObjectTimeStamp(objectptr) + 621355968000000000;
|
||||
}
|
||||
|
||||
public static ulong GetCurrentTime()
|
||||
{
|
||||
return GetCurrentTimeTicks() + 621355968000000000;
|
||||
}
|
||||
|
||||
public static bool IsActive {
|
||||
get {
|
||||
if (_injection_IsActive.active)
|
||||
{
|
||||
return _injection_IsActive.data;
|
||||
}
|
||||
return GetIsCaptureActive();
|
||||
}
|
||||
}
|
||||
|
||||
public static void IssuePluginEvent()
|
||||
{
|
||||
if (_injection_DisableSubmit) return;
|
||||
GL.IssuePluginEvent(GetRenderEventFunc(), 2);
|
||||
}
|
||||
|
||||
public static void SubmitApplicationOutput(SDKApplicationOutput applicationOutput)
|
||||
{
|
||||
if (_injection_DisableSubmitApplicationOutput) return;
|
||||
AddString("APPNAME", applicationOutput.applicationName, 5);
|
||||
AddString("APPVER", applicationOutput.applicationVersion, 5);
|
||||
AddString("ENGNAME", applicationOutput.engineName, 5);
|
||||
AddString("ENGVER", applicationOutput.engineVersion, 5);
|
||||
AddString("GFXAPI", applicationOutput.graphicsAPI, 5);
|
||||
AddString("SDKID", applicationOutput.sdkID, 5);
|
||||
AddString("SDKVER", applicationOutput.sdkVersion, 5);
|
||||
AddString("SUPPORT", applicationOutput.supportedFeatures.ToString(), 5);
|
||||
AddString("XRNAME", applicationOutput.xrDeviceName, 5);
|
||||
}
|
||||
|
||||
public static bool GetStructFromGlobalChannel <T> ( ref T mystruct, int channel, ulong tag)
|
||||
{
|
||||
IntPtr structPtr = GetCompositorChannelObject(channel, tag, UInt64.MaxValue);
|
||||
if (structPtr == IntPtr.Zero) return false;
|
||||
mystruct= (T)Marshal.PtrToStructure(structPtr, typeof(T));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int AddStructToGlobalChannel<T>(ref T mystruct, int channel, ulong tag)
|
||||
{
|
||||
GCHandle gch = GCHandle.Alloc(mystruct, GCHandleType.Pinned);
|
||||
int output = AddObjectToCompositorChannel(channel, gch.AddrOfPinnedObject(), Marshal.SizeOf(mystruct), tag);
|
||||
gch.Free();
|
||||
return output;
|
||||
}
|
||||
|
||||
public static bool GetStructFromLocalChannel<T>(ref T mystruct, int channel, ulong tag)
|
||||
{
|
||||
IntPtr structPtr = GetChannelObject(channel, tag, UInt64.MaxValue);
|
||||
if (structPtr == IntPtr.Zero) return false;
|
||||
mystruct = (T)Marshal.PtrToStructure(structPtr, typeof(T));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int AddStructToLocalChannel<T>(ref T mystruct, int channel, ulong tag)
|
||||
{
|
||||
GCHandle gch = GCHandle.Alloc(mystruct, GCHandleType.Pinned);
|
||||
int output = AddObjectToChannel(channel, gch.AddrOfPinnedObject(), Marshal.SizeOf(mystruct), tag);
|
||||
gch.Free();
|
||||
return output;
|
||||
}
|
||||
|
||||
// Add ANY structure to the current frame
|
||||
public static void AddStructToFrame<T>(ref T mystruct, ulong tag)
|
||||
{
|
||||
GCHandle gch = GCHandle.Alloc(mystruct, GCHandleType.Pinned);
|
||||
AddObjectToFrame(gch.AddrOfPinnedObject(), Marshal.SizeOf(mystruct), tag);
|
||||
gch.Free();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the master pose sent to ALL applications.
|
||||
///
|
||||
/// when called initialy, having the flags set to 0 will return the current pose (which includes resolution - which you might need)
|
||||
/// If you wish to change the pose, change the parts of the structures you need to, and set the appropriate flag to update.
|
||||
/// atm, the flags will be for Pose, Stage, Clipping Plane, and resolution.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="setframe"></param>
|
||||
/// <returns>The current pose - could be yours, someone elses, or a combination</returns>
|
||||
|
||||
public static bool UpdateInputFrame(ref SDKInputFrame setframe)
|
||||
{
|
||||
if (_injection_SDKInputFrame.active && _injection_SDKInputFrame.action != null)
|
||||
{
|
||||
_injection_SDKInputFrame.action.Invoke();
|
||||
setframe = _injection_SDKInputFrame.data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pin the object briefly so we can send it to the API without it being accidentally garbage collected
|
||||
GCHandle gch = GCHandle.Alloc(setframe, GCHandleType.Pinned);
|
||||
IntPtr structPtr = updatinputframe(gch.AddrOfPinnedObject());
|
||||
gch.Free();
|
||||
|
||||
if (structPtr == IntPtr.Zero)
|
||||
{
|
||||
setframe = SDKInputFrame.empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
setframe = (SDKInputFrame)Marshal.PtrToStructure(structPtr, typeof(SDKInputFrame));
|
||||
_injection_SDKInputFrame.data = setframe;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static SDKTexture GetViewfinderTexture()
|
||||
{
|
||||
SDKTexture overlaytexture = SDKTexture.empty;
|
||||
IntPtr structPtr = GetCompositorChannelObject(11, Tag("OUTTEX"), UInt64.MaxValue);
|
||||
if (structPtr == IntPtr.Zero) return new SDKTexture();
|
||||
overlaytexture = (SDKTexture)Marshal.PtrToStructure(structPtr, typeof(SDKTexture));
|
||||
return overlaytexture;
|
||||
}
|
||||
|
||||
public static void AddTexture(SDKTexture texture)
|
||||
{
|
||||
if (_injection_DisableAddTexture) return;
|
||||
string tag = "";
|
||||
switch (texture.id)
|
||||
{
|
||||
case TEXTURE_ID.BACKGROUND_COLOR_BUFFER_ID:
|
||||
tag = "BGCTEX";
|
||||
break;
|
||||
case TEXTURE_ID.FOREGROUND_COLOR_BUFFER_ID:
|
||||
tag = "FGCTEX";
|
||||
break;
|
||||
case TEXTURE_ID.OPTIMIZED_COLOR_BUFFER_ID:
|
||||
tag = "OPTTEX";
|
||||
break;
|
||||
}
|
||||
AddTexture(texture, Tag(tag));
|
||||
}
|
||||
|
||||
public static void CreateFrame(SDKOutputFrame frame)
|
||||
{
|
||||
if (_injection_DisableCreateFrame) return;
|
||||
GCHandle gch = GCHandle.Alloc(frame, GCHandleType.Pinned);
|
||||
AddObjectToFrame(gch.AddrOfPinnedObject(), Marshal.SizeOf(frame), Tag("OUTFRAME"));
|
||||
gch.Free();
|
||||
}
|
||||
|
||||
public static void SetGroundPlane(SDKPlane groundPlane)
|
||||
{
|
||||
AddStructToGlobalChannel<SDKPlane>(ref groundPlane, 2, SDKBridge.Tag("SetGND"));
|
||||
}
|
||||
|
||||
public static bool GetResolution(ref SDKResolution sdkResolution)
|
||||
{
|
||||
if(_injection_SDKResolution.active && _injection_SDKResolution.action != null)
|
||||
{
|
||||
_injection_SDKResolution.action.Invoke();
|
||||
sdkResolution = _injection_SDKResolution.data;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool output = GetStructFromLocalChannel<SDKResolution>(ref sdkResolution, 15, SDKBridge.Tag("SDKRes"));
|
||||
_injection_SDKResolution.data = sdkResolution;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
456
Assets/LIV/Scripts/SDKRender.cs
Normal file
456
Assets/LIV/Scripts/SDKRender.cs
Normal file
@ -0,0 +1,456 @@
|
||||
#if !LIV_UNIVERSAL_RENDER
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public partial class SDKRender : System.IDisposable
|
||||
{
|
||||
// Renders the clip plane in the foreground texture
|
||||
private CommandBuffer _clipPlaneCommandBuffer = null;
|
||||
// Renders the clipped opaque content in to the foreground texture alpha
|
||||
private CommandBuffer _combineAlphaCommandBuffer = null;
|
||||
// Captures texture before post-effects
|
||||
private CommandBuffer _captureTextureCommandBuffer = null;
|
||||
// Renders captured texture
|
||||
private CommandBuffer _applyTextureCommandBuffer = null;
|
||||
// Renders background and foreground in single render
|
||||
private CommandBuffer _optimizedRenderingCommandBuffer = null;
|
||||
|
||||
private CameraEvent _clipPlaneCameraEvent = CameraEvent.AfterForwardOpaque;
|
||||
private CameraEvent _clipPlaneCombineAlphaCameraEvent = CameraEvent.AfterEverything;
|
||||
private CameraEvent _captureTextureEvent = CameraEvent.BeforeImageEffects;
|
||||
private CameraEvent _applyTextureEvent = CameraEvent.AfterEverything;
|
||||
private CameraEvent _optimizedRenderingCameraEvent = CameraEvent.AfterEverything;
|
||||
|
||||
// Tessellated quad
|
||||
private Mesh _clipPlaneMesh = null;
|
||||
// Clear material
|
||||
private Material _clipPlaneSimpleMaterial = null;
|
||||
// Transparent material for visual debugging
|
||||
private Material _clipPlaneSimpleDebugMaterial = null;
|
||||
// Tessellated height map clear material
|
||||
private Material _clipPlaneComplexMaterial = null;
|
||||
// Tessellated height map clear material for visual debugging
|
||||
private Material _clipPlaneComplexDebugMaterial = null;
|
||||
private Material _writeOpaqueToAlphaMaterial = null;
|
||||
private Material _combineAlphaMaterial = null;
|
||||
private Material _writeMaterial = null;
|
||||
private Material _forceForwardRenderingMaterial = null;
|
||||
|
||||
private RenderTexture _backgroundRenderTexture = null;
|
||||
private RenderTexture _foregroundRenderTexture = null;
|
||||
private RenderTexture _optimizedRenderTexture = null;
|
||||
private RenderTexture _complexClipPlaneRenderTexture = null;
|
||||
|
||||
Material GetClipPlaneMaterial(bool debugClipPlane, bool complexClipPlane, ColorWriteMask colorWriteMask)
|
||||
{
|
||||
Material output;
|
||||
|
||||
if (complexClipPlane)
|
||||
{
|
||||
output = debugClipPlane ? _clipPlaneComplexDebugMaterial : _clipPlaneComplexMaterial;
|
||||
output.SetTexture(SDKShaders.LIV_CLIP_PLANE_HEIGHT_MAP_PROPERTY, _complexClipPlaneRenderTexture);
|
||||
output.SetFloat(SDKShaders.LIV_TESSELLATION_PROPERTY, _inputFrame.clipPlane.tesselation);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = debugClipPlane ? _clipPlaneSimpleDebugMaterial : _clipPlaneSimpleMaterial;
|
||||
}
|
||||
|
||||
output.SetInt(SDKShaders.LIV_COLOR_MASK, (int)colorWriteMask);
|
||||
return output;
|
||||
}
|
||||
|
||||
Material GetGroundClipPlaneMaterial(bool debugClipPlane, ColorWriteMask colorWriteMask)
|
||||
{
|
||||
Material output;
|
||||
output = debugClipPlane ? _clipPlaneSimpleDebugMaterial : _clipPlaneSimpleMaterial;
|
||||
output.SetInt(SDKShaders.LIV_COLOR_MASK, (int)colorWriteMask);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool useDeferredRendering {
|
||||
get {
|
||||
return _cameraInstance.actualRenderingPath == RenderingPath.DeferredLighting ||
|
||||
_cameraInstance.actualRenderingPath == RenderingPath.DeferredShading;
|
||||
}
|
||||
}
|
||||
|
||||
bool interlacedRendering {
|
||||
get {
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.INTERLACED_RENDER);
|
||||
}
|
||||
}
|
||||
|
||||
bool canRenderBackground {
|
||||
get {
|
||||
if (interlacedRendering)
|
||||
{
|
||||
// Render only if frame is even
|
||||
if (Time.frameCount % 2 != 0) return false;
|
||||
}
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.BACKGROUND_RENDER) && _backgroundRenderTexture != null;
|
||||
}
|
||||
}
|
||||
|
||||
bool canRenderForeground {
|
||||
get {
|
||||
if (interlacedRendering)
|
||||
{
|
||||
// Render only if frame is odd
|
||||
if (Time.frameCount % 2 != 1) return false;
|
||||
}
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.FOREGROUND_RENDER) && _foregroundRenderTexture != null;
|
||||
}
|
||||
}
|
||||
|
||||
bool canRenderOptimized {
|
||||
get {
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OPTIMIZED_RENDER) && _optimizedRenderTexture != null; ;
|
||||
}
|
||||
}
|
||||
|
||||
public SDKRender(LIV liv)
|
||||
{
|
||||
_liv = liv;
|
||||
CreateAssets();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
UpdateBridgeResolution();
|
||||
UpdateBridgeInputFrame();
|
||||
SDKUtils.ApplyUserSpaceTransform(this);
|
||||
UpdateTextures();
|
||||
InvokePreRender();
|
||||
if (canRenderBackground) RenderBackground();
|
||||
if (canRenderForeground) RenderForeground();
|
||||
if (canRenderOptimized) RenderOptimized();
|
||||
IvokePostRender();
|
||||
SDKUtils.CreateBridgeOutputFrame(this);
|
||||
SDKBridge.IssuePluginEvent();
|
||||
}
|
||||
|
||||
// Default render without any special changes
|
||||
private void RenderBackground()
|
||||
{
|
||||
SDKUtils.SetCamera(_cameraInstance, _cameraInstance.transform, _inputFrame, localToWorldMatrix, spectatorLayerMask);
|
||||
_cameraInstance.targetTexture = _backgroundRenderTexture;
|
||||
|
||||
RenderTexture tempRenderTexture = null;
|
||||
|
||||
bool overridePostProcessing = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OVERRIDE_POST_PROCESSING);
|
||||
if (overridePostProcessing)
|
||||
{
|
||||
tempRenderTexture = RenderTexture.GetTemporary(_backgroundRenderTexture.width, _backgroundRenderTexture.height, 0, _backgroundRenderTexture.format);
|
||||
#if UNITY_EDITOR
|
||||
tempRenderTexture.name = "LIV.TemporaryRenderTexture";
|
||||
#endif
|
||||
_captureTextureCommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, tempRenderTexture);
|
||||
_applyTextureCommandBuffer.Blit(tempRenderTexture, BuiltinRenderTextureType.CurrentActive);
|
||||
|
||||
_cameraInstance.AddCommandBuffer(_captureTextureEvent, _captureTextureCommandBuffer);
|
||||
_cameraInstance.AddCommandBuffer(_applyTextureEvent, _applyTextureCommandBuffer);
|
||||
}
|
||||
|
||||
SDKShaders.StartRendering();
|
||||
SDKShaders.StartBackgroundRendering();
|
||||
InvokePreRenderBackground();
|
||||
SendTextureToBridge(_backgroundRenderTexture, TEXTURE_ID.BACKGROUND_COLOR_BUFFER_ID);
|
||||
_cameraInstance.Render();
|
||||
InvokePostRenderBackground();
|
||||
_cameraInstance.targetTexture = null;
|
||||
SDKShaders.StopBackgroundRendering();
|
||||
SDKShaders.StopRendering();
|
||||
|
||||
if (overridePostProcessing)
|
||||
{
|
||||
_cameraInstance.RemoveCommandBuffer(_captureTextureEvent, _captureTextureCommandBuffer);
|
||||
_cameraInstance.RemoveCommandBuffer(_applyTextureEvent, _applyTextureCommandBuffer);
|
||||
|
||||
_captureTextureCommandBuffer.Clear();
|
||||
_applyTextureCommandBuffer.Clear();
|
||||
|
||||
RenderTexture.ReleaseTemporary(tempRenderTexture);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the image which is in front of our clip plane
|
||||
// The compositing is heavily relying on the alpha channel, therefore we want to make sure it does
|
||||
// not get corrupted by the postprocessing or any shader
|
||||
private void RenderForeground()
|
||||
{
|
||||
bool debugClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.DEBUG_CLIP_PLANE);
|
||||
bool renderComplexClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.COMPLEX_CLIP_PLANE);
|
||||
bool renderGroundClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.GROUND_CLIP_PLANE);
|
||||
bool overridePostProcessing = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OVERRIDE_POST_PROCESSING);
|
||||
bool fixPostEffectsAlpha = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.FIX_FOREGROUND_ALPHA) | _liv.fixPostEffectsAlpha;
|
||||
|
||||
MonoBehaviour[] behaviours = null;
|
||||
bool[] wasBehaviourEnabled = null;
|
||||
if (disableStandardAssets) SDKUtils.DisableStandardAssets(_cameraInstance, ref behaviours, ref wasBehaviourEnabled);
|
||||
|
||||
// Capture camera defaults
|
||||
CameraClearFlags capturedClearFlags = _cameraInstance.clearFlags;
|
||||
Color capturedBgColor = _cameraInstance.backgroundColor;
|
||||
Color capturedFogColor = RenderSettings.fogColor;
|
||||
|
||||
// Make sure that fog does not corrupt alpha channel
|
||||
RenderSettings.fogColor = new Color(capturedFogColor.r, capturedFogColor.g, capturedFogColor.b, 0f);
|
||||
SDKUtils.SetCamera(_cameraInstance, _cameraInstance.transform, _inputFrame, localToWorldMatrix, spectatorLayerMask);
|
||||
_cameraInstance.clearFlags = CameraClearFlags.Color;
|
||||
_cameraInstance.backgroundColor = Color.clear;
|
||||
_cameraInstance.targetTexture = _foregroundRenderTexture;
|
||||
|
||||
RenderTexture capturedAlphaRenderTexture = RenderTexture.GetTemporary(_foregroundRenderTexture.width, _foregroundRenderTexture.height, 0, _foregroundRenderTexture.format);
|
||||
#if UNITY_EDITOR
|
||||
capturedAlphaRenderTexture.name = "LIV.CapturedAlphaRenderTexture";
|
||||
#endif
|
||||
|
||||
// Render opaque pixels into alpha channel
|
||||
_clipPlaneCommandBuffer.DrawMesh(_clipPlaneMesh, Matrix4x4.identity, _writeOpaqueToAlphaMaterial, 0, 0);
|
||||
|
||||
// Render clip plane
|
||||
Matrix4x4 clipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.clipPlane.transform;
|
||||
_clipPlaneCommandBuffer.DrawMesh(_clipPlaneMesh, clipPlaneTransform,
|
||||
GetClipPlaneMaterial(debugClipPlane, renderComplexClipPlane, ColorWriteMask.All), 0, 0);
|
||||
|
||||
// Render ground clip plane
|
||||
if (renderGroundClipPlane)
|
||||
{
|
||||
Matrix4x4 groundClipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.groundClipPlane.transform;
|
||||
_clipPlaneCommandBuffer.DrawMesh(_clipPlaneMesh, groundClipPlaneTransform,
|
||||
GetGroundClipPlaneMaterial(debugClipPlane, ColorWriteMask.All), 0, 0);
|
||||
}
|
||||
|
||||
// Copy alpha in to texture
|
||||
_clipPlaneCommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, capturedAlphaRenderTexture);
|
||||
_cameraInstance.AddCommandBuffer(_clipPlaneCameraEvent, _clipPlaneCommandBuffer);
|
||||
|
||||
// Fix alpha corruption by post processing
|
||||
RenderTexture tempRenderTexture = null;
|
||||
if (overridePostProcessing || fixPostEffectsAlpha)
|
||||
{
|
||||
tempRenderTexture = RenderTexture.GetTemporary(_foregroundRenderTexture.width, _foregroundRenderTexture.height, 0, _foregroundRenderTexture.format);
|
||||
#if UNITY_EDITOR
|
||||
tempRenderTexture.name = "LIV.TemporaryRenderTexture";
|
||||
#endif
|
||||
_captureTextureCommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, tempRenderTexture);
|
||||
_cameraInstance.AddCommandBuffer(_captureTextureEvent, _captureTextureCommandBuffer);
|
||||
|
||||
_writeMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, overridePostProcessing ? (int)ColorWriteMask.All : (int)ColorWriteMask.Alpha);
|
||||
_applyTextureCommandBuffer.Blit(tempRenderTexture, BuiltinRenderTextureType.CurrentActive, _writeMaterial);
|
||||
_cameraInstance.AddCommandBuffer(_applyTextureEvent, _applyTextureCommandBuffer);
|
||||
}
|
||||
|
||||
// Combine captured alpha with result alpha
|
||||
_combineAlphaMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, (int)ColorWriteMask.Alpha);
|
||||
_combineAlphaCommandBuffer.Blit(capturedAlphaRenderTexture, BuiltinRenderTextureType.CurrentActive, _combineAlphaMaterial);
|
||||
_cameraInstance.AddCommandBuffer(_clipPlaneCombineAlphaCameraEvent, _combineAlphaCommandBuffer);
|
||||
|
||||
if (useDeferredRendering) SDKUtils.ForceForwardRendering(cameraInstance, _clipPlaneMesh, _forceForwardRenderingMaterial);
|
||||
|
||||
SDKShaders.StartRendering();
|
||||
SDKShaders.StartForegroundRendering();
|
||||
InvokePreRenderForeground();
|
||||
SendTextureToBridge(_foregroundRenderTexture, TEXTURE_ID.FOREGROUND_COLOR_BUFFER_ID);
|
||||
_cameraInstance.Render();
|
||||
InvokePostRenderForeground();
|
||||
_cameraInstance.targetTexture = null;
|
||||
SDKShaders.StopForegroundRendering();
|
||||
SDKShaders.StopRendering();
|
||||
|
||||
if (overridePostProcessing || fixPostEffectsAlpha)
|
||||
{
|
||||
_cameraInstance.RemoveCommandBuffer(_captureTextureEvent, _captureTextureCommandBuffer);
|
||||
_cameraInstance.RemoveCommandBuffer(_applyTextureEvent, _applyTextureCommandBuffer);
|
||||
|
||||
_captureTextureCommandBuffer.Clear();
|
||||
_applyTextureCommandBuffer.Clear();
|
||||
|
||||
RenderTexture.ReleaseTemporary(tempRenderTexture);
|
||||
}
|
||||
|
||||
_cameraInstance.RemoveCommandBuffer(_clipPlaneCameraEvent, _clipPlaneCommandBuffer);
|
||||
_cameraInstance.RemoveCommandBuffer(_clipPlaneCombineAlphaCameraEvent, _combineAlphaCommandBuffer);
|
||||
|
||||
RenderTexture.ReleaseTemporary(capturedAlphaRenderTexture);
|
||||
|
||||
_clipPlaneCommandBuffer.Clear();
|
||||
_combineAlphaCommandBuffer.Clear();
|
||||
|
||||
// Revert camera defaults
|
||||
_cameraInstance.clearFlags = capturedClearFlags;
|
||||
_cameraInstance.backgroundColor = capturedBgColor;
|
||||
RenderSettings.fogColor = capturedFogColor;
|
||||
|
||||
SDKUtils.RestoreStandardAssets(ref behaviours, ref wasBehaviourEnabled);
|
||||
}
|
||||
|
||||
// Renders a single camera in a single texture with occlusion only from opaque objects.
|
||||
// This is the most performant option for mixed reality.
|
||||
// It does not support any transparency in the foreground layer.
|
||||
private void RenderOptimized()
|
||||
{
|
||||
bool debugClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.DEBUG_CLIP_PLANE);
|
||||
bool renderComplexClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.COMPLEX_CLIP_PLANE);
|
||||
bool renderGroundClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.GROUND_CLIP_PLANE);
|
||||
|
||||
SDKUtils.SetCamera(_cameraInstance, _cameraInstance.transform, _inputFrame, localToWorldMatrix, spectatorLayerMask);
|
||||
_cameraInstance.targetTexture = _optimizedRenderTexture;
|
||||
|
||||
// Clear alpha channel
|
||||
_writeMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, (int)ColorWriteMask.Alpha);
|
||||
_optimizedRenderingCommandBuffer.Blit(BuiltinRenderTextureType.None, BuiltinRenderTextureType.CurrentActive, _writeMaterial);
|
||||
|
||||
// Render opaque pixels into alpha channel
|
||||
_writeOpaqueToAlphaMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, (int)ColorWriteMask.Alpha);
|
||||
_optimizedRenderingCommandBuffer.DrawMesh(_clipPlaneMesh, Matrix4x4.identity, _writeOpaqueToAlphaMaterial, 0, 0);
|
||||
|
||||
// Render clip plane
|
||||
Matrix4x4 clipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.clipPlane.transform;
|
||||
_optimizedRenderingCommandBuffer.DrawMesh(_clipPlaneMesh, clipPlaneTransform,
|
||||
GetClipPlaneMaterial(debugClipPlane, renderComplexClipPlane, ColorWriteMask.Alpha), 0, 0);
|
||||
|
||||
// Render ground clip plane
|
||||
if (renderGroundClipPlane)
|
||||
{
|
||||
Matrix4x4 groundClipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.groundClipPlane.transform;
|
||||
_optimizedRenderingCommandBuffer.DrawMesh(_clipPlaneMesh, groundClipPlaneTransform,
|
||||
GetGroundClipPlaneMaterial(debugClipPlane, ColorWriteMask.Alpha), 0, 0);
|
||||
}
|
||||
|
||||
_cameraInstance.AddCommandBuffer(CameraEvent.AfterEverything, _optimizedRenderingCommandBuffer);
|
||||
|
||||
// TODO: this is just proprietary
|
||||
SDKShaders.StartRendering();
|
||||
SDKShaders.StartBackgroundRendering();
|
||||
InvokePreRenderBackground();
|
||||
SendTextureToBridge(_optimizedRenderTexture, TEXTURE_ID.OPTIMIZED_COLOR_BUFFER_ID);
|
||||
_cameraInstance.Render();
|
||||
InvokePostRenderBackground();
|
||||
_cameraInstance.targetTexture = null;
|
||||
SDKShaders.StopBackgroundRendering();
|
||||
SDKShaders.StopRendering();
|
||||
|
||||
_cameraInstance.RemoveCommandBuffer(CameraEvent.AfterEverything, _optimizedRenderingCommandBuffer);
|
||||
_optimizedRenderingCommandBuffer.Clear();
|
||||
}
|
||||
|
||||
private void CreateAssets()
|
||||
{
|
||||
bool cameraReferenceEnabled = cameraReference.enabled;
|
||||
if (cameraReferenceEnabled)
|
||||
{
|
||||
cameraReference.enabled = false;
|
||||
}
|
||||
bool cameraReferenceActive = cameraReference.gameObject.activeSelf;
|
||||
if (cameraReferenceActive)
|
||||
{
|
||||
cameraReference.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
GameObject cloneGO = (GameObject)Object.Instantiate(cameraReference.gameObject, _liv.stage);
|
||||
_cameraInstance = (Camera)cloneGO.GetComponent("Camera");
|
||||
|
||||
SDKUtils.CleanCameraBehaviours(_cameraInstance, _liv.excludeBehaviours);
|
||||
|
||||
if (cameraReferenceActive != cameraReference.gameObject.activeSelf)
|
||||
{
|
||||
cameraReference.gameObject.SetActive(cameraReferenceActive);
|
||||
}
|
||||
if (cameraReferenceEnabled != cameraReference.enabled)
|
||||
{
|
||||
cameraReference.enabled = cameraReferenceEnabled;
|
||||
}
|
||||
|
||||
_cameraInstance.name = "LIV Camera";
|
||||
if (_cameraInstance.tag == "MainCamera")
|
||||
{
|
||||
_cameraInstance.tag = "Untagged";
|
||||
}
|
||||
|
||||
_cameraInstance.transform.localScale = Vector3.one;
|
||||
_cameraInstance.rect = new Rect(0, 0, 1, 1);
|
||||
_cameraInstance.depth = 0;
|
||||
#if UNITY_5_4_OR_NEWER
|
||||
_cameraInstance.stereoTargetEye = StereoTargetEyeMask.None;
|
||||
#endif
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
_cameraInstance.allowMSAA = false;
|
||||
#endif
|
||||
_cameraInstance.enabled = false;
|
||||
_cameraInstance.gameObject.SetActive(true);
|
||||
|
||||
_clipPlaneMesh = new Mesh();
|
||||
SDKUtils.CreateClipPlane(_clipPlaneMesh, 10, 10, true, 1000f);
|
||||
_clipPlaneSimpleMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_SIMPLE_SHADER));
|
||||
_clipPlaneSimpleDebugMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_SIMPLE_DEBUG_SHADER));
|
||||
_clipPlaneComplexMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_COMPLEX_SHADER));
|
||||
_clipPlaneComplexDebugMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_COMPLEX_DEBUG_SHADER));
|
||||
_writeOpaqueToAlphaMaterial = new Material(Shader.Find(SDKShaders.LIV_WRITE_OPAQUE_TO_ALPHA_SHADER));
|
||||
_combineAlphaMaterial = new Material(Shader.Find(SDKShaders.LIV_COMBINE_ALPHA_SHADER));
|
||||
_writeMaterial = new Material(Shader.Find(SDKShaders.LIV_WRITE_SHADER));
|
||||
_forceForwardRenderingMaterial = new Material(Shader.Find(SDKShaders.LIV_FORCE_FORWARD_RENDERING_SHADER));
|
||||
_clipPlaneCommandBuffer = new CommandBuffer();
|
||||
_combineAlphaCommandBuffer = new CommandBuffer();
|
||||
_captureTextureCommandBuffer = new CommandBuffer();
|
||||
_applyTextureCommandBuffer = new CommandBuffer();
|
||||
_optimizedRenderingCommandBuffer = new CommandBuffer();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
_clipPlaneMesh.name = "LIV.clipPlane";
|
||||
_clipPlaneSimpleMaterial.name = "LIV.clipPlaneSimple";
|
||||
_clipPlaneSimpleDebugMaterial.name = "LIV.clipPlaneSimpleDebug";
|
||||
_clipPlaneComplexMaterial.name = "LIV.clipPlaneComplex";
|
||||
_clipPlaneComplexDebugMaterial.name = "LIV.clipPlaneComplexDebug";
|
||||
_writeOpaqueToAlphaMaterial.name = "LIV.writeOpaqueToAlpha";
|
||||
_combineAlphaMaterial.name = "LIV.combineAlpha";
|
||||
_writeMaterial.name = "LIV.write";
|
||||
_forceForwardRenderingMaterial.name = "LIV.forceForwardRendering";
|
||||
_clipPlaneCommandBuffer.name = "LIV.renderClipPlanes";
|
||||
_combineAlphaCommandBuffer.name = "LIV.foregroundCombineAlpha";
|
||||
_captureTextureCommandBuffer.name = "LIV.captureTexture";
|
||||
_applyTextureCommandBuffer.name = "LIV.applyTexture";
|
||||
_optimizedRenderingCommandBuffer.name = "LIV.optimizedRendering";
|
||||
#endif
|
||||
}
|
||||
|
||||
private void DestroyAssets()
|
||||
{
|
||||
if (_cameraInstance != null)
|
||||
{
|
||||
Object.Destroy(_cameraInstance.gameObject);
|
||||
_cameraInstance = null;
|
||||
}
|
||||
|
||||
SDKUtils.DestroyObject<Mesh>(ref _clipPlaneMesh);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneSimpleMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneSimpleDebugMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneComplexMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneComplexDebugMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _writeOpaqueToAlphaMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _combineAlphaMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _writeMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _forceForwardRenderingMaterial);
|
||||
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _clipPlaneCommandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _combineAlphaCommandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _captureTextureCommandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _applyTextureCommandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _optimizedRenderingCommandBuffer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReleaseBridgePoseControl();
|
||||
DestroyAssets();
|
||||
SDKUtils.DestroyTexture(ref _backgroundRenderTexture);
|
||||
SDKUtils.DestroyTexture(ref _foregroundRenderTexture);
|
||||
SDKUtils.DestroyTexture(ref _optimizedRenderTexture);
|
||||
SDKUtils.DestroyTexture(ref _complexClipPlaneRenderTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
455
Assets/LIV/Scripts/SDKRenderShared.cs
Normal file
455
Assets/LIV/Scripts/SDKRenderShared.cs
Normal file
@ -0,0 +1,455 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using System.Collections;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public partial class SDKRender : System.IDisposable
|
||||
{
|
||||
private LIV _liv = null;
|
||||
public LIV liv {
|
||||
get {
|
||||
return _liv;
|
||||
}
|
||||
}
|
||||
|
||||
private SDKOutputFrame _outputFrame = SDKOutputFrame.empty;
|
||||
public SDKOutputFrame outputFrame {
|
||||
get {
|
||||
return _outputFrame;
|
||||
}
|
||||
}
|
||||
|
||||
private SDKInputFrame _inputFrame = SDKInputFrame.empty;
|
||||
public SDKInputFrame inputFrame {
|
||||
get {
|
||||
return _inputFrame;
|
||||
}
|
||||
}
|
||||
|
||||
private SDKResolution _resolution = SDKResolution.zero;
|
||||
public SDKResolution resolution {
|
||||
get {
|
||||
return _resolution;
|
||||
}
|
||||
}
|
||||
|
||||
private Camera _cameraInstance = null;
|
||||
public Camera cameraInstance {
|
||||
get {
|
||||
return _cameraInstance;
|
||||
}
|
||||
}
|
||||
|
||||
public Camera cameraReference {
|
||||
get {
|
||||
return _liv.MRCameraPrefab == null ? _liv.HMDCamera : _liv.MRCameraPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
public Camera hmdCamera {
|
||||
get {
|
||||
return _liv.HMDCamera;
|
||||
}
|
||||
}
|
||||
|
||||
public Transform stage {
|
||||
get {
|
||||
return _liv.stage;
|
||||
}
|
||||
}
|
||||
|
||||
public Transform stageTransform {
|
||||
get {
|
||||
return _liv.stageTransform;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix4x4 stageLocalToWorldMatrix {
|
||||
get {
|
||||
return _liv.stage == null ? Matrix4x4.identity : _liv.stage.localToWorldMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix4x4 localToWorldMatrix {
|
||||
get {
|
||||
return _liv.stageTransform == null ? stageLocalToWorldMatrix : _liv.stageTransform.localToWorldMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
public int spectatorLayerMask {
|
||||
get {
|
||||
return _liv.spectatorLayerMask;
|
||||
}
|
||||
}
|
||||
|
||||
public bool disableStandardAssets {
|
||||
get {
|
||||
return _liv.disableStandardAssets;
|
||||
}
|
||||
}
|
||||
|
||||
private SDKPose _requestedPose = SDKPose.empty;
|
||||
private int _requestedPoseFrameIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Detect if the game can actually change the pose during this frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Because other applications can take over the pose, the game has to know if it can take over the pose or not.</para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class CanControlCameraPose : MonoBehaviour
|
||||
/// {
|
||||
/// [SerializeField] LIV.SDK.Unity.LIV _liv;
|
||||
///
|
||||
/// private void Update()
|
||||
/// {
|
||||
/// if(_liv.isActive)
|
||||
/// {
|
||||
/// Debug.Log(_liv.render.canSetPose);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool canSetPose
|
||||
{
|
||||
get {
|
||||
if (_inputFrame.frameid == 0) return false;
|
||||
return _inputFrame.priority.pose <= (sbyte)PRIORITY.GAME;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Control camera pose by calling this method each frame. The pose is released when you stop calling it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>By default the pose is set in worldspace, turn on local space for using the stage relative space instead.</para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class ControlCameraPose : MonoBehaviour
|
||||
/// {
|
||||
/// [SerializeField] LIV.SDK.Unity.LIV _liv;
|
||||
/// [SerializeField] float _fov = 60f;
|
||||
///
|
||||
/// private void Update()
|
||||
/// {
|
||||
/// if(_liv.isActive)
|
||||
/// {
|
||||
/// _liv.render.SetPose(transform.position, transform.rotation, _fov);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool SetPose(Vector3 position, Quaternion rotation, float verticalFieldOfView = 60f, bool useLocalSpace = false)
|
||||
{
|
||||
if (_inputFrame.frameid == 0) return false;
|
||||
SDKPose inputPose = _inputFrame.pose;
|
||||
float aspect = 1f;
|
||||
if (_resolution.height > 0)
|
||||
{
|
||||
aspect = (float)_resolution.width / (float)_resolution.height;
|
||||
}
|
||||
|
||||
if (!useLocalSpace)
|
||||
{
|
||||
Matrix4x4 worldToLocal = Matrix4x4.identity;
|
||||
Transform localTransform = stageTransform == null ? stage : stageTransform;
|
||||
if(localTransform != null) worldToLocal = localTransform.worldToLocalMatrix;
|
||||
position = worldToLocal.MultiplyPoint(position);
|
||||
rotation = SDKUtils.RotateQuaternionByMatrix(worldToLocal, rotation);
|
||||
}
|
||||
|
||||
_requestedPose = new SDKPose()
|
||||
{
|
||||
localPosition = position,
|
||||
localRotation = rotation,
|
||||
verticalFieldOfView = verticalFieldOfView,
|
||||
projectionMatrix = Matrix4x4.Perspective(verticalFieldOfView, aspect, inputPose.nearClipPlane, inputPose.farClipPlane)
|
||||
};
|
||||
|
||||
_requestedPoseFrameIndex = Time.frameCount;
|
||||
return _inputFrame.priority.pose <= (sbyte)PRIORITY.GAME;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the game ground plane.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If you wisth to use local space coordinates use local space instead.
|
||||
/// The local space has to be relative to stage or stage transform if set.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void SetGroundPlane(float distance, Vector3 normal, bool useLocalSpace = false)
|
||||
{
|
||||
float outputDistance = distance;
|
||||
Vector3 outputNormal = normal;
|
||||
|
||||
if (!useLocalSpace)
|
||||
{
|
||||
Transform localTransform = stageTransform == null ? stage : stageTransform;
|
||||
Matrix4x4 worldToLocal = localTransform.worldToLocalMatrix;
|
||||
Vector3 localPosition = worldToLocal.MultiplyPoint(normal * distance);
|
||||
outputNormal = worldToLocal.MultiplyVector(normal);
|
||||
outputDistance = -Vector3.Dot(normal, localPosition);
|
||||
}
|
||||
|
||||
SDKBridge.SetGroundPlane(new SDKPlane() { distance = outputDistance, normal = outputNormal });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the game ground plane.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If you wisth to use local space coordinates use local space instead.
|
||||
/// The local space has to be relative to stage or stage transform if set.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void SetGroundPlane(Plane plane, bool useLocalSpace = false)
|
||||
{
|
||||
SetGroundPlane(plane.distance, plane.normal, useLocalSpace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the game ground plane.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The transform up vector defines the normal of the plane and the position defines the distance.
|
||||
/// By default, the transform uses world space coordinates. If you wisth to use local space coordinates
|
||||
/// use local space instead. The local space has to be relative to stage or stage transform if set.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class SetGround : MonoBehaviour
|
||||
/// {
|
||||
/// [SerializeField] LIV.SDK.Unity.LIV _liv = null;
|
||||
///
|
||||
/// void Update ()
|
||||
/// {
|
||||
/// if(_liv.isActive)
|
||||
/// {
|
||||
/// _liv.render.SetGroundPlane(transform);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void SetGroundPlane(Transform transform, bool useLocalSpace = false)
|
||||
{
|
||||
if (transform == null) return;
|
||||
Quaternion rotation = useLocalSpace ? transform.localRotation : transform.rotation;
|
||||
Vector3 position = useLocalSpace ? transform.localPosition : transform.position;
|
||||
Vector3 normal = rotation * Vector3.up;
|
||||
SetGroundPlane(-Vector3.Dot(normal, position), normal, useLocalSpace);
|
||||
}
|
||||
|
||||
private void ReleaseBridgePoseControl()
|
||||
{
|
||||
_inputFrame.ReleaseControl();
|
||||
SDKBridge.UpdateInputFrame(ref _inputFrame);
|
||||
}
|
||||
|
||||
private void UpdateBridgeResolution()
|
||||
{
|
||||
SDKBridge.GetResolution(ref _resolution);
|
||||
}
|
||||
|
||||
private void UpdateBridgeInputFrame()
|
||||
{
|
||||
if (_requestedPoseFrameIndex == Time.frameCount)
|
||||
{
|
||||
_inputFrame.ObtainControl();
|
||||
_inputFrame.pose = _requestedPose;
|
||||
_requestedPose = SDKPose.empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inputFrame.ReleaseControl();
|
||||
}
|
||||
|
||||
if (_cameraInstance != null)
|
||||
{
|
||||
// Near and far is always driven by game
|
||||
_inputFrame.pose.nearClipPlane = _cameraInstance.nearClipPlane;
|
||||
_inputFrame.pose.farClipPlane = _cameraInstance.farClipPlane;
|
||||
}
|
||||
|
||||
SDKBridge.UpdateInputFrame(ref _inputFrame);
|
||||
}
|
||||
|
||||
private void InvokePreRender()
|
||||
{
|
||||
if (_liv.onPreRender != null) _liv.onPreRender(this);
|
||||
}
|
||||
|
||||
private void IvokePostRender()
|
||||
{
|
||||
if (_liv.onPostRender != null) _liv.onPostRender(this);
|
||||
}
|
||||
|
||||
private void InvokePreRenderBackground()
|
||||
{
|
||||
if (_liv.onPreRenderBackground != null) _liv.onPreRenderBackground(this);
|
||||
}
|
||||
|
||||
private void InvokePostRenderBackground()
|
||||
{
|
||||
if (_liv.onPostRenderBackground != null) _liv.onPostRenderBackground(this);
|
||||
}
|
||||
|
||||
private void InvokePreRenderForeground()
|
||||
{
|
||||
if (_liv.onPreRenderForeground != null) _liv.onPreRenderForeground(this);
|
||||
}
|
||||
|
||||
private void InvokePostRenderForeground()
|
||||
{
|
||||
if (_liv.onPostRenderForeground != null) _liv.onPostRenderForeground(this);
|
||||
}
|
||||
|
||||
private void CreateBackgroundTexture()
|
||||
{
|
||||
if (SDKUtils.CreateTexture(ref _backgroundRenderTexture, _resolution.width, _resolution.height, 24, RenderTextureFormat.ARGB32))
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
_backgroundRenderTexture.name = "LIV.BackgroundRenderTexture";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("LIV: Unable to create background texture!");
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateForegroundTexture()
|
||||
{
|
||||
if (SDKUtils.CreateTexture(ref _foregroundRenderTexture, _resolution.width, _resolution.height, 24, RenderTextureFormat.ARGB32))
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
_foregroundRenderTexture.name = "LIV.ForegroundRenderTexture";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("LIV: Unable to create foreground texture!");
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateOptimizedTexture()
|
||||
{
|
||||
if (SDKUtils.CreateTexture(ref _optimizedRenderTexture, _resolution.width, _resolution.height, 24, RenderTextureFormat.ARGB32))
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
_optimizedRenderTexture.name = "LIV.OptimizedRenderTexture";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("LIV: Unable to create optimized texture!");
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateComplexClipPlaneTexture()
|
||||
{
|
||||
if (SDKUtils.CreateTexture(ref _complexClipPlaneRenderTexture, _inputFrame.clipPlane.width, _inputFrame.clipPlane.height, 0, RenderTextureFormat.ARGB32))
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
_complexClipPlaneRenderTexture.name = "LIV.ComplexClipPlaneRenderTexture";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("LIV: Unable to create complex clip plane texture!");
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextures()
|
||||
{
|
||||
if (SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.BACKGROUND_RENDER))
|
||||
{
|
||||
if (
|
||||
_backgroundRenderTexture == null ||
|
||||
_backgroundRenderTexture.width != _resolution.width ||
|
||||
_backgroundRenderTexture.height != _resolution.height
|
||||
)
|
||||
{
|
||||
CreateBackgroundTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDKUtils.DestroyTexture(ref _backgroundRenderTexture);
|
||||
}
|
||||
|
||||
if (SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.FOREGROUND_RENDER))
|
||||
{
|
||||
if (
|
||||
_foregroundRenderTexture == null ||
|
||||
_foregroundRenderTexture.width != _resolution.width ||
|
||||
_foregroundRenderTexture.height != _resolution.height
|
||||
)
|
||||
{
|
||||
CreateForegroundTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDKUtils.DestroyTexture(ref _foregroundRenderTexture);
|
||||
}
|
||||
|
||||
if (SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OPTIMIZED_RENDER))
|
||||
{
|
||||
if (
|
||||
_optimizedRenderTexture == null ||
|
||||
_optimizedRenderTexture.width != _resolution.width ||
|
||||
_optimizedRenderTexture.height != _resolution.height
|
||||
)
|
||||
{
|
||||
CreateOptimizedTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDKUtils.DestroyTexture(ref _optimizedRenderTexture);
|
||||
}
|
||||
|
||||
if (SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.COMPLEX_CLIP_PLANE))
|
||||
{
|
||||
if (
|
||||
_complexClipPlaneRenderTexture == null ||
|
||||
_complexClipPlaneRenderTexture.width != _inputFrame.clipPlane.width ||
|
||||
_complexClipPlaneRenderTexture.height != _inputFrame.clipPlane.height
|
||||
)
|
||||
{
|
||||
CreateComplexClipPlaneTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDKUtils.DestroyTexture(ref _complexClipPlaneRenderTexture);
|
||||
}
|
||||
}
|
||||
|
||||
void SendTextureToBridge(RenderTexture texture, TEXTURE_ID id)
|
||||
{
|
||||
SDKBridge.AddTexture(new SDKTexture()
|
||||
{
|
||||
id = id,
|
||||
texturePtr = texture.GetNativeTexturePtr(),
|
||||
SharedHandle = System.IntPtr.Zero,
|
||||
device = SDKUtils.GetDevice(),
|
||||
dummy = 0,
|
||||
type = TEXTURE_TYPE.COLOR_BUFFER,
|
||||
format = TEXTURE_FORMAT.ARGB32,
|
||||
colorSpace = SDKUtils.GetColorSpace(texture),
|
||||
width = texture.width,
|
||||
height = texture.height
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
56
Assets/LIV/Scripts/SDKShaders.cs
Normal file
56
Assets/LIV/Scripts/SDKShaders.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
static class SDKShaders
|
||||
{
|
||||
public static readonly int LIV_COLOR_MASK = Shader.PropertyToID("_LivColorMask");
|
||||
public static readonly int LIV_TESSELLATION_PROPERTY = Shader.PropertyToID("_LivTessellation");
|
||||
public static readonly int LIV_CLIP_PLANE_HEIGHT_MAP_PROPERTY = Shader.PropertyToID("_LivClipPlaneHeightMap");
|
||||
|
||||
public const string LIV_MR_FOREGROUND_KEYWORD = "LIV_MR_FOREGROUND";
|
||||
public const string LIV_MR_BACKGROUND_KEYWORD = "LIV_MR_BACKGROUND";
|
||||
public const string LIV_MR_KEYWORD = "LIV_MR";
|
||||
|
||||
public const string LIV_CLIP_PLANE_SIMPLE_SHADER = "Hidden/LIV_ClipPlaneSimple";
|
||||
public const string LIV_CLIP_PLANE_SIMPLE_DEBUG_SHADER = "Hidden/LIV_ClipPlaneSimpleDebug";
|
||||
public const string LIV_CLIP_PLANE_COMPLEX_SHADER = "Hidden/LIV_ClipPlaneComplex";
|
||||
public const string LIV_CLIP_PLANE_COMPLEX_DEBUG_SHADER = "Hidden/LIV_ClipPlaneComplexDebug";
|
||||
public const string LIV_WRITE_OPAQUE_TO_ALPHA_SHADER = "Hidden/LIV_WriteOpaqueToAlpha";
|
||||
public const string LIV_COMBINE_ALPHA_SHADER = "Hidden/LIV_CombineAlpha";
|
||||
public const string LIV_WRITE_SHADER = "Hidden/LIV_Write";
|
||||
public const string LIV_FORCE_FORWARD_RENDERING_SHADER = "Hidden/LIV_ForceForwardRendering";
|
||||
|
||||
public static void StartRendering()
|
||||
{
|
||||
Shader.EnableKeyword(LIV_MR_KEYWORD);
|
||||
}
|
||||
|
||||
public static void StopRendering()
|
||||
{
|
||||
Shader.DisableKeyword(LIV_MR_KEYWORD);
|
||||
}
|
||||
|
||||
public static void StartForegroundRendering()
|
||||
{
|
||||
Shader.EnableKeyword(LIV_MR_FOREGROUND_KEYWORD);
|
||||
}
|
||||
|
||||
public static void StopForegroundRendering()
|
||||
{
|
||||
Shader.DisableKeyword(LIV_MR_FOREGROUND_KEYWORD);
|
||||
}
|
||||
|
||||
public static void StartBackgroundRendering()
|
||||
{
|
||||
Shader.EnableKeyword(LIV_MR_BACKGROUND_KEYWORD);
|
||||
}
|
||||
|
||||
public static void StopBackgroundRendering()
|
||||
{
|
||||
Shader.DisableKeyword(LIV_MR_BACKGROUND_KEYWORD);
|
||||
}
|
||||
}
|
||||
}
|
941
Assets/LIV/Scripts/SDKStructs.cs
Normal file
941
Assets/LIV/Scripts/SDKStructs.cs
Normal file
@ -0,0 +1,941 @@
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public struct SDKConstants
|
||||
{
|
||||
public const string SDK_ID = "IKZLYPTTD9OATLUM0IBASUY8UIQ9K8YZ";
|
||||
public const string SDK_VERSION = "1.5.4";
|
||||
public const string ENGINE_NAME = "unity";
|
||||
}
|
||||
|
||||
public enum PRIORITY : sbyte
|
||||
{
|
||||
NONE = 0,
|
||||
GAME = 63
|
||||
}
|
||||
|
||||
[System.Flags]
|
||||
public enum FEATURES : ulong
|
||||
{
|
||||
NONE = 0L,
|
||||
BACKGROUND_RENDER = 1L,
|
||||
FOREGROUND_RENDER = 1L << 1,
|
||||
COMPLEX_CLIP_PLANE = 1L << 2,
|
||||
BACKGROUND_DEPTH_RENDER = 1L << 3,
|
||||
OVERRIDE_POST_PROCESSING = 1L << 4,
|
||||
FIX_FOREGROUND_ALPHA = 1L << 5,
|
||||
GROUND_CLIP_PLANE = 1L << 6,
|
||||
RELEASE_CONTROL = 1L << 15,
|
||||
OPTIMIZED_RENDER = 1L << 28,
|
||||
INTERLACED_RENDER = 1L << 29,
|
||||
DEBUG_CLIP_PLANE = 1L << 48,
|
||||
}
|
||||
|
||||
public enum TEXTURE_ID : uint
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
BACKGROUND_COLOR_BUFFER_ID = 10,
|
||||
FOREGROUND_COLOR_BUFFER_ID = 20,
|
||||
OPTIMIZED_COLOR_BUFFER_ID = 30
|
||||
}
|
||||
|
||||
public enum TEXTURE_TYPE : uint
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
COLOR_BUFFER = 1
|
||||
}
|
||||
|
||||
public enum TEXTURE_FORMAT : uint
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
ARGB32 = 10
|
||||
}
|
||||
|
||||
public enum TEXTURE_DEVICE : uint
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
RAW = 1,
|
||||
DIRECTX = 2,
|
||||
OPENGL = 3,
|
||||
VULKAN = 4,
|
||||
METAL = 5
|
||||
}
|
||||
|
||||
public enum TEXTURE_COLOR_SPACE : uint
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
LINEAR = 1,
|
||||
SRGB = 2,
|
||||
}
|
||||
|
||||
public enum RENDERING_PIPELINE : uint
|
||||
{
|
||||
UNDEFINED = 0,
|
||||
FORWARD = 1,
|
||||
DEFERRED = 2,
|
||||
VERTEX_LIT = 3,
|
||||
UNIVERSAL = 4,
|
||||
HIGH_DEFINITION = 5
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKResolution
|
||||
{
|
||||
public int width, height;
|
||||
public static SDKResolution zero {
|
||||
get {
|
||||
return new SDKResolution() { width = 0, height = 0 };
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKResolution:
|
||||
width: {width}
|
||||
height: {height}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKVector3
|
||||
{
|
||||
public float x, y, z;
|
||||
public static SDKVector3 zero {
|
||||
get {
|
||||
return new SDKVector3() { x = 0, y = 0, z = 0 };
|
||||
}
|
||||
}
|
||||
|
||||
public static SDKVector3 one {
|
||||
get {
|
||||
return new SDKVector3() { x = 1, y = 1, z = 1 };
|
||||
}
|
||||
}
|
||||
|
||||
public static SDKVector3 forward {
|
||||
get {
|
||||
return new SDKVector3() { x = 0, y = 0, z = 1 };
|
||||
}
|
||||
}
|
||||
|
||||
public static SDKVector3 up {
|
||||
get {
|
||||
return new SDKVector3() { x = 0, y = 1, z = 0 };
|
||||
}
|
||||
}
|
||||
|
||||
public static SDKVector3 right {
|
||||
get {
|
||||
return new SDKVector3() { x = 1, y = 0, z = 0 };
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator Vector3(SDKVector3 v)
|
||||
{
|
||||
return new Vector3(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
public static implicit operator SDKVector3(Vector3 v)
|
||||
{
|
||||
return new SDKVector3() { x = v.x, y = v.y, z = v.z };
|
||||
}
|
||||
|
||||
// Delete begin
|
||||
public static SDKVector3 operator +(SDKVector3 lhs, SDKVector3 rhs)
|
||||
{
|
||||
SDKVector3 res;
|
||||
res.x = lhs.x + rhs.x;
|
||||
res.y = lhs.y + rhs.y;
|
||||
res.z = lhs.z + rhs.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static SDKVector3 operator -(SDKVector3 lhs, SDKVector3 rhs)
|
||||
{
|
||||
SDKVector3 res;
|
||||
res.x = lhs.x - rhs.x;
|
||||
res.y = lhs.y - rhs.y;
|
||||
res.z = lhs.z - rhs.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static SDKVector3 operator *(SDKVector3 lhs, SDKVector3 rhs)
|
||||
{
|
||||
SDKVector3 res;
|
||||
res.x = lhs.x * rhs.x;
|
||||
res.y = lhs.y * rhs.y;
|
||||
res.z = lhs.z * rhs.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static SDKVector3 operator *(SDKVector3 lhs, float rhs)
|
||||
{
|
||||
SDKVector3 res;
|
||||
res.x = lhs.x * rhs;
|
||||
res.y = lhs.y * rhs;
|
||||
res.z = lhs.z * rhs;
|
||||
return res;
|
||||
}
|
||||
// delete end
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKVector3:
|
||||
x: {x}
|
||||
y: {y}
|
||||
z: {z}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKQuaternion
|
||||
{
|
||||
public float x, y, z, w;
|
||||
public static SDKQuaternion identity {
|
||||
get {
|
||||
return new SDKQuaternion() { x = 0, y = 0, z = 0, w = 1.0f };
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator Quaternion(SDKQuaternion v)
|
||||
{
|
||||
return new Quaternion(v.x, v.y, v.z, v.w);
|
||||
}
|
||||
|
||||
public static implicit operator SDKQuaternion(Quaternion v)
|
||||
{
|
||||
return new SDKQuaternion() { x = v.x, y = v.y, z = v.z, w = v.w };
|
||||
}
|
||||
|
||||
// Delete begin
|
||||
public static SDKQuaternion Euler(float pitch, float yaw, float roll)
|
||||
{
|
||||
float rollOver2 = roll * 0.5f;
|
||||
float sinRollOver2 = Mathf.Sin(rollOver2);
|
||||
float cosRollOver2 = Mathf.Cos(rollOver2);
|
||||
float pitchOver2 = pitch * 0.5f;
|
||||
float sinPitchOver2 = Mathf.Sin(pitchOver2);
|
||||
float cosPitchOver2 = Mathf.Cos(pitchOver2);
|
||||
float yawOver2 = yaw * 0.5f;
|
||||
float sinYawOver2 = Mathf.Sin(yawOver2);
|
||||
float cosYawOver2 = Mathf.Cos(yawOver2);
|
||||
|
||||
var w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2;
|
||||
var x = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2;
|
||||
var y = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2;
|
||||
var z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2;
|
||||
|
||||
return new SDKQuaternion() { x = x, y = y, z = z, w = w };
|
||||
}
|
||||
|
||||
public static SDKQuaternion operator *(SDKQuaternion lhs, SDKQuaternion rhs)
|
||||
{
|
||||
float tx = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y;
|
||||
float ty = lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z;
|
||||
float tz = lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x;
|
||||
float tw = lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z;
|
||||
|
||||
return new SDKQuaternion() { x = tx, y = ty, z = tz, w = tw };
|
||||
}
|
||||
|
||||
public static SDKVector3 operator *(SDKQuaternion lhs, SDKVector3 rhs)
|
||||
{
|
||||
float tx = lhs.x * 2.0f;
|
||||
float ty = lhs.y * 2.0f;
|
||||
float tz = lhs.z * 2.0f;
|
||||
float txx = lhs.x * tx;
|
||||
float tyy = lhs.y * ty;
|
||||
float tzz = lhs.z * tz;
|
||||
float txy = lhs.x * ty;
|
||||
float txz = lhs.x * tz;
|
||||
float tyz = lhs.y * tz;
|
||||
float twx = lhs.w * tx;
|
||||
float twy = lhs.w * ty;
|
||||
float twz = lhs.w * tz;
|
||||
|
||||
SDKVector3 res;
|
||||
res.x = (1.0f - (tyy + tzz)) * rhs.x + (txy - twz) * rhs.y + (txz + twy) * rhs.z;
|
||||
res.y = (txy + twz) * rhs.x + (1.0f - (txx + tzz)) * rhs.y + (tyz - twx) * rhs.z;
|
||||
res.z = (txz - twy) * rhs.x + (tyz + twx) * rhs.y + (1.0f - (txx + tyy)) * rhs.z;
|
||||
return res;
|
||||
}
|
||||
// Delete end
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKQuaternion:
|
||||
x: {x}
|
||||
y: {y}
|
||||
z: {z}
|
||||
w: {w}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKMatrix4x4
|
||||
{
|
||||
public float m00, m01, m02, m03,
|
||||
m10, m11, m12, m13,
|
||||
m20, m21, m22, m23,
|
||||
m30, m31, m32, m33;
|
||||
|
||||
public static SDKMatrix4x4 identity {
|
||||
get {
|
||||
return new SDKMatrix4x4()
|
||||
{
|
||||
m00 = 1,
|
||||
m01 = 0,
|
||||
m02 = 0,
|
||||
m03 = 0,
|
||||
m10 = 0,
|
||||
m11 = 1,
|
||||
m12 = 0,
|
||||
m13 = 0,
|
||||
m20 = 0,
|
||||
m21 = 0,
|
||||
m22 = 1,
|
||||
m23 = 0,
|
||||
m30 = 0,
|
||||
m31 = 0,
|
||||
m32 = 0,
|
||||
m33 = 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator Matrix4x4(SDKMatrix4x4 v)
|
||||
{
|
||||
return new Matrix4x4()
|
||||
{
|
||||
m00 = v.m00,
|
||||
m01 = v.m01,
|
||||
m02 = v.m02,
|
||||
m03 = v.m03,
|
||||
m10 = v.m10,
|
||||
m11 = v.m11,
|
||||
m12 = v.m12,
|
||||
m13 = v.m13,
|
||||
m20 = v.m20,
|
||||
m21 = v.m21,
|
||||
m22 = v.m22,
|
||||
m23 = v.m23,
|
||||
m30 = v.m30,
|
||||
m31 = v.m31,
|
||||
m32 = v.m32,
|
||||
m33 = v.m33
|
||||
};
|
||||
}
|
||||
|
||||
public static implicit operator SDKMatrix4x4(Matrix4x4 v)
|
||||
{
|
||||
return new SDKMatrix4x4()
|
||||
{
|
||||
m00 = v.m00,
|
||||
m01 = v.m01,
|
||||
m02 = v.m02,
|
||||
m03 = v.m03,
|
||||
m10 = v.m10,
|
||||
m11 = v.m11,
|
||||
m12 = v.m12,
|
||||
m13 = v.m13,
|
||||
m20 = v.m20,
|
||||
m21 = v.m21,
|
||||
m22 = v.m22,
|
||||
m23 = v.m23,
|
||||
m30 = v.m30,
|
||||
m31 = v.m31,
|
||||
m32 = v.m32,
|
||||
m33 = v.m33
|
||||
};
|
||||
}
|
||||
|
||||
public static SDKMatrix4x4 Perspective(float vFov, float aspect, float zNear, float zFar)
|
||||
{
|
||||
float vFovRad = vFov * Mathf.Deg2Rad;
|
||||
float hFovRad = 2.0f * Mathf.Atan(Mathf.Tan(vFovRad * 0.5f) * aspect);
|
||||
float w = 1.0f / Mathf.Tan(hFovRad * 0.5f);
|
||||
float h = 1.0f / Mathf.Tan(vFovRad * 0.5f);
|
||||
float q0 = (zFar + zNear) / (zNear - zFar);
|
||||
float q1 = 2.0f * (zFar * zNear) / (zNear - zFar);
|
||||
|
||||
return new SDKMatrix4x4()
|
||||
{
|
||||
m00 = w,
|
||||
m01 = 0,
|
||||
m02 = 0,
|
||||
m03 = 0,
|
||||
m10 = 0,
|
||||
m11 = h,
|
||||
m12 = 0,
|
||||
m13 = 0,
|
||||
m20 = 0,
|
||||
m21 = 0,
|
||||
m22 = q0,
|
||||
m23 = q1,
|
||||
m30 = 0,
|
||||
m31 = 0,
|
||||
m32 = -1,
|
||||
m33 = 0
|
||||
};
|
||||
}
|
||||
|
||||
// begin delete
|
||||
public static SDKMatrix4x4 operator *(SDKMatrix4x4 lhs, SDKMatrix4x4 rhs)
|
||||
{
|
||||
SDKMatrix4x4 res = SDKMatrix4x4.identity;
|
||||
|
||||
res.m00 = lhs.m00 * rhs.m00 + lhs.m01 * rhs.m10 + lhs.m02 * rhs.m20 + lhs.m03 * rhs.m30;
|
||||
res.m01 = lhs.m00 * rhs.m01 + lhs.m01 * rhs.m11 + lhs.m02 * rhs.m21 + lhs.m03 * rhs.m31;
|
||||
res.m02 = lhs.m00 * rhs.m02 + lhs.m01 * rhs.m12 + lhs.m02 * rhs.m22 + lhs.m03 * rhs.m32;
|
||||
res.m03 = lhs.m00 * rhs.m03 + lhs.m01 * rhs.m13 + lhs.m02 * rhs.m23 + lhs.m03 * rhs.m33;
|
||||
|
||||
res.m10 = lhs.m10 * rhs.m00 + lhs.m11 * rhs.m10 + lhs.m12 * rhs.m20 + lhs.m13 * rhs.m30;
|
||||
res.m11 = lhs.m10 * rhs.m01 + lhs.m11 * rhs.m11 + lhs.m12 * rhs.m21 + lhs.m13 * rhs.m31;
|
||||
res.m12 = lhs.m10 * rhs.m02 + lhs.m11 * rhs.m12 + lhs.m12 * rhs.m22 + lhs.m13 * rhs.m32;
|
||||
res.m13 = lhs.m10 * rhs.m03 + lhs.m11 * rhs.m13 + lhs.m12 * rhs.m23 + lhs.m13 * rhs.m33;
|
||||
|
||||
res.m20 = lhs.m20 * rhs.m00 + lhs.m21 * rhs.m10 + lhs.m22 * rhs.m20 + lhs.m23 * rhs.m30;
|
||||
res.m21 = lhs.m20 * rhs.m01 + lhs.m21 * rhs.m11 + lhs.m22 * rhs.m21 + lhs.m23 * rhs.m31;
|
||||
res.m22 = lhs.m20 * rhs.m02 + lhs.m21 * rhs.m12 + lhs.m22 * rhs.m22 + lhs.m23 * rhs.m32;
|
||||
res.m23 = lhs.m20 * rhs.m03 + lhs.m21 * rhs.m13 + lhs.m22 * rhs.m23 + lhs.m23 * rhs.m33;
|
||||
|
||||
res.m30 = lhs.m30 * rhs.m00 + lhs.m31 * rhs.m10 + lhs.m32 * rhs.m20 + lhs.m33 * rhs.m30;
|
||||
res.m31 = lhs.m30 * rhs.m01 + lhs.m31 * rhs.m11 + lhs.m32 * rhs.m21 + lhs.m33 * rhs.m31;
|
||||
res.m32 = lhs.m30 * rhs.m02 + lhs.m31 * rhs.m12 + lhs.m32 * rhs.m22 + lhs.m33 * rhs.m32;
|
||||
res.m33 = lhs.m30 * rhs.m03 + lhs.m31 * rhs.m13 + lhs.m32 * rhs.m23 + lhs.m33 * rhs.m33;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static SDKVector3 operator *(SDKMatrix4x4 lhs, SDKVector3 rhs)
|
||||
{
|
||||
SDKVector3 res;
|
||||
res.x = lhs.m00 * rhs.x + lhs.m01 * rhs.y + lhs.m02 * rhs.z;
|
||||
res.y = lhs.m10 * rhs.x + lhs.m11 * rhs.y + lhs.m12 * rhs.z;
|
||||
res.z = lhs.m20 * rhs.x + lhs.m21 * rhs.y + lhs.m22 * rhs.z;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Creates a translation matrix.
|
||||
public static SDKMatrix4x4 Translate(SDKVector3 value)
|
||||
{
|
||||
return new SDKMatrix4x4
|
||||
{
|
||||
m00 = 1.0f,
|
||||
m01 = 0.0f,
|
||||
m02 = 0.0f,
|
||||
m03 = value.x,
|
||||
m10 = 0.0f,
|
||||
m11 = 1.0f,
|
||||
m12 = 0.0f,
|
||||
m13 = value.y,
|
||||
m20 = 0.0f,
|
||||
m21 = 0.0f,
|
||||
m22 = 1.0f,
|
||||
m23 = value.z,
|
||||
m30 = 0.0f,
|
||||
m31 = 0.0f,
|
||||
m32 = 0.0f,
|
||||
m33 = 1.0f
|
||||
};
|
||||
}
|
||||
|
||||
// Creates a rotation matrix.
|
||||
public static SDKMatrix4x4 Rotate(SDKQuaternion value)
|
||||
{
|
||||
float qx = value.x;
|
||||
float qy = value.y;
|
||||
float qz = value.z;
|
||||
float qw = value.w;
|
||||
|
||||
return new SDKMatrix4x4
|
||||
{
|
||||
m00 = 1.0f - 2.0f * qy * qy - 2.0f * qz * qz,
|
||||
m01 = 2.0f * qx * qy - 2.0f * qz * qw,
|
||||
m02 = 2.0f * qx * qz + 2.0f * qy * qw,
|
||||
m03 = 0.0f,
|
||||
m10 = 2.0f * qx * qy + 2.0f * qz * qw,
|
||||
m11 = 1.0f - 2.0f * qx * qx - 2.0f * qz * qz,
|
||||
m12 = 2.0f * qy * qz - 2.0f * qx * qw,
|
||||
m13 = 0.0f,
|
||||
m20 = 2.0f * qx * qz - 2.0f * qy * qw,
|
||||
m21 = 2.0f * qy * qz + 2.0f * qx * qw,
|
||||
m22 = 1.0f - 2.0f * qx * qx - 2.0f * qy * qy,
|
||||
m23 = 0.0f,
|
||||
m30 = 0.0f,
|
||||
m31 = 0.0f,
|
||||
m32 = 0.0f,
|
||||
m33 = 1.0f
|
||||
};
|
||||
}
|
||||
|
||||
// Creates a scaling matrix.
|
||||
public static SDKMatrix4x4 Scale(SDKVector3 value)
|
||||
{
|
||||
return new SDKMatrix4x4
|
||||
{
|
||||
m00 = value.x,
|
||||
m01 = 0.0f,
|
||||
m02 = 0.0f,
|
||||
m03 = 0.0f,
|
||||
m10 = 0.0f,
|
||||
m11 = value.y,
|
||||
m12 = 0.0f,
|
||||
m13 = 0.0f,
|
||||
m20 = 0.0f,
|
||||
m21 = 0.0f,
|
||||
m22 = value.z,
|
||||
m23 = 0.0f,
|
||||
m30 = 0.0f,
|
||||
m31 = 0.0f,
|
||||
m32 = 0.0f,
|
||||
m33 = 1.0f
|
||||
};
|
||||
}
|
||||
|
||||
public static SDKMatrix4x4 TRS(SDKVector3 translation, SDKQuaternion rotation, SDKVector3 scale)
|
||||
{
|
||||
return Translate(translation) * Rotate(rotation) * Scale(scale);
|
||||
}
|
||||
// end delete
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"Matrix4x4:
|
||||
{m00} {m01} {m02} {m03}
|
||||
{m10} {m11} {m12} {m13}
|
||||
{m20} {m21} {m22} {m23}
|
||||
{m30} {m31} {m32} {m33}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKPlane
|
||||
{
|
||||
public float distance;
|
||||
public SDKVector3 normal;
|
||||
|
||||
public static implicit operator SDKPlane(Plane v)
|
||||
{
|
||||
return new SDKPlane()
|
||||
{
|
||||
distance = v.distance,
|
||||
normal = v.normal
|
||||
};
|
||||
}
|
||||
|
||||
public static SDKPlane empty {
|
||||
get {
|
||||
return new SDKPlane() { distance = 0f, normal = SDKVector3.up };
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKPlane:
|
||||
{distance} {normal}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKPriority
|
||||
{
|
||||
public sbyte pose;
|
||||
public sbyte clipPlane;
|
||||
public sbyte stage;
|
||||
public sbyte resolution;
|
||||
public sbyte feature;
|
||||
public sbyte nearFarAdjustment;
|
||||
public sbyte groundPlane;
|
||||
public sbyte reserved2;
|
||||
|
||||
public static SDKPriority empty {
|
||||
get {
|
||||
return new SDKPriority()
|
||||
{
|
||||
pose = -(sbyte)PRIORITY.GAME,
|
||||
clipPlane = -(sbyte)PRIORITY.GAME,
|
||||
stage = -(sbyte)PRIORITY.GAME,
|
||||
resolution = -(sbyte)PRIORITY.GAME,
|
||||
feature = -(sbyte)PRIORITY.GAME,
|
||||
nearFarAdjustment = (sbyte)PRIORITY.GAME,
|
||||
groundPlane = -(sbyte)PRIORITY.GAME,
|
||||
reserved2 = -(sbyte)PRIORITY.GAME
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"Priority:
|
||||
pose: {pose}, clipPlane: {clipPlane}, stage: {stage}, resolution: {resolution}, feature: {feature}, nearFarAdjustment: {nearFarAdjustment}, groundPlane: {groundPlane}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKApplicationOutput
|
||||
{
|
||||
public FEATURES supportedFeatures;
|
||||
public string engineName;
|
||||
public string engineVersion;
|
||||
public string applicationName;
|
||||
public string applicationVersion;
|
||||
public string xrDeviceName;
|
||||
public string graphicsAPI;
|
||||
public string sdkID;
|
||||
public string sdkVersion;
|
||||
|
||||
public static SDKApplicationOutput empty {
|
||||
get {
|
||||
return new SDKApplicationOutput()
|
||||
{
|
||||
supportedFeatures = FEATURES.NONE,
|
||||
engineName = string.Empty,
|
||||
engineVersion = string.Empty,
|
||||
applicationName = string.Empty,
|
||||
applicationVersion = string.Empty,
|
||||
xrDeviceName = string.Empty,
|
||||
graphicsAPI = string.Empty,
|
||||
sdkID = SDKConstants.SDK_ID,
|
||||
sdkVersion = string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKApplicationOutput:
|
||||
supportedFeatures: {supportedFeatures}
|
||||
engineName: {engineName}
|
||||
engineVersion: {engineVersion}
|
||||
applicationName: {applicationName}
|
||||
applicationVersion: {applicationVersion}
|
||||
xrDeviceName: {xrDeviceName}
|
||||
graphicsAPI: {graphicsAPI}
|
||||
sdkID: {sdkID}
|
||||
sdkVersion: {sdkVersion}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKInputFrame
|
||||
{
|
||||
public SDKPose pose;
|
||||
public SDKClipPlane clipPlane;
|
||||
public SDKTransform stageTransform;
|
||||
public FEATURES features;
|
||||
public SDKClipPlane groundClipPlane;
|
||||
|
||||
public ulong frameid; // This is actually the time stamp of this frame - its populated by the bridge at creation time.
|
||||
public ulong referenceframe; // Use the previous frames frameid to populate this field - it must be set to the correct frame id, or it will fail.
|
||||
public SDKPriority priority; // this is a mixed field combining flags and priority - the contents of this flag are not yet set in stone
|
||||
|
||||
public static SDKInputFrame empty {
|
||||
get {
|
||||
return new SDKInputFrame()
|
||||
{
|
||||
pose = SDKPose.empty,
|
||||
clipPlane = SDKClipPlane.empty,
|
||||
stageTransform = SDKTransform.empty,
|
||||
features = FEATURES.NONE,
|
||||
groundClipPlane = SDKClipPlane.empty,
|
||||
frameid = 0,
|
||||
referenceframe = 0,
|
||||
priority = SDKPriority.empty
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseControl()
|
||||
{
|
||||
priority = SDKPriority.empty;
|
||||
}
|
||||
|
||||
public void ObtainControl()
|
||||
{
|
||||
priority = SDKPriority.empty;
|
||||
priority.pose = (sbyte)PRIORITY.GAME;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKInputFrame:
|
||||
pose: {pose}
|
||||
clipPlane: {clipPlane}
|
||||
stageTransform: {stageTransform}
|
||||
features: {features}
|
||||
groundClipPlane: {groundClipPlane}
|
||||
frameid: {frameid}
|
||||
referenceframe: {referenceframe}
|
||||
priority: {priority:X4}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKOutputFrame
|
||||
{
|
||||
public RENDERING_PIPELINE renderingPipeline;
|
||||
public SDKTrackedSpace trackedSpace;
|
||||
|
||||
public static SDKOutputFrame empty {
|
||||
get {
|
||||
return new SDKOutputFrame()
|
||||
{
|
||||
renderingPipeline = RENDERING_PIPELINE.UNDEFINED,
|
||||
trackedSpace = SDKTrackedSpace.empty
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKOutputFrame:
|
||||
renderingPipeline: {renderingPipeline}
|
||||
trackedSpace: {trackedSpace}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKTrackedSpace
|
||||
{
|
||||
public SDKVector3 trackedSpaceWorldPosition;
|
||||
public SDKQuaternion trackedSpaceWorldRotation;
|
||||
public SDKVector3 trackedSpaceLocalScale;
|
||||
public SDKMatrix4x4 trackedSpaceLocalToWorldMatrix;
|
||||
public SDKMatrix4x4 trackedSpaceWorldToLocalMatrix;
|
||||
|
||||
public static SDKTrackedSpace empty {
|
||||
get {
|
||||
return new SDKTrackedSpace()
|
||||
{
|
||||
trackedSpaceWorldPosition = SDKVector3.zero,
|
||||
trackedSpaceWorldRotation = SDKQuaternion.identity,
|
||||
trackedSpaceLocalScale = SDKVector3.zero,
|
||||
trackedSpaceLocalToWorldMatrix = SDKMatrix4x4.identity,
|
||||
trackedSpaceWorldToLocalMatrix = SDKMatrix4x4.identity
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKTrackedSpace:
|
||||
trackedSpaceWorldPosition: {trackedSpaceWorldPosition}
|
||||
trackedSpaceWorldRotation: {trackedSpaceWorldRotation}
|
||||
trackedSpaceLocalScale: {trackedSpaceLocalScale}
|
||||
trackedSpaceLocalToWorldMatrix: {trackedSpaceLocalToWorldMatrix}
|
||||
trackedSpaceWorldToLocalMatrix: {trackedSpaceWorldToLocalMatrix}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKTexture
|
||||
{
|
||||
public TEXTURE_ID id;
|
||||
public System.IntPtr texturePtr;
|
||||
public System.IntPtr SharedHandle;
|
||||
public TEXTURE_DEVICE device;
|
||||
public int dummy;
|
||||
public TEXTURE_TYPE type;
|
||||
public TEXTURE_FORMAT format;
|
||||
public TEXTURE_COLOR_SPACE colorSpace;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public static SDKTexture empty {
|
||||
get {
|
||||
return new SDKTexture()
|
||||
{
|
||||
id = TEXTURE_ID.UNDEFINED,
|
||||
texturePtr = System.IntPtr.Zero,
|
||||
SharedHandle = System.IntPtr.Zero,
|
||||
device = TEXTURE_DEVICE.UNDEFINED,
|
||||
dummy = 0,
|
||||
type = TEXTURE_TYPE.UNDEFINED,
|
||||
format = TEXTURE_FORMAT.UNDEFINED,
|
||||
colorSpace = TEXTURE_COLOR_SPACE.UNDEFINED,
|
||||
width = 0,
|
||||
height = 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKTexture:
|
||||
id: {id}
|
||||
texturePtr: {texturePtr}
|
||||
SharedHandle: {SharedHandle}
|
||||
device: {device}
|
||||
dummy: {dummy}
|
||||
type: {type}
|
||||
format: {format}
|
||||
colorSpace: {colorSpace}
|
||||
width: {width}
|
||||
height: {height}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKTransform
|
||||
{
|
||||
public SDKVector3 localPosition;
|
||||
public SDKQuaternion localRotation;
|
||||
public SDKVector3 localScale;
|
||||
|
||||
public static SDKTransform empty {
|
||||
get {
|
||||
return new SDKTransform()
|
||||
{
|
||||
localPosition = SDKVector3.zero,
|
||||
localRotation = SDKQuaternion.identity,
|
||||
localScale = SDKVector3.one
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKTransform:
|
||||
localPosition: {localPosition}
|
||||
localRotation: {localRotation}
|
||||
localScale: {localScale}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKClipPlane
|
||||
{
|
||||
public SDKMatrix4x4 transform;
|
||||
public int width;
|
||||
public int height;
|
||||
public float tesselation;
|
||||
|
||||
public static SDKClipPlane empty {
|
||||
get {
|
||||
return new SDKClipPlane()
|
||||
{
|
||||
transform = SDKMatrix4x4.identity,
|
||||
width = 0,
|
||||
height = 0,
|
||||
tesselation = 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKClipPlane:
|
||||
transform: {transform}
|
||||
width: {width}
|
||||
height: {height}
|
||||
tesselation: {tesselation}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKControllerState
|
||||
{
|
||||
public SDKVector3 hmdposition;
|
||||
public SDKQuaternion hmdrotation;
|
||||
|
||||
public SDKVector3 calibrationcameraposition;
|
||||
public SDKQuaternion calibrationcamerarotation;
|
||||
|
||||
public SDKVector3 cameraposition;
|
||||
public SDKQuaternion camerarotation;
|
||||
|
||||
public SDKVector3 leftposition;
|
||||
public SDKQuaternion leftrotation;
|
||||
|
||||
public SDKVector3 rightposition;
|
||||
public SDKQuaternion rightrotation;
|
||||
|
||||
public static SDKControllerState empty {
|
||||
get {
|
||||
return new SDKControllerState()
|
||||
{
|
||||
hmdposition = SDKVector3.zero,
|
||||
hmdrotation = SDKQuaternion.identity,
|
||||
calibrationcameraposition = SDKVector3.zero,
|
||||
calibrationcamerarotation = SDKQuaternion.identity,
|
||||
cameraposition = SDKVector3.zero,
|
||||
camerarotation = SDKQuaternion.identity,
|
||||
leftposition = SDKVector3.zero,
|
||||
leftrotation = SDKQuaternion.identity,
|
||||
rightposition = SDKVector3.zero,
|
||||
rightrotation = SDKQuaternion.identity,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKControllerState:
|
||||
hmdposition: {hmdposition}
|
||||
hmdrotation: {hmdrotation}
|
||||
calibrationcameraposition: {calibrationcameraposition}
|
||||
calibrationcamerarotation: {calibrationcamerarotation}
|
||||
cameraposition: {cameraposition}
|
||||
camerarotation: {camerarotation}
|
||||
leftposition: {leftposition}
|
||||
leftrotation: {leftrotation}
|
||||
rightposition: {rightposition}
|
||||
rightrotation: {rightrotation}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SDKPose
|
||||
{
|
||||
public SDKMatrix4x4 projectionMatrix;
|
||||
public SDKVector3 localPosition;
|
||||
public SDKQuaternion localRotation;
|
||||
public float verticalFieldOfView;
|
||||
public float nearClipPlane;
|
||||
public float farClipPlane;
|
||||
public int unused0;
|
||||
public int unused1;
|
||||
|
||||
public static SDKPose empty {
|
||||
get {
|
||||
return new SDKPose()
|
||||
{
|
||||
projectionMatrix = SDKMatrix4x4.Perspective(90f, 1f, 0.01f, 1000f),
|
||||
localPosition = SDKVector3.zero,
|
||||
localRotation = SDKQuaternion.identity,
|
||||
verticalFieldOfView = 90f,
|
||||
nearClipPlane = 0.01f,
|
||||
farClipPlane = 1000f,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$@"SDKPose:
|
||||
projectionMatrix: {projectionMatrix}
|
||||
localPosition: {localPosition}
|
||||
localRotation: {localRotation}
|
||||
verticalFieldOfView: {verticalFieldOfView}
|
||||
nearClipPlane: {nearClipPlane}
|
||||
farClipPlane: {farClipPlane}";
|
||||
}
|
||||
}
|
||||
}
|
476
Assets/LIV/Scripts/SDKUniversalRender.cs
Normal file
476
Assets/LIV/Scripts/SDKUniversalRender.cs
Normal file
@ -0,0 +1,476 @@
|
||||
#if LIV_UNIVERSAL_RENDER
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public partial class SDKRender : System.IDisposable
|
||||
{
|
||||
// Renders the clip plane in the foreground texture
|
||||
private SDKPass _clipPlanePass = null;
|
||||
// Renders the clipped opaque content in to the foreground texture alpha
|
||||
private SDKPass _combineAlphaPass = null;
|
||||
// Captures texture before post-effects
|
||||
private SDKPass _captureTexturePass = null;
|
||||
// Renders captured texture
|
||||
private SDKPass _applyTexturePass = null;
|
||||
// Renders background and foreground in single render
|
||||
private SDKPass _optimizedRenderingPass = null;
|
||||
|
||||
private RenderPassEvent _clipPlaneRenderPassEvent = RenderPassEvent.AfterRenderingOpaques;
|
||||
private RenderPassEvent _addAlphaRenderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
|
||||
private RenderPassEvent _captureTextureRenderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
|
||||
private RenderPassEvent _applyTextureRenderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
|
||||
private RenderPassEvent _optimizedRenderingPassEvent = RenderPassEvent.AfterRendering;
|
||||
|
||||
// Tessellated quad
|
||||
private Mesh _clipPlaneMesh = null;
|
||||
// Clear material
|
||||
private Material _clipPlaneSimpleMaterial = null;
|
||||
// Transparent material for visual debugging
|
||||
private Material _clipPlaneSimpleDebugMaterial = null;
|
||||
// Tessellated height map clear material
|
||||
private Material _clipPlaneComplexMaterial = null;
|
||||
// Tessellated height map clear material for visual debugging
|
||||
private Material _clipPlaneComplexDebugMaterial = null;
|
||||
private Material _writeOpaqueToAlphaMaterial = null;
|
||||
private Material _combineAlphaMaterial = null;
|
||||
private Material _writeMaterial = null;
|
||||
private Material _forceForwardRenderingMaterial = null;
|
||||
|
||||
private RenderTexture _backgroundRenderTexture = null;
|
||||
private RenderTexture _foregroundRenderTexture = null;
|
||||
private RenderTexture _optimizedRenderTexture = null;
|
||||
private RenderTexture _complexClipPlaneRenderTexture = null;
|
||||
|
||||
private UniversalAdditionalCameraData _universalAdditionalCameraData = null;
|
||||
private RenderTargetIdentifier _cameraColorTextureIdentifier = new RenderTargetIdentifier("_CameraColorTexture");
|
||||
|
||||
Material GetClipPlaneMaterial(bool debugClipPlane, bool complexClipPlane, ColorWriteMask colorWriteMask)
|
||||
{
|
||||
Material output;
|
||||
|
||||
if (complexClipPlane)
|
||||
{
|
||||
output = debugClipPlane ? _clipPlaneComplexDebugMaterial : _clipPlaneComplexMaterial;
|
||||
output.SetTexture(SDKShaders.LIV_CLIP_PLANE_HEIGHT_MAP_PROPERTY, _complexClipPlaneRenderTexture);
|
||||
output.SetFloat(SDKShaders.LIV_TESSELLATION_PROPERTY, _inputFrame.clipPlane.tesselation);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = debugClipPlane ? _clipPlaneSimpleDebugMaterial : _clipPlaneSimpleMaterial;
|
||||
}
|
||||
|
||||
output.SetInt(SDKShaders.LIV_COLOR_MASK, (int)colorWriteMask);
|
||||
return output;
|
||||
}
|
||||
|
||||
Material GetGroundClipPlaneMaterial(bool debugClipPlane, ColorWriteMask colorWriteMask)
|
||||
{
|
||||
Material output;
|
||||
output = debugClipPlane ? _clipPlaneSimpleDebugMaterial : _clipPlaneSimpleMaterial;
|
||||
output.SetInt(SDKShaders.LIV_COLOR_MASK, (int)colorWriteMask);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool useDeferredRendering {
|
||||
get {
|
||||
return _cameraInstance.actualRenderingPath == RenderingPath.DeferredLighting ||
|
||||
_cameraInstance.actualRenderingPath == RenderingPath.DeferredShading;
|
||||
}
|
||||
}
|
||||
|
||||
bool interlacedRendering {
|
||||
get {
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.INTERLACED_RENDER);
|
||||
}
|
||||
}
|
||||
|
||||
bool canRenderBackground {
|
||||
get {
|
||||
if (interlacedRendering)
|
||||
{
|
||||
// Render only if frame is even
|
||||
if (Time.frameCount % 2 != 0) return false;
|
||||
}
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.BACKGROUND_RENDER) && _backgroundRenderTexture != null;
|
||||
}
|
||||
}
|
||||
|
||||
bool canRenderForeground {
|
||||
get {
|
||||
if (interlacedRendering)
|
||||
{
|
||||
// Render only if frame is odd
|
||||
if (Time.frameCount % 2 != 1) return false;
|
||||
}
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.FOREGROUND_RENDER) && _foregroundRenderTexture != null;
|
||||
}
|
||||
}
|
||||
|
||||
bool canRenderOptimized {
|
||||
get {
|
||||
return SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OPTIMIZED_RENDER) && _optimizedRenderTexture != null; ;
|
||||
}
|
||||
}
|
||||
|
||||
public SDKRender(LIV liv)
|
||||
{
|
||||
_liv = liv;
|
||||
CreateAssets();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
UpdateBridgeResolution();
|
||||
UpdateBridgeInputFrame();
|
||||
SDKUtils.ApplyUserSpaceTransform(this);
|
||||
UpdateTextures();
|
||||
InvokePreRender();
|
||||
if (canRenderBackground) RenderBackground();
|
||||
if (canRenderForeground) RenderForeground();
|
||||
if (canRenderOptimized) RenderOptimized();
|
||||
IvokePostRender();
|
||||
SDKUtils.CreateBridgeOutputFrame(this);
|
||||
SDKBridge.IssuePluginEvent();
|
||||
}
|
||||
|
||||
// Default render without any special changes
|
||||
private void RenderBackground()
|
||||
{
|
||||
SDKUtils.SetCamera(_cameraInstance, _cameraInstance.transform, _inputFrame, localToWorldMatrix, spectatorLayerMask);
|
||||
_cameraInstance.targetTexture = _backgroundRenderTexture;
|
||||
|
||||
RenderTexture tempRenderTexture = null;
|
||||
|
||||
bool overridePostProcessing = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OVERRIDE_POST_PROCESSING);
|
||||
if (overridePostProcessing)
|
||||
{
|
||||
tempRenderTexture = RenderTexture.GetTemporary(_backgroundRenderTexture.width, _backgroundRenderTexture.height, 0, _backgroundRenderTexture.format);
|
||||
#if UNITY_EDITOR
|
||||
tempRenderTexture.name = "LIV.TemporaryRenderTexture";
|
||||
#endif
|
||||
|
||||
_captureTexturePass.commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, tempRenderTexture);
|
||||
_applyTexturePass.commandBuffer.Blit(tempRenderTexture, BuiltinRenderTextureType.CurrentActive);
|
||||
|
||||
SDKUniversalRenderFeature.AddPass(_captureTexturePass);
|
||||
SDKUniversalRenderFeature.AddPass(_applyTexturePass);
|
||||
}
|
||||
|
||||
SDKShaders.StartRendering();
|
||||
SDKShaders.StartBackgroundRendering();
|
||||
InvokePreRenderBackground();
|
||||
SendTextureToBridge(_backgroundRenderTexture, TEXTURE_ID.BACKGROUND_COLOR_BUFFER_ID);
|
||||
_cameraInstance.Render();
|
||||
InvokePostRenderBackground();
|
||||
_cameraInstance.targetTexture = null;
|
||||
SDKShaders.StopBackgroundRendering();
|
||||
SDKShaders.StopRendering();
|
||||
|
||||
if (overridePostProcessing)
|
||||
{
|
||||
_captureTexturePass.commandBuffer.Clear();
|
||||
_applyTexturePass.commandBuffer.Clear();
|
||||
RenderTexture.ReleaseTemporary(tempRenderTexture);
|
||||
}
|
||||
|
||||
SDKUniversalRenderFeature.ClearPasses();
|
||||
}
|
||||
|
||||
// Extract the image which is in front of our clip plane
|
||||
// The compositing is heavily relying on the alpha channel, therefore we want to make sure it does
|
||||
// not get corrupted by the postprocessing or any shader
|
||||
private void RenderForeground()
|
||||
{
|
||||
bool debugClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.DEBUG_CLIP_PLANE);
|
||||
bool renderComplexClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.COMPLEX_CLIP_PLANE);
|
||||
bool renderGroundClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.GROUND_CLIP_PLANE);
|
||||
bool overridePostProcessing = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.OVERRIDE_POST_PROCESSING);
|
||||
bool fixPostEffectsAlpha = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.FIX_FOREGROUND_ALPHA) | _liv.fixPostEffectsAlpha;
|
||||
|
||||
MonoBehaviour[] behaviours = null;
|
||||
bool[] wasBehaviourEnabled = null;
|
||||
if (disableStandardAssets) SDKUtils.DisableStandardAssets(_cameraInstance, ref behaviours, ref wasBehaviourEnabled);
|
||||
|
||||
// Capture camera defaults
|
||||
CameraClearFlags capturedClearFlags = _cameraInstance.clearFlags;
|
||||
Color capturedBgColor = _cameraInstance.backgroundColor;
|
||||
Color capturedFogColor = RenderSettings.fogColor;
|
||||
|
||||
// Make sure that fog does not corrupt alpha channel
|
||||
RenderSettings.fogColor = new Color(capturedFogColor.r, capturedFogColor.g, capturedFogColor.b, 0f);
|
||||
SDKUtils.SetCamera(_cameraInstance, _cameraInstance.transform, _inputFrame, localToWorldMatrix, spectatorLayerMask);
|
||||
_cameraInstance.clearFlags = CameraClearFlags.Color;
|
||||
_cameraInstance.backgroundColor = Color.clear;
|
||||
_cameraInstance.targetTexture = _foregroundRenderTexture;
|
||||
|
||||
RenderTexture capturedAlphaRenderTexture = RenderTexture.GetTemporary(_foregroundRenderTexture.width, _foregroundRenderTexture.height, 0, _foregroundRenderTexture.format);
|
||||
#if UNITY_EDITOR
|
||||
capturedAlphaRenderTexture.name = "LIV.CapturedAlphaRenderTexture";
|
||||
#endif
|
||||
|
||||
// Render opaque pixels into alpha channel
|
||||
_clipPlanePass.commandBuffer.DrawMesh(_clipPlaneMesh, Matrix4x4.identity, _writeOpaqueToAlphaMaterial, 0, 0);
|
||||
|
||||
// Render clip plane
|
||||
Matrix4x4 clipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.clipPlane.transform;
|
||||
_clipPlanePass.commandBuffer.DrawMesh(_clipPlaneMesh, clipPlaneTransform,
|
||||
GetClipPlaneMaterial(debugClipPlane, renderComplexClipPlane, ColorWriteMask.All), 0, 0);
|
||||
|
||||
// Render ground clip plane
|
||||
if (renderGroundClipPlane)
|
||||
{
|
||||
Matrix4x4 groundClipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.groundClipPlane.transform;
|
||||
_clipPlanePass.commandBuffer.DrawMesh(_clipPlaneMesh, groundClipPlaneTransform,
|
||||
GetGroundClipPlaneMaterial(debugClipPlane, ColorWriteMask.All), 0, 0);
|
||||
}
|
||||
|
||||
// Copy alpha in to texture
|
||||
_clipPlanePass.commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, capturedAlphaRenderTexture);
|
||||
_clipPlanePass.commandBuffer.SetRenderTarget(_cameraColorTextureIdentifier);
|
||||
SDKUniversalRenderFeature.AddPass(_clipPlanePass);
|
||||
|
||||
// Fix alpha corruption by post processing
|
||||
RenderTexture tempRenderTexture = null;
|
||||
if (overridePostProcessing || fixPostEffectsAlpha)
|
||||
{
|
||||
tempRenderTexture = RenderTexture.GetTemporary(_foregroundRenderTexture.width, _foregroundRenderTexture.height, 0, _foregroundRenderTexture.format);
|
||||
#if UNITY_EDITOR
|
||||
tempRenderTexture.name = "LIV.TemporaryRenderTexture";
|
||||
#endif
|
||||
_captureTexturePass.commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, tempRenderTexture);
|
||||
SDKUniversalRenderFeature.AddPass(_captureTexturePass);
|
||||
|
||||
_writeMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, overridePostProcessing ? (int)ColorWriteMask.All : (int)ColorWriteMask.Alpha);
|
||||
_applyTexturePass.commandBuffer.Blit(tempRenderTexture, BuiltinRenderTextureType.CurrentActive, _writeMaterial);
|
||||
SDKUniversalRenderFeature.AddPass(_applyTexturePass);
|
||||
}
|
||||
|
||||
// Combine captured alpha with result alpha
|
||||
_combineAlphaMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, (int)ColorWriteMask.Alpha);
|
||||
_combineAlphaPass.commandBuffer.Blit(capturedAlphaRenderTexture, BuiltinRenderTextureType.CurrentActive, _combineAlphaMaterial);
|
||||
SDKUniversalRenderFeature.AddPass(_combineAlphaPass);
|
||||
|
||||
if (useDeferredRendering) SDKUtils.ForceForwardRendering(cameraInstance, _clipPlaneMesh, _forceForwardRenderingMaterial);
|
||||
|
||||
SDKShaders.StartRendering();
|
||||
SDKShaders.StartForegroundRendering();
|
||||
InvokePreRenderForeground();
|
||||
SendTextureToBridge(_foregroundRenderTexture, TEXTURE_ID.FOREGROUND_COLOR_BUFFER_ID);
|
||||
_cameraInstance.Render();
|
||||
InvokePostRenderForeground();
|
||||
_cameraInstance.targetTexture = null;
|
||||
SDKShaders.StopForegroundRendering();
|
||||
SDKShaders.StopRendering();
|
||||
|
||||
if (overridePostProcessing || fixPostEffectsAlpha)
|
||||
{
|
||||
_captureTexturePass.commandBuffer.Clear();
|
||||
_applyTexturePass.commandBuffer.Clear();
|
||||
|
||||
RenderTexture.ReleaseTemporary(tempRenderTexture);
|
||||
}
|
||||
|
||||
RenderTexture.ReleaseTemporary(capturedAlphaRenderTexture);
|
||||
|
||||
_clipPlanePass.commandBuffer.Clear();
|
||||
_combineAlphaPass.commandBuffer.Clear();
|
||||
|
||||
SDKUniversalRenderFeature.ClearPasses();
|
||||
|
||||
// Revert camera defaults
|
||||
_cameraInstance.clearFlags = capturedClearFlags;
|
||||
_cameraInstance.backgroundColor = capturedBgColor;
|
||||
RenderSettings.fogColor = capturedFogColor;
|
||||
|
||||
SDKUtils.RestoreStandardAssets(ref behaviours, ref wasBehaviourEnabled);
|
||||
}
|
||||
|
||||
// Renders a single camera in a single texture with occlusion only from opaque objects.
|
||||
// This is the most performant option for mixed reality.
|
||||
// It does not support any transparency in the foreground layer.
|
||||
private void RenderOptimized()
|
||||
{
|
||||
bool debugClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.DEBUG_CLIP_PLANE);
|
||||
bool renderComplexClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.COMPLEX_CLIP_PLANE);
|
||||
bool renderGroundClipPlane = SDKUtils.FeatureEnabled(inputFrame.features, FEATURES.GROUND_CLIP_PLANE);
|
||||
|
||||
SDKUtils.SetCamera(_cameraInstance, _cameraInstance.transform, _inputFrame, localToWorldMatrix, spectatorLayerMask);
|
||||
_cameraInstance.targetTexture = _optimizedRenderTexture;
|
||||
|
||||
// Clear alpha channel
|
||||
_writeMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, (int)ColorWriteMask.Alpha);
|
||||
_optimizedRenderingPass.commandBuffer.Blit(BuiltinRenderTextureType.None, BuiltinRenderTextureType.CurrentActive, _writeMaterial);
|
||||
|
||||
// Render opaque pixels into alpha channel
|
||||
_writeOpaqueToAlphaMaterial.SetInt(SDKShaders.LIV_COLOR_MASK, (int)ColorWriteMask.Alpha);
|
||||
_optimizedRenderingPass.commandBuffer.DrawMesh(_clipPlaneMesh, Matrix4x4.identity, _writeOpaqueToAlphaMaterial, 0, 0);
|
||||
|
||||
// Render clip plane
|
||||
Matrix4x4 clipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.clipPlane.transform;
|
||||
_optimizedRenderingPass.commandBuffer.DrawMesh(_clipPlaneMesh, clipPlaneTransform,
|
||||
GetClipPlaneMaterial(debugClipPlane, renderComplexClipPlane, ColorWriteMask.Alpha), 0, 0);
|
||||
|
||||
// Render ground clip plane
|
||||
if (renderGroundClipPlane)
|
||||
{
|
||||
Matrix4x4 groundClipPlaneTransform = localToWorldMatrix * (Matrix4x4)_inputFrame.groundClipPlane.transform;
|
||||
_optimizedRenderingPass.commandBuffer.DrawMesh(_clipPlaneMesh, groundClipPlaneTransform,
|
||||
GetGroundClipPlaneMaterial(debugClipPlane, ColorWriteMask.Alpha), 0, 0);
|
||||
}
|
||||
|
||||
SDKUniversalRenderFeature.AddPass(_optimizedRenderingPass);
|
||||
|
||||
// TODO: this is just proprietary
|
||||
SDKShaders.StartRendering();
|
||||
SDKShaders.StartBackgroundRendering();
|
||||
InvokePreRenderBackground();
|
||||
SendTextureToBridge(_optimizedRenderTexture, TEXTURE_ID.OPTIMIZED_COLOR_BUFFER_ID);
|
||||
_cameraInstance.Render();
|
||||
InvokePostRenderBackground();
|
||||
_cameraInstance.targetTexture = null;
|
||||
SDKShaders.StopBackgroundRendering();
|
||||
SDKShaders.StopRendering();
|
||||
|
||||
_optimizedRenderingPass.commandBuffer.Clear();
|
||||
SDKUniversalRenderFeature.ClearPasses();
|
||||
}
|
||||
|
||||
private void CreateAssets()
|
||||
{
|
||||
bool cameraReferenceEnabled = cameraReference.enabled;
|
||||
if (cameraReferenceEnabled)
|
||||
{
|
||||
cameraReference.enabled = false;
|
||||
}
|
||||
bool cameraReferenceActive = cameraReference.gameObject.activeSelf;
|
||||
if (cameraReferenceActive)
|
||||
{
|
||||
cameraReference.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
GameObject cloneGO = (GameObject)Object.Instantiate(cameraReference.gameObject, _liv.stage);
|
||||
_cameraInstance = (Camera)cloneGO.GetComponent("Camera");
|
||||
|
||||
SDKUtils.CleanCameraBehaviours(_cameraInstance, _liv.excludeBehaviours);
|
||||
|
||||
if (cameraReferenceActive != cameraReference.gameObject.activeSelf)
|
||||
{
|
||||
cameraReference.gameObject.SetActive(cameraReferenceActive);
|
||||
}
|
||||
if (cameraReferenceEnabled != cameraReference.enabled)
|
||||
{
|
||||
cameraReference.enabled = cameraReferenceEnabled;
|
||||
}
|
||||
|
||||
_cameraInstance.name = "LIV Camera";
|
||||
if (_cameraInstance.tag == "MainCamera")
|
||||
{
|
||||
_cameraInstance.tag = "Untagged";
|
||||
}
|
||||
|
||||
_cameraInstance.transform.localScale = Vector3.one;
|
||||
_cameraInstance.rect = new Rect(0, 0, 1, 1);
|
||||
_cameraInstance.depth = 0;
|
||||
#if UNITY_5_4_OR_NEWER
|
||||
_cameraInstance.stereoTargetEye = StereoTargetEyeMask.None;
|
||||
#endif
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
_cameraInstance.allowMSAA = false;
|
||||
#endif
|
||||
_cameraInstance.enabled = false;
|
||||
_cameraInstance.gameObject.SetActive(true);
|
||||
_universalAdditionalCameraData = _cameraInstance.GetComponent<UniversalAdditionalCameraData>();
|
||||
|
||||
_clipPlaneMesh = new Mesh();
|
||||
SDKUtils.CreateClipPlane(_clipPlaneMesh, 10, 10, true, 1000f);
|
||||
_clipPlaneSimpleMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_SIMPLE_SHADER));
|
||||
_clipPlaneSimpleDebugMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_SIMPLE_DEBUG_SHADER));
|
||||
_clipPlaneComplexMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_COMPLEX_SHADER));
|
||||
_clipPlaneComplexDebugMaterial = new Material(Shader.Find(SDKShaders.LIV_CLIP_PLANE_COMPLEX_DEBUG_SHADER));
|
||||
_writeOpaqueToAlphaMaterial = new Material(Shader.Find(SDKShaders.LIV_WRITE_OPAQUE_TO_ALPHA_SHADER));
|
||||
_combineAlphaMaterial = new Material(Shader.Find(SDKShaders.LIV_COMBINE_ALPHA_SHADER));
|
||||
_writeMaterial = new Material(Shader.Find(SDKShaders.LIV_WRITE_SHADER));
|
||||
_forceForwardRenderingMaterial = new Material(Shader.Find(SDKShaders.LIV_FORCE_FORWARD_RENDERING_SHADER));
|
||||
|
||||
_clipPlanePass = new SDKPass();
|
||||
_clipPlanePass.renderPassEvent = _clipPlaneRenderPassEvent;
|
||||
_clipPlanePass.commandBuffer = new CommandBuffer();
|
||||
|
||||
_combineAlphaPass = new SDKPass();
|
||||
_combineAlphaPass.renderPassEvent = _addAlphaRenderPassEvent;
|
||||
_combineAlphaPass.commandBuffer = new CommandBuffer();
|
||||
|
||||
_captureTexturePass = new SDKPass();
|
||||
_captureTexturePass.renderPassEvent = _captureTextureRenderPassEvent;
|
||||
_captureTexturePass.commandBuffer = new CommandBuffer();
|
||||
|
||||
_applyTexturePass = new SDKPass();
|
||||
_applyTexturePass.renderPassEvent = _applyTextureRenderPassEvent;
|
||||
_applyTexturePass.commandBuffer = new CommandBuffer();
|
||||
|
||||
_optimizedRenderingPass = new SDKPass();
|
||||
_optimizedRenderingPass.renderPassEvent = _optimizedRenderingPassEvent;
|
||||
_optimizedRenderingPass.commandBuffer = new CommandBuffer();
|
||||
|
||||
_universalAdditionalCameraData.antialiasing = AntialiasingMode.None;
|
||||
_universalAdditionalCameraData.antialiasingQuality = AntialiasingQuality.Low;
|
||||
_universalAdditionalCameraData.dithering = false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
_clipPlaneMesh.name = "LIV.clipPlane";
|
||||
_clipPlaneSimpleMaterial.name = "LIV.clipPlaneSimple";
|
||||
_clipPlaneSimpleDebugMaterial.name = "LIV.clipPlaneSimpleDebug";
|
||||
_clipPlaneComplexMaterial.name = "LIV.clipPlaneComplex";
|
||||
_clipPlaneComplexDebugMaterial.name = "LIV.clipPlaneComplexDebug";
|
||||
_writeOpaqueToAlphaMaterial.name = "LIV.writeOpaqueToAlpha";
|
||||
_combineAlphaMaterial.name = "LIV.combineAlpha";
|
||||
_writeMaterial.name = "LIV.write";
|
||||
_forceForwardRenderingMaterial.name = "LIV.forceForwardRendering";
|
||||
_clipPlanePass.commandBuffer.name = "LIV.renderClipPlanes";
|
||||
_combineAlphaPass.commandBuffer.name = "LIV.foregroundCombineAlpha";
|
||||
_captureTexturePass.commandBuffer.name = "LIV.captureTexture";
|
||||
_applyTexturePass.commandBuffer.name = "LIV.applyTexture";
|
||||
_optimizedRenderingPass.commandBuffer.name = "LIV.optimizedRendering";
|
||||
#endif
|
||||
}
|
||||
|
||||
private void DestroyAssets()
|
||||
{
|
||||
if (_cameraInstance != null)
|
||||
{
|
||||
Object.Destroy(_cameraInstance.gameObject);
|
||||
_cameraInstance = null;
|
||||
}
|
||||
|
||||
SDKUtils.DestroyObject<Mesh>(ref _clipPlaneMesh);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneSimpleMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneSimpleDebugMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneComplexMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _clipPlaneComplexDebugMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _writeOpaqueToAlphaMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _combineAlphaMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _writeMaterial);
|
||||
SDKUtils.DestroyObject<Material>(ref _forceForwardRenderingMaterial);
|
||||
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _clipPlanePass.commandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _combineAlphaPass.commandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _captureTexturePass.commandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _applyTexturePass.commandBuffer);
|
||||
SDKUtils.DisposeObject<CommandBuffer>(ref _optimizedRenderingPass.commandBuffer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReleaseBridgePoseControl();
|
||||
DestroyAssets();
|
||||
SDKUtils.DestroyTexture(ref _backgroundRenderTexture);
|
||||
SDKUtils.DestroyTexture(ref _foregroundRenderTexture);
|
||||
SDKUtils.DestroyTexture(ref _optimizedRenderTexture);
|
||||
SDKUtils.DestroyTexture(ref _complexClipPlaneRenderTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
49
Assets/LIV/Scripts/SDKUniversalRenderFeature.cs
Normal file
49
Assets/LIV/Scripts/SDKUniversalRenderFeature.cs
Normal file
@ -0,0 +1,49 @@
|
||||
#if LIV_UNIVERSAL_RENDER
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public class SDKPass : ScriptableRenderPass
|
||||
{
|
||||
public CommandBuffer commandBuffer;
|
||||
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
context.ExecuteCommandBuffer(commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public class SDKUniversalRenderFeature : ScriptableRendererFeature
|
||||
{
|
||||
static List<SDKPass> passes = new List<SDKPass>();
|
||||
|
||||
public static void AddPass(SDKPass pass)
|
||||
{
|
||||
passes.Add(pass);
|
||||
}
|
||||
|
||||
public static void ClearPasses()
|
||||
{
|
||||
passes.Clear();
|
||||
}
|
||||
|
||||
public override void Create()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||||
{
|
||||
while (passes.Count > 0)
|
||||
{
|
||||
renderer.EnqueuePass(passes[0]);
|
||||
passes.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
343
Assets/LIV/Scripts/SDKUtils.cs
Normal file
343
Assets/LIV/Scripts/SDKUtils.cs
Normal file
@ -0,0 +1,343 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace LIV.SDK.Unity
|
||||
{
|
||||
public static class SDKUtils
|
||||
{
|
||||
public static void CreateClipPlane(Mesh mesh, int resX, int resY, bool useQuads, float skirtLength)
|
||||
{
|
||||
int vertexCount = (resX + 1) * (resY + 1);
|
||||
int triangleCount = useQuads ? (resX * resY * 4) : (resX * resY * 2 * 3);
|
||||
Vector3[] v = new Vector3[vertexCount];
|
||||
Vector2[] uv = new Vector2[vertexCount];
|
||||
int[] t = new int[triangleCount];
|
||||
|
||||
float hWidth = 0.5f;
|
||||
float hHeight = 0.5f;
|
||||
|
||||
int resX1 = resX + 1;
|
||||
int resY1 = resY + 1;
|
||||
|
||||
for (int y = 0; y < resY1; y++)
|
||||
{
|
||||
for (int x = 0; x < resX1; x++)
|
||||
{
|
||||
int vi = y * resX1 + x;
|
||||
float uvx = (float)x / (float)resX;
|
||||
float uvy = (float)y / (float)resY;
|
||||
float skirtX = (x == 0 || x == resX) ? skirtLength : 1f;
|
||||
float skirtY = (y == 0 || y == resY) ? skirtLength : 1f;
|
||||
v[vi] = new Vector2((-hWidth + uvx) * skirtX, (-hHeight + uvy) * skirtY);
|
||||
uv[vi] = new Vector2(Mathf.InverseLerp(1, resX - 1, x), Mathf.InverseLerp(1, resY - 1, y));
|
||||
}
|
||||
}
|
||||
|
||||
mesh.Clear();
|
||||
mesh.vertices = v;
|
||||
mesh.uv = uv;
|
||||
mesh.bounds = new Bounds(Vector3.zero, Vector3.one * float.MaxValue);
|
||||
|
||||
{
|
||||
int faces = resX * resY;
|
||||
int vi = 0;
|
||||
int ti = 0;
|
||||
|
||||
if (useQuads)
|
||||
{
|
||||
for (int i = 0; i < faces; i++)
|
||||
{
|
||||
vi = (i / resX) * resX1 + (i % resX);
|
||||
t[ti++] = vi + 1;
|
||||
t[ti++] = vi;
|
||||
t[ti++] = vi + 1 + resX;
|
||||
t[ti++] = vi + 2 + resX;
|
||||
}
|
||||
mesh.SetIndices(t, MeshTopology.Quads, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < faces; i++)
|
||||
{
|
||||
vi = (i / resX) * resX1 + (i % resX);
|
||||
|
||||
t[ti++] = vi + 2 + resX;
|
||||
t[ti++] = vi + 1;
|
||||
t[ti++] = vi;
|
||||
|
||||
t[ti++] = vi + 1 + resX;
|
||||
t[ti++] = vi + 2 + resX;
|
||||
t[ti++] = vi;
|
||||
}
|
||||
mesh.SetIndices(t, MeshTopology.Triangles, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static RenderTextureReadWrite GetReadWriteFromColorSpace(TEXTURE_COLOR_SPACE colorSpace)
|
||||
{
|
||||
switch (colorSpace)
|
||||
{
|
||||
case TEXTURE_COLOR_SPACE.LINEAR:
|
||||
return RenderTextureReadWrite.Linear;
|
||||
case TEXTURE_COLOR_SPACE.SRGB:
|
||||
return RenderTextureReadWrite.sRGB;
|
||||
default:
|
||||
return RenderTextureReadWrite.Default;
|
||||
}
|
||||
}
|
||||
|
||||
public static TEXTURE_COLOR_SPACE GetDefaultColorSpace {
|
||||
get {
|
||||
switch (QualitySettings.activeColorSpace)
|
||||
{
|
||||
case UnityEngine.ColorSpace.Gamma:
|
||||
return TEXTURE_COLOR_SPACE.SRGB;
|
||||
case UnityEngine.ColorSpace.Linear:
|
||||
return TEXTURE_COLOR_SPACE.LINEAR;
|
||||
|
||||
}
|
||||
return TEXTURE_COLOR_SPACE.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
public static TEXTURE_COLOR_SPACE GetColorSpace(RenderTexture renderTexture)
|
||||
{
|
||||
if (renderTexture == null) return TEXTURE_COLOR_SPACE.UNDEFINED;
|
||||
if (renderTexture.sRGB) return TEXTURE_COLOR_SPACE.SRGB;
|
||||
return TEXTURE_COLOR_SPACE.LINEAR;
|
||||
}
|
||||
|
||||
public static RENDERING_PIPELINE GetRenderingPipeline(RenderingPath renderingPath)
|
||||
{
|
||||
switch (renderingPath)
|
||||
{
|
||||
case RenderingPath.DeferredLighting:
|
||||
return RENDERING_PIPELINE.DEFERRED;
|
||||
case RenderingPath.DeferredShading:
|
||||
return RENDERING_PIPELINE.DEFERRED;
|
||||
case RenderingPath.Forward:
|
||||
return RENDERING_PIPELINE.FORWARD;
|
||||
case RenderingPath.VertexLit:
|
||||
return RENDERING_PIPELINE.VERTEX_LIT;
|
||||
default:
|
||||
return RENDERING_PIPELINE.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
public static TEXTURE_DEVICE GetDevice()
|
||||
{
|
||||
switch (SystemInfo.graphicsDeviceType)
|
||||
{
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.Direct3D11:
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.Direct3D12:
|
||||
return TEXTURE_DEVICE.DIRECTX;
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.Vulkan:
|
||||
return TEXTURE_DEVICE.VULKAN;
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.Metal:
|
||||
return TEXTURE_DEVICE.METAL;
|
||||
case UnityEngine.Rendering.GraphicsDeviceType.OpenGLCore:
|
||||
return TEXTURE_DEVICE.OPENGL;
|
||||
default:
|
||||
return TEXTURE_DEVICE.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ContainsFlag(ulong flags, ulong flag)
|
||||
{
|
||||
return (flags & flag) != 0;
|
||||
}
|
||||
|
||||
public static ulong SetFlag(ulong flags, ulong flag, bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
return flags | flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
return flags & (~flag);
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetCameraPositionAndRotation(SDKPose pose, Matrix4x4 originLocalToWorldMatrix, out Vector3 position, out Quaternion rotation)
|
||||
{
|
||||
position = originLocalToWorldMatrix.MultiplyPoint(pose.localPosition);
|
||||
rotation = RotateQuaternionByMatrix(originLocalToWorldMatrix, pose.localRotation);
|
||||
}
|
||||
|
||||
public static void CleanCameraBehaviours(Camera camera, string[] excludeBehaviours)
|
||||
{
|
||||
// Remove all children from camera clone.
|
||||
foreach (Transform child in camera.transform)
|
||||
{
|
||||
Object.Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
if (excludeBehaviours == null) return;
|
||||
for (int i = 0; i < excludeBehaviours.Length; i++)
|
||||
{
|
||||
Object.Destroy(camera.GetComponent(excludeBehaviours[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCamera(Camera camera, Transform cameraTransform, SDKInputFrame inputFrame, Matrix4x4 originLocalToWorldMatrix, int layerMask)
|
||||
{
|
||||
Vector3 worldPosition = Vector3.zero;
|
||||
Quaternion worldRotation = Quaternion.identity;
|
||||
float verticalFieldOfView = inputFrame.pose.verticalFieldOfView;
|
||||
float nearClipPlane = inputFrame.pose.nearClipPlane;
|
||||
float farClipPlane = inputFrame.pose.farClipPlane;
|
||||
Matrix4x4 projectionMatrix = inputFrame.pose.projectionMatrix;
|
||||
|
||||
GetCameraPositionAndRotation(inputFrame.pose, originLocalToWorldMatrix, out worldPosition, out worldRotation);
|
||||
|
||||
cameraTransform.position = worldPosition;
|
||||
cameraTransform.rotation = worldRotation;
|
||||
camera.fieldOfView = verticalFieldOfView;
|
||||
camera.nearClipPlane = nearClipPlane;
|
||||
camera.farClipPlane = farClipPlane;
|
||||
camera.projectionMatrix = projectionMatrix;
|
||||
camera.cullingMask = layerMask;
|
||||
}
|
||||
|
||||
public static Quaternion RotateQuaternionByMatrix(Matrix4x4 matrix, Quaternion rotation)
|
||||
{
|
||||
return Quaternion.LookRotation(
|
||||
matrix.MultiplyVector(Vector3.forward),
|
||||
matrix.MultiplyVector(Vector3.up)
|
||||
) * rotation;
|
||||
}
|
||||
|
||||
public static SDKTrackedSpace GetTrackedSpace(Transform transform)
|
||||
{
|
||||
if (transform == null) return SDKTrackedSpace.empty;
|
||||
return new SDKTrackedSpace
|
||||
{
|
||||
trackedSpaceWorldPosition = transform.position,
|
||||
trackedSpaceWorldRotation = transform.rotation,
|
||||
trackedSpaceLocalScale = transform.localScale,
|
||||
trackedSpaceLocalToWorldMatrix = transform.localToWorldMatrix,
|
||||
trackedSpaceWorldToLocalMatrix = transform.worldToLocalMatrix,
|
||||
};
|
||||
}
|
||||
|
||||
public static bool DestroyObject<T>(ref T reference) where T : UnityEngine.Object
|
||||
{
|
||||
if (reference == null) return false;
|
||||
Object.Destroy(reference);
|
||||
reference = default(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool DisposeObject<T>(ref T reference) where T : System.IDisposable
|
||||
{
|
||||
if (reference == null) return false;
|
||||
reference.Dispose();
|
||||
reference = default(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CreateTexture(ref RenderTexture renderTexture, int width, int height, int depth, RenderTextureFormat format)
|
||||
{
|
||||
DestroyTexture(ref renderTexture);
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
Debug.LogError("LIV: Unable to create render texture. Texture dimension must be higher than zero.");
|
||||
return false;
|
||||
}
|
||||
|
||||
renderTexture = new RenderTexture(width, height, depth, format)
|
||||
{
|
||||
antiAliasing = 1,
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
useMipMap = false,
|
||||
anisoLevel = 0
|
||||
};
|
||||
|
||||
if (!renderTexture.Create())
|
||||
{
|
||||
Debug.LogError("LIV: Unable to create render texture.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void DestroyTexture(ref RenderTexture _renderTexture)
|
||||
{
|
||||
if (_renderTexture == null) return;
|
||||
if (_renderTexture.IsCreated())
|
||||
{
|
||||
_renderTexture.Release();
|
||||
}
|
||||
_renderTexture = null;
|
||||
}
|
||||
|
||||
public static void ApplyUserSpaceTransform(SDKRender render)
|
||||
{
|
||||
if (render.stageTransform == null) return;
|
||||
render.stageTransform.localPosition = render.inputFrame.stageTransform.localPosition;
|
||||
render.stageTransform.localRotation = render.inputFrame.stageTransform.localRotation;
|
||||
render.stageTransform.localScale = render.inputFrame.stageTransform.localScale;
|
||||
}
|
||||
|
||||
public static void CreateBridgeOutputFrame(SDKRender render)
|
||||
{
|
||||
RENDERING_PIPELINE renderingPipeline = RENDERING_PIPELINE.UNDEFINED;
|
||||
#if LIV_UNIVERSAL_RENDER
|
||||
renderingPipeline = RENDERING_PIPELINE.UNIVERSAL;
|
||||
#else
|
||||
if(render.cameraInstance != null)
|
||||
{
|
||||
renderingPipeline = SDKUtils.GetRenderingPipeline(render.cameraInstance.actualRenderingPath);
|
||||
}
|
||||
#endif
|
||||
SDKBridge.CreateFrame(new SDKOutputFrame()
|
||||
{
|
||||
renderingPipeline = renderingPipeline,
|
||||
trackedSpace = SDKUtils.GetTrackedSpace(render.stageTransform == null ? render.stage : render.stageTransform)
|
||||
});
|
||||
}
|
||||
|
||||
public static bool FeatureEnabled(FEATURES features, FEATURES feature)
|
||||
{
|
||||
return SDKUtils.ContainsFlag((ulong)features, (ulong)feature);
|
||||
}
|
||||
|
||||
// Disable standard assets if required.
|
||||
public static void DisableStandardAssets(Camera cameraInstance, ref MonoBehaviour[] behaviours, ref bool[] wasBehaviourEnabled)
|
||||
{
|
||||
behaviours = null;
|
||||
wasBehaviourEnabled = null;
|
||||
behaviours = cameraInstance.gameObject.GetComponents<MonoBehaviour>();
|
||||
wasBehaviourEnabled = new bool[behaviours.Length];
|
||||
for (var i = 0; i < behaviours.Length; i++)
|
||||
{
|
||||
var behaviour = behaviours[i];
|
||||
// generates garbage
|
||||
if (behaviour.enabled && behaviour.GetType().ToString().StartsWith("UnityStandardAssets."))
|
||||
{
|
||||
behaviour.enabled = false;
|
||||
wasBehaviourEnabled[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore disabled behaviours.
|
||||
public static void RestoreStandardAssets(ref MonoBehaviour[] behaviours, ref bool[] wasBehaviourEnabled)
|
||||
{
|
||||
if (behaviours != null)
|
||||
for (var i = 0; i < behaviours.Length; i++)
|
||||
if (wasBehaviourEnabled[i])
|
||||
behaviours[i].enabled = true;
|
||||
}
|
||||
|
||||
public static void ForceForwardRendering(Camera cameraInstance, Mesh clipPlaneMesh, Material forceForwardRenderingMaterial)
|
||||
{
|
||||
Matrix4x4 forceForwardRenderingMatrix = cameraInstance.transform.localToWorldMatrix * Matrix4x4.TRS(Vector3.forward * (cameraInstance.nearClipPlane + 0.1f), Quaternion.identity, Vector3.one);
|
||||
Graphics.DrawMesh(clipPlaneMesh, forceForwardRenderingMatrix, forceForwardRenderingMaterial, 0, cameraInstance, 0, new MaterialPropertyBlock(), false, false, false);
|
||||
}
|
||||
}
|
||||
}
|
@ -17925,6 +17925,65 @@ MeshCollider:
|
||||
m_Convex: 0
|
||||
m_CookingOptions: 30
|
||||
m_Mesh: {fileID: 8049113947432375598, guid: 4cbf0dbca1ca1a5499c4b7806ab6aac5, type: 3}
|
||||
--- !u!1 &1698363238
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1698363240}
|
||||
- component: {fileID: 1698363239}
|
||||
m_Layer: 0
|
||||
m_Name: LIV
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1698363239
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1698363238}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 419ad76f2ffc722478bc67f61f9c32e7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_stage: {fileID: 1270359727}
|
||||
_stageTransform: {fileID: 0}
|
||||
_HMDCamera: {fileID: 1249534346}
|
||||
_MRCameraPrefab: {fileID: 0}
|
||||
_disableStandardAssets: 0
|
||||
_spectatorLayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
_excludeBehaviours:
|
||||
- AudioListener
|
||||
- Collider
|
||||
- SteamVR_Camera
|
||||
- SteamVR_Fade
|
||||
- SteamVR_ExternalCamera
|
||||
_fixPostEffectsAlpha: 1
|
||||
--- !u!4 &1698363240
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1698363238}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 11
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1701657063
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -18951,6 +19010,7 @@ MonoBehaviour:
|
||||
type: 3}
|
||||
m_CancelAction: {fileID: 2387711382375263438, guid: c348712bda248c246b8c49b3db54643f,
|
||||
type: 3}
|
||||
m_EnableBuiltinActionsAsFallback: 1
|
||||
m_EnableGamepadInput: 1
|
||||
m_EnableJoystickInput: 1
|
||||
m_HorizontalAxis: Horizontal
|
||||
|
@ -1,5 +1,18 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-2850737546700727566
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8e67cb7969c50a9428e7b47bea58abff, type: 3}
|
||||
m_Name: SDKUniversalRenderFeature
|
||||
m_EditorClassIdentifier:
|
||||
m_Active: 1
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -15,8 +28,9 @@ MonoBehaviour:
|
||||
debugShaders:
|
||||
debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7,
|
||||
type: 3}
|
||||
m_RendererFeatures: []
|
||||
m_RendererFeatureMap:
|
||||
m_RendererFeatures:
|
||||
- {fileID: -2850737546700727566}
|
||||
m_RendererFeatureMap: f2da081d4e2570d8
|
||||
m_UseNativeRenderPass: 0
|
||||
postProcessData: {fileID: 0}
|
||||
xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2}
|
||||
|
@ -806,7 +806,8 @@ PlayerSettings:
|
||||
webGLLinkerTarget: 1
|
||||
webGLThreadsSupport: 0
|
||||
webGLDecompressionFallback: 0
|
||||
scriptingDefineSymbols: {}
|
||||
scriptingDefineSymbols:
|
||||
Standalone: LIV_UNIVERSAL_RENDER
|
||||
additionalCompilerArguments: {}
|
||||
platformArchitecture: {}
|
||||
scriptingBackend:
|
||||
|
Loading…
Reference in New Issue
Block a user