Skip to content

Commit fa9e595

Browse files
committed
Fix WebCamWebGL
1 parent 1fda06e commit fa9e595

File tree

5 files changed

+167
-7
lines changed

5 files changed

+167
-7
lines changed

Packages/webxr-interactions/Runtime/Plugins.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/webxr-interactions/Runtime/Plugins/WebGL.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
var LibraryFixWebCamWebGL = {
2+
$webcamBufferToTextureTable: {},
3+
$webcamLatestTextureId: 0,
4+
$disableNextSubImage: false,
5+
6+
glTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, type, pixels) {
7+
if (disableNextSubImage) {
8+
disableNextSubImage = false;
9+
return;
10+
}
11+
if (GL.currentContext.supportsWebGL2EntryPoints) {
12+
if (GLctx.currentPixelUnpackBufferBinding) {
13+
GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels)
14+
} else if (pixels != 0) {
15+
GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, emscriptenWebGLGetHeapForType(type), pixels >> emscriptenWebGLGetShiftForType(type))
16+
} else {
17+
GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, null)
18+
}
19+
return
20+
}
21+
var pixelData = null;
22+
if (pixels)
23+
pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, 0);
24+
GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixelData)
25+
},
26+
27+
JS_WebCamVideo_SetLatestTextureId: function(textureId) {
28+
webcamLatestTextureId = textureId;
29+
},
30+
31+
JS_WebCamVideo_RemoveWhereTextureId: function(textureId) {
32+
Object.entries(webcamBufferToTextureTable).forEach(function (pair) {
33+
if (pair[1] == textureId) {
34+
delete webcamBufferToTextureTable[pair[0]];
35+
}
36+
});
37+
},
38+
39+
JS_WebCamVideo_GrabFrame: function(deviceId, buffer, destWidth, destHeight) {
40+
var videoElement;
41+
if (typeof activeWebCams !== "undefined") {
42+
var webcamDevice = activeWebCams[deviceId];
43+
if (!webcamDevice)
44+
return;
45+
var timeNow = performance.now();
46+
if (timeNow < webcamDevice.nextFrameAvailableTime) {
47+
return;
48+
}
49+
webcamDevice.nextFrameAvailableTime += webcamDevice.frameLengthInMsecs;
50+
if (webcamDevice.nextFrameAvailableTime < timeNow) {
51+
webcamDevice.nextFrameAvailableTime = timeNow + webcamDevice.frameLengthInMsecs
52+
}
53+
videoElement = webcamDevice.video;
54+
}
55+
if (typeof MediaDevices !== "undefined") {
56+
if (!MediaDevices[deviceId].video) {
57+
console.error("WebCam not initialized.");
58+
return;
59+
}
60+
videoElement = MediaDevices[deviceId].video;
61+
}
62+
if (!webcamBufferToTextureTable[buffer]) {
63+
if (!webcamLatestTextureId) {
64+
return;
65+
}
66+
webcamBufferToTextureTable[buffer] = webcamLatestTextureId;
67+
GLctx.deleteTexture(GL.textures[webcamBufferToTextureTable[buffer]]);
68+
var t = GLctx.createTexture();
69+
t.name = webcamBufferToTextureTable[buffer];
70+
GL.textures[webcamBufferToTextureTable[buffer]] = t;
71+
GLctx.bindTexture(GLctx.TEXTURE_2D, t);
72+
GLctx.texParameteri(GLctx.TEXTURE_2D, GLctx.TEXTURE_WRAP_S, GLctx.CLAMP_TO_EDGE);
73+
GLctx.texParameteri(GLctx.TEXTURE_2D, GLctx.TEXTURE_WRAP_T, GLctx.CLAMP_TO_EDGE);
74+
GLctx.texParameteri(GLctx.TEXTURE_2D, GLctx.TEXTURE_MIN_FILTER, GLctx.LINEAR);
75+
webcamLatestTextureId = 0
76+
} else {
77+
GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[webcamBufferToTextureTable[buffer]])
78+
}
79+
GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, true);
80+
GLctx.texImage2D(GLctx.TEXTURE_2D, 0, GLctx.RGBA, GLctx.RGBA, GLctx.UNSIGNED_BYTE, videoElement);
81+
GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, false);
82+
disableNextSubImage = true;
83+
return 1;
84+
}
85+
};
86+
87+
autoAddDeps(LibraryFixWebCamWebGL, '$webcamBufferToTextureTable');
88+
autoAddDeps(LibraryFixWebCamWebGL, '$webcamLatestTextureId');
89+
autoAddDeps(LibraryFixWebCamWebGL, '$disableNextSubImage');
90+
mergeInto(LibraryManager.library, LibraryFixWebCamWebGL);

