1
0
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:
xpeng 2022-08-19 23:02:51 +02:00
parent 732045d109
commit 67d911847b
22 changed files with 4563 additions and 3 deletions

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

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

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

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

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

View File

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

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

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

View 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();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

522
Assets/LIV/Scripts/LIV.cs Normal file
View 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 users 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 users playspace.")]
[FormerlySerializedAs("StageTransform")]
[SerializeField] Transform _stageTransform = null;
/// <summary>
/// This transform is an additional wrapper to the users 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 users HMD.")]
[FormerlySerializedAs("HMDCamera")]
[SerializeField] Camera _HMDCamera = null;
/// <summary>
/// This is the camera responsible for rendering the users HMD.
/// </summary>
/// <remarks>
/// <para>The LIV SDK, by default clones this object to match your applications 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>Unitys 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 youre using.</para>
/// <para>LIV is meant to include the users 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 players 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);
}
}
}
}

View 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;
}
}
}

View 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

View 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
});
}
}
}

View 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);
}
}
}

View 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}";
}
}
}

View 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

View 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

View 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);
}
}
}

View File

@ -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

View File

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

View File

@ -806,7 +806,8 @@ PlayerSettings:
webGLLinkerTarget: 1
webGLThreadsSupport: 0
webGLDecompressionFallback: 0
scriptingDefineSymbols: {}
scriptingDefineSymbols:
Standalone: LIV_UNIVERSAL_RENDER
additionalCompilerArguments: {}
platformArchitecture: {}
scriptingBackend: