com.github.asus4.texture-source 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Texture Source
2
2
 
3
- TextureSource is an utility for using CV in Unity. It enables you to choose multiple input sources in Editor.
3
+ TextureSource is a utility for using CV in Unity. It enables you to choose multiple input sources in Editor.
4
4
 
5
5
  ## Install via UPM
6
6
 
7
- Add following setting to `Packages/manifest.json`
7
+ Add the following setting to `Packages/manifest.json`
8
8
 
9
- ```
9
+ ```json
10
10
  {
11
11
  "scopedRegistries": [
12
12
  {
@@ -18,7 +18,7 @@ Add following setting to `Packages/manifest.json`
18
18
  }
19
19
  ],
20
20
  "dependencies": {
21
- "com.github.asus4.texture-source": "0.1.0",
21
+ "com.github.asus4.texture-source": "0.1.3",
22
22
  ...// other dependencies
23
23
  }
24
24
  }
@@ -0,0 +1,8 @@
1
+ // Ported from RenderPipeLine-Core, to support both URP and Built-in RP in one shader
2
+ // com.unity.render-pipelines.core copyright © 2020 Unity Technologies ApS
3
+ // Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
4
+
5
+ float3 FastSRGBToLinear(float3 c)
6
+ {
7
+ return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
8
+ }
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: d73b9c13ee77b4bb48a8ff20c23c9709
3
+ ShaderIncludeImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -1,5 +1,7 @@
1
1
  #pragma kernel TextureTransform
2
2
 
3
+ #include "Common.hlsl"
4
+
3
5
  Texture2D<float4> _InputTex;
4
6
  RWTexture2D<float4> _OutputTex;
5
7
  uint2 _OutputTexSize;
@@ -18,7 +20,13 @@ void TextureTransform (uint2 id : SV_DispatchThreadID)
18
20
  float2 uv = (float2)id / float2(_OutputTexSize - 1.0);
19
21
  uv = mul(_TransformMatrix, float4(uv, 0, 1)).xy;
20
22
 
23
+ float4 c = _InputTex.SampleLevel(linearClampSampler, uv, 0);
24
+
25
+ #ifndef UNITY_NO_LINEAR_COLORSPACE
26
+ c.rgb = FastSRGBToLinear(c.rgb);
27
+ #endif // !UNITY_COLORSPACE_GAMMA
28
+
21
29
  _OutputTex[id] = any(uv < 0) || any(uv > 1)
22
30
  ? float4(0, 0, 0, 1)
23
- : _InputTex.SampleLevel(linearClampSampler, uv, 0);
31
+ : c;
24
32
  }
@@ -0,0 +1,144 @@
1
+ // Only available with AR Foundation
2
+ #if MODULE_ARFOUNDATION_ENABLED
3
+ namespace TextureSource
4
+ {
5
+ using System;
6
+ using UnityEngine;
7
+ using UnityEngine.XR.ARFoundation;
8
+
9
+ [CreateAssetMenu(menuName = "ScriptableObject/Texture Source/ARFoundation", fileName = "ARFoundationTextureSource")]
10
+ public sealed class ARFoundationTextureSource : BaseTextureSource
11
+ {
12
+ private static readonly int _DisplayTransformID = Shader.PropertyToID("_UnityDisplayTransform");
13
+
14
+ private ARCameraManager cameraManager;
15
+ private RenderTexture texture;
16
+ private Material material;
17
+ private int lastUpdatedFrame = -1;
18
+
19
+ private static readonly Lazy<Shader> ARCameraBackgroundShader = new(() =>
20
+ {
21
+ string shaderName = Application.platform switch
22
+ {
23
+ RuntimePlatform.Android => "Unlit/ARCoreBackground",
24
+ RuntimePlatform.IPhonePlayer => "Unlit/ARKitBackground",
25
+ #if UNITY_ANDROID
26
+ _ => "Unlit/ARCoreBackground",
27
+ #elif UNITY_IOS
28
+ _ => "Unlit/ARKitBackground",
29
+ #else
30
+ _ => throw new NotSupportedException($"ARFoundationTextureSource is not supported on {Application.platform}"),
31
+ #endif
32
+ };
33
+ return Shader.Find(shaderName);
34
+ });
35
+
36
+ public override bool DidUpdateThisFrame => lastUpdatedFrame == Time.frameCount;
37
+ public override Texture Texture => texture;
38
+
39
+ public override void Start()
40
+ {
41
+ cameraManager = FindAnyObjectByType<ARCameraManager>();
42
+ if (cameraManager == null)
43
+ {
44
+ throw new InvalidOperationException("ARCameraManager is not found");
45
+ }
46
+
47
+ var shader = ARCameraBackgroundShader.Value;
48
+ material = new Material(shader);
49
+
50
+ cameraManager.frameReceived += OnFrameReceived;
51
+ }
52
+
53
+ public override void Stop()
54
+ {
55
+ if (cameraManager != null)
56
+ {
57
+ cameraManager.frameReceived -= OnFrameReceived;
58
+ }
59
+
60
+ if (texture != null)
61
+ {
62
+ texture.Release();
63
+ Destroy(texture);
64
+ texture = null;
65
+ }
66
+
67
+ if (material != null)
68
+ {
69
+ Destroy(material);
70
+ material = null;
71
+ }
72
+ }
73
+
74
+ public override void Next()
75
+ {
76
+ if (cameraManager == null)
77
+ {
78
+ return;
79
+ }
80
+ // Switch the camera facing direction.
81
+ cameraManager.requestedFacingDirection = cameraManager.currentFacingDirection switch
82
+ {
83
+ CameraFacingDirection.World => CameraFacingDirection.User,
84
+ CameraFacingDirection.User => CameraFacingDirection.World,
85
+ _ => CameraFacingDirection.World,
86
+ };
87
+ }
88
+
89
+ private void OnFrameReceived(ARCameraFrameEventArgs args)
90
+ {
91
+ // Find best texture size
92
+ int bestWidth = 0;
93
+ int bestHeight = 0;
94
+ int count = args.textures.Count;
95
+ for (int i = 0; i < count; i++)
96
+ {
97
+ var tex = args.textures[i];
98
+ bestWidth = Math.Max(bestWidth, tex.width);
99
+ bestHeight = Math.Max(bestHeight, tex.height);
100
+ material.SetTexture(args.propertyNameIds[i], tex);
101
+ }
102
+
103
+ // Swap if screen is portrait
104
+ float screenAspect = (float)Screen.width / Screen.height;
105
+ if (bestWidth > bestHeight && screenAspect < 1f)
106
+ {
107
+ (bestWidth, bestHeight) = (bestHeight, bestWidth);
108
+ }
109
+
110
+ // Create render texture
111
+ Utils.GetTargetSizeScale(
112
+ new Vector2Int(bestWidth, bestHeight), screenAspect,
113
+ out Vector2Int dstSize, out Vector2 scale);
114
+ EnsureRenderTexture(dstSize.x, dstSize.y);
115
+
116
+ // SetMaterialKeywords(material, args.enabledMaterialKeywords, args.disabledMaterialKeywords);
117
+
118
+ if (args.displayMatrix.HasValue)
119
+ {
120
+ material.SetMatrix(_DisplayTransformID, args.displayMatrix.Value);
121
+ }
122
+
123
+ Graphics.Blit(null, texture, material);
124
+
125
+ lastUpdatedFrame = Time.frameCount;
126
+ }
127
+
128
+ private void EnsureRenderTexture(int width, int height)
129
+ {
130
+ if (texture == null || texture.width != width || texture.height != height)
131
+ {
132
+ if (texture != null)
133
+ {
134
+ texture.Release();
135
+ texture = null;
136
+ }
137
+ int depth = 32;
138
+ texture = new RenderTexture(width, height, depth, RenderTextureFormat.ARGB32);
139
+ texture.Create();
140
+ }
141
+ }
142
+ }
143
+ }
144
+ #endif // MODULE_ARFOUNDATION_ENABLED
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 107561cd512c541429a04e0ab1d41f54
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "name": "TextureSource",
3
3
  "rootNamespace": "",
4
- "references": [],
4
+ "references": [
5
+ "GUID:a9420e37d7990b54abdef6688edbe313"
6
+ ],
5
7
  "includePlatforms": [],
6
8
  "excludePlatforms": [],
7
9
  "allowUnsafeCode": false,
@@ -9,6 +11,12 @@
9
11
  "precompiledReferences": [],
10
12
  "autoReferenced": true,
11
13
  "defineConstraints": [],