Packages/webxr-interactions/Runtime/Plugins/WebGL/FixWebCamWebGL.jslib.meta

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/webxr-interactions/Runtime/Scripts/PlayWebcam.cs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1+
using System;
12
using System.Collections;
3+
#if UNITY_WEBGL && !UNITY_EDITOR
4+
using System.Runtime.InteropServices;
5+
#endif
26
using UnityEngine;
37

48
public class PlayWebcam : MonoBehaviour
59
{
10+
#if UNITY_WEBGL && !UNITY_EDITOR
11+
[DllImport("__Internal")]
12+
public static extern void JS_WebCamVideo_SetLatestTextureId(System.IntPtr textureId);
13+
14+
[DllImport("__Internal")]
15+
public static extern void JS_WebCamVideo_RemoveWhereTextureId(System.IntPtr textureId);
16+
#endif
17+
618
[SerializeField]
719
private string thresholdMinName = "_ThresholdMin";
820
[SerializeField]
@@ -14,10 +26,11 @@ public class PlayWebcam : MonoBehaviour
1426

1527
private Material material;
1628
private bool hasThresholdProperties = false;
17-
private int thresholdMinID = 0;
18-
private int thresholdMaxID = 0;
29+
private int thresholdMinID = -1;
30+
private int thresholdMaxID = -1;
1931
private Color thresholdMinColor;
2032
private Color thresholdMaxColor;
33+
private IntPtr latestWebcamPtr = IntPtr.Zero;
2134

2235
private int defaultWidth = 1280;
2336
private int defaultHeight = 720;
@@ -36,15 +49,17 @@ void TrySetupRenderer()
3649
_renderer.sharedMaterial = material;
3750
hasThresholdProperties = false;
3851
thresholdMinID = material.shader.FindPropertyIndex(thresholdMinName);
39-
if (thresholdMinID > -1)
52+
if (thresholdMinID == -1)
4053
{
41-
thresholdMinID = material.shader.GetPropertyNameId(thresholdMinID);
54+
return;
4255
}
56+
thresholdMinID = material.shader.GetPropertyNameId(thresholdMinID);
4357
thresholdMaxID = material.shader.FindPropertyIndex(thresholdMaxName);
44-
if (thresholdMaxID > -1)
58+
if (thresholdMaxID == -1)
4559
{
46-
thresholdMaxID = material.shader.GetPropertyNameId(thresholdMaxID);
60+
return;
4761
}
62+
thresholdMaxID = material.shader.GetPropertyNameId(thresholdMaxID);
4863
thresholdMinColor = material.GetColor(thresholdMinID);
4964
thresholdMaxColor = material.GetColor(thresholdMaxID);
5065
hasThresholdProperties = true;
@@ -76,16 +91,23 @@ void Play()
7691
transform.localScale = new Vector3(ratio, 1f, 1f);
7792
material.mainTexture = webcamTexture;
7893
}
94+
latestWebcamPtr = webcamTexture.GetNativeTexturePtr();
95+
#if UNITY_WEBGL && !UNITY_EDITOR
96+
JS_WebCamVideo_RemoveWhereTextureId(latestWebcamPtr);
97+
#endif
7998
webcamTexture.Play();
8099
StartCoroutine(SetScale());
81100
}
82101

83102
IEnumerator SetScale()
84103
{
85-
while (!webcamTexture.isPlaying || webcamTexture.height == 16)
104+
while (webcamTexture.GetNativeTexturePtr() == latestWebcamPtr)
86105
{
87106
yield return null;
88107
}
108+
#if UNITY_WEBGL && !UNITY_EDITOR
109+
JS_WebCamVideo_SetLatestTextureId(webcamTexture.GetNativeTexturePtr());
110+
#endif
89111
float ratio = (float)webcamTexture.width / (float)webcamTexture.height;
90112
transform.localScale = new Vector3(ratio, 1f, 1f);
91113
}

0 commit comments

Comments
 (0)