12
- "versionDefines": [],
14
+ "versionDefines": [
15
+ {
16
+ "name": "com.unity.xr.arfoundation",
17
+ "expression": "4.0.0",
18
+ "define": "MODULE_ARFOUNDATION_ENABLED"
19
+ }
20
+ ],
13
21
  "noEngineReferences": false
14
22
  }
@@ -1,11 +1,10 @@
1
1
  namespace TextureSource
2
2
  {
3
+ using System;
3
4
  using UnityEngine;
4
5
 
5
- public class TextureTransformer : System.IDisposable
6
+ public class TextureTransformer : IDisposable
6
7
  {
7
- private static ComputeShader compute;
8
- private static int kernel;
9
8
  private static readonly int _InputTex = Shader.PropertyToID("_InputTex");
10
9
  private static readonly int _OutputTex = Shader.PropertyToID("_OutputTex");
11
10
  private static readonly int _OutputTexSize = Shader.PropertyToID("_OutputTexSize");
@@ -14,14 +13,24 @@ namespace TextureSource
14
13
  private static readonly Matrix4x4 PopMatrix = Matrix4x4.Translate(new Vector3(0.5f, 0.5f, 0));
15
14
  private static readonly Matrix4x4 PushMatrix = Matrix4x4.Translate(new Vector3(-0.5f, -0.5f, 0));
16
15
 
16
+ public static readonly Lazy<ComputeShader> DefaultComputeShader = new(()
17
+ => Resources.Load<ComputeShader>("com.github.asus4.texture-source/TextureTransform"));
18
+
19
+ private readonly ComputeShader compute;
20
+ private readonly int kernel;
17
21
  private RenderTexture texture;
18
22
  public readonly int width;
19
23
  public readonly int height;
20
24
 
21
25
  public RenderTexture Texture => texture;
22
26
 
23
- public TextureTransformer(int width, int height)
27
+ public TextureTransformer(int width, int height, ComputeShader shader = null)
24
28
  {
29
+ compute = shader != null
30
+ ? shader
31
+ : DefaultComputeShader.Value;
32
+ kernel = compute.FindKernel("TextureTransform");
33
+
25
34
  this.width = width;
26
35
  this.height = height;
27
36
 
@@ -30,16 +39,10 @@ namespace TextureSource
30
39
  enableRandomWrite = true,
31
40
  useMipMap = false,
32
41
  depthBufferBits = 0,
42
+ // sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear,
33
43
  };
34
44
  texture = new RenderTexture(desc);
35
45
  texture.Create();
36
-
37
- if (compute == null)
38
- {
39
- const string SHADER_PATH = "com.github.asus4.texture-source/TextureTransform";
40
- compute = Resources.Load<ComputeShader>(SHADER_PATH);
41
- kernel = compute.FindKernel("TextureTransform");
42
- }
43
46
  }
44
47
 
45
48
  public void Dispose()
@@ -47,11 +50,17 @@ namespace TextureSource
47
50
  if (texture != null)
48
51
  {
49
52
  texture.Release();
50
- Object.Destroy(texture);
53
+ UnityEngine.Object.Destroy(texture);
51
54
  }
52
55
  texture = null;
53
56
  }
54
57
 
58
+ /// <summary>
59
+ /// Transform with a matrix
60
+ /// </summary>
61
+ /// <param name="input">A input texture</param>
62
+ /// <param name="t">A matrix</param>
63
+ /// <returns>The transformed texture</returns>
55
64
  public RenderTexture Transform(Texture input, Matrix4x4 t)
56
65
  {
57
66
  compute.SetTexture(kernel, _InputTex, input, 0);
@@ -62,6 +71,14 @@ namespace TextureSource
62
71
  return texture;
63
72
  }
64
73
 
74
+ /// <summary>
75
+ /// Transform with offset, rotation, and scale
76
+ /// </summary>
77
+ /// <param name="input">A input texture</param>
78
+ /// <param name="offset">A 2D offset</param>
79
+ /// <param name="eulerRotation">A rotation in euler angles</param>
80
+ /// <param name="scale">A scale</param>
81
+ /// <returns>The transformed texture</returns>
65
82
  public RenderTexture Transform(Texture input, Vector2 offset, float eulerRotation, Vector2 scale)
66
83
  {
67
84
  Matrix4x4 trs = Matrix4x4.TRS(
@@ -70,5 +87,25 @@ namespace TextureSource
70
87
  new Vector3(1f / scale.x, 1f / scale.y, 1));
71
88
  return Transform(input, PopMatrix * trs * PushMatrix);
72
89
  }
90
+
91
+ /// <summary>
92
+ /// Transform with multiple textures
93
+ /// </summary>
94
+ /// <param name="propertyIds">An array of property name IDs associated with each texture</param>
95
+ /// <param name="textures">An array of textures</param>
96
+ /// <param name="t">A matrix</param>
97
+ /// <returns>The transformed texture</returns>
98
+ public RenderTexture Transform(ReadOnlySpan<int> propertyIds, ReadOnlySpan<Texture> textures, Matrix4x4 t)
99
+ {
100
+ for (int i = 0; i < propertyIds.Length; i++)
101
+ {
102
+ compute.SetTexture(kernel, propertyIds[i], textures[i], 0);
103
+ }
104
+ compute.SetTexture(kernel, _OutputTex, texture, 0);
105
+ compute.SetInts(_OutputTexSize, texture.width, texture.height);
106
+ compute.SetMatrix(_TransformMatrix, t);
107
+ compute.Dispatch(kernel, Mathf.CeilToInt(texture.width / 8f), Mathf.CeilToInt(texture.height / 8f), 1);
108
+ return texture;
109
+ }
73
110
  }
74
111
  }
@@ -0,0 +1,33 @@
1
+ namespace TextureSource
2
+ {
3
+ using UnityEngine;
4
+
5
+ internal static class Utils
6
+ {
7
+ public static void GetTargetSizeScale(
8
+ Vector2Int srcSize, float dstAspect,
9
+ out Vector2Int dstSize, out Vector2 scale)
10
+ {
11
+ float srcAspect = (float)srcSize.x / srcSize.y;
12
+ int width, height;
13
+ if (srcAspect > dstAspect)
14
+ {
15
+ width = RoundToEven(srcSize.y * dstAspect);
16
+ height = srcSize.y;
17
+ scale = new Vector2((float)srcSize.x / width, 1);
18
+ }
19
+ else
20
+ {
21
+ width = srcSize.x;
22
+ height = RoundToEven(srcSize.x / dstAspect);
23
+ scale = new Vector2(1, (float)srcSize.y / height);
24
+ }
25
+ dstSize = new Vector2Int(width, height);
26
+ }
27
+
28
+ private static int RoundToEven(float n)
29
+ {
30
+ return Mathf.RoundToInt(n / 2) * 2;
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 994d1f7299166498fb0798e74fd2cbf0
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -39,6 +39,17 @@ namespace TextureSource
39
39
  public bool DidUpdateThisFrame => activeSource.DidUpdateThisFrame;
40
40
  public Texture Texture => activeSource.Texture;
41
41
 
42
+ public BaseTextureSource Source
43
+ {
44
+ get => source;
45
+ set => source = value;
46
+ }
47
+ public BaseTextureSource SourceForEditor
48
+ {
49
+ get => sourceForEditor;
50
+ set => sourceForEditor = value;
51
+ }
52
+
42
53
  private void OnEnable()
43
54
  {
44
55
  activeSource = sourceForEditor != null && Application.isEditor
@@ -90,42 +101,27 @@ namespace TextureSource
90
101
 
91
102
  private Texture TrimToScreen(Texture texture)
92
103
  {
93
- float cameraAspect = (float)texture.width / texture.height;
94
- float targetAspect = (float)Screen.width / Screen.height;
104
+ float srcAspect = (float)texture.width / texture.height;
105
+ float dstAspect = (float)Screen.width / Screen.height;
95
106
 
96
- if (Mathf.Abs(cameraAspect - targetAspect) < 0.01f)
107
+ // Allow 1% mismatch
108
+ if (Mathf.Abs(srcAspect - dstAspect) < 0.01f)
97
109
  {
98
110
  return texture;
99
111
  }
100
112
 
101
- int width, height;
102
- Vector2 scale;
103
- if (cameraAspect > targetAspect)
104
- {
105
- width = RoundToEven(texture.height * targetAspect);
106
- height = texture.height;
107
- scale = new Vector2((float)texture.width / width, 1);
108
- }
109
- else
110
- {
111
- width = texture.width;
112
- height = RoundToEven(texture.width / targetAspect);
113
- scale = new Vector2(1, (float)texture.height / height);
114
- }
113
+ Utils.GetTargetSizeScale(
114
+ new Vector2Int(texture.width, texture.height), dstAspect,
115
+ out Vector2Int dstSize, out Vector2 scale);
115
116
 
116
- bool needInitialize = transformer == null || width != transformer.width || height != transformer.height;
117
+ bool needInitialize = transformer == null || dstSize.x != transformer.width || dstSize.y != transformer.height;
117
118
  if (needInitialize)
118
119
  {
119
120
  transformer?.Dispose();
120
- transformer = new TextureTransformer(width, height);
121
+ transformer = new TextureTransformer(dstSize.x, dstSize.y);
121
122
  }
122
123
 
123
124
  return transformer.Transform(texture, Vector2.zero, 0, scale);
124
125
  }
125
-
126
- private static int RoundToEven(float n)
127
- {
128
- return Mathf.RoundToInt(n / 2) * 2;
129
- }
130
126
  }
131
127
  }
@@ -57,12 +57,48 @@ namespace TextureSource
57
57
  private int lastUpdatedFrame = -1;
58
58
  private bool isFrontFacing;
59
59
 
60
+ public WebCamKindFlag KindFilter
61
+ {
62
+ get => kindFilter;
63
+ set => kindFilter = value;
64
+ }
65
+
66
+ public FacingFlag FacingFilter
67
+ {
68
+ get => facingFilter;
69
+ set => facingFilter = value;
70
+ }
71
+
72
+ public Vector2Int Resolution
73
+ {
74
+ get => resolution;
75
+ set => resolution = value;
76
+ }
77
+
78
+ public bool IsFrontFacing => isFrontFacing;
79
+
80
+ public int FrameRate
81
+ {
82
+ get => frameRate;
83
+ set => frameRate = value;
84
+ }
85
+
60
86
  public override void Start()
61
87
  {
62
88
  devices = WebCamTexture.devices.Where(IsMatchFilter).ToArray();
63
89
  StartCamera(currentIndex);
64
90
  }
65
91
 
92
+ private void StartCamera(int index)
93
+ {
94
+ Stop();
95
+ WebCamDevice device = devices[index];
96
+ webCamTexture = new WebCamTexture(device.name, resolution.x, resolution.y, frameRate);
97
+ webCamTexture.Play();
98
+ isFrontFacing = device.isFrontFacing;
99
+ lastUpdatedFrame = -1;
100
+ }
101
+
66
102
  public override void Stop()
67
103
  {
68
104
  if (webCamTexture != null)
@@ -80,17 +116,6 @@ namespace TextureSource
80
116
  StartCamera(currentIndex);
81
117
  }
82
118
 
83
- private void StartCamera(int index)
84
- {
85
- Stop();
86
- WebCamDevice device = devices[index];
87
- webCamTexture = new WebCamTexture(device.name, resolution.x, resolution.y, frameRate);
88
- webCamTexture.Play();
89
- isFrontFacing = device.isFrontFacing;
90
- lastUpdatedFrame = -1;
91
- Debug.Log($"Started camera:{device.name}");
92
- }
93
-
94
119
  private RenderTexture NormalizeWebCam()
95
120
  {
96
121
  if (webCamTexture == null)
package/package.json CHANGED
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "name": "com.github.asus4.texture-source",
3
+ "version": "0.2.0",
3
4
  "displayName": "TextureSource",
4
- "author": "Koki Ibukuro",
5
- "description": "Virtual Texture Source",
6
- "keywords": [
7
- "unity"
8
- ],
9
- "license": "SEE LICENSE IN LICENSE",
5
+ "description": "Simplify WebCamera and test video handling for using Computer Vision in Unity",
10
6
  "unity": "2020.3",
11
7
  "unityRelease": "0f1",
12
- "version": "0.1.2",
13
- "type": "tool"
8
+ "keywords": [
9
+ "unity",
10
+ "cv"
11
+ ],
12
+ "documentationUrl": "https://github.com/asus4/TextureSource/tree/main",
13
+ "changelogUrl": "https://github.com/asus4/TextureSource/releases",
14
+ "licensesUrl": "https://github.com/asus4/TextureSource/blob/main/Packages/com.github.asus4.texture-source/LICENSE",
15
+ "author": {
16
+ "name": "Koki Ibukuro",
17
+ "url": "https://github.com/asus4"
18
+ },
19
+ "dependencies": {
20
+ "com.unity.modules.video": "1.0.0"
21
+ }
14
22
  }