You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity WebGL构建中无法设置WebcamTexture分辨率求助

Unity WebGL WebCamTexture 分辨率设置无效(始终480×640)解决方案

问题原因

Unity WebGL平台下,WebCamTexture的requestedWidth/requestedHeight参数无法直接生效,本质是因为WebGL依赖浏览器的getUserMedia API,而浏览器仅允许选择摄像头硬件支持的固定分辨率档位,Unity的封装逻辑在WebGL上对自定义分辨率的处理存在限制,导致默认 fallback 到480×640。

解决步骤

1. 获取浏览器支持的摄像头分辨率档位

通过JavaScript插件调用浏览器原生API,获取当前摄像头支持的所有分辨率,筛选出最接近16:9的档位。

创建Plugins/WebGL/CameraResolution.jslib文件,放入以下代码:

mergeInto(LibraryManager.library, {
    GetSupportedResolutions: function() {
        navigator.mediaDevices.getUserMedia({ video: true })
            .then(stream => {
                const track = stream.getVideoTracks()[0];
                const capabilities = track.getCapabilities();
                const resolutions = [];
                // 遍历所有支持的宽高组合
                if (capabilities.width?.values && capabilities.height?.values) {
                    for (let i = 0; i < capabilities.width.values.length; i++) {
                        resolutions.push(`${capabilities.width.values[i]}x${capabilities.height.values[i]}`);
                    }
                }
                // 关闭临时流
                stream.getTracks().forEach(track => track.stop());
                // 将结果传递给Unity
                sendMessage('CameraController', 'OnResolutionsReceived', JSON.stringify(resolutions));
            })
            .catch(err => {
                console.error('获取分辨率失败:', err);
                sendMessage('CameraController', 'OnResolutionsReceived', '[]');
            });
    }
});

2. 修改Unity C#代码适配WebGL

更新摄像头初始化逻辑,优先使用浏览器支持的16:9分辨率,若无法匹配则用RenderTexture做缩放适配:

using UnityEngine;
using System.Collections.Generic;
using System.Runtime.InteropServices;

public class CameraController : MonoBehaviour
{
    private WebCamTexture _camTexture;
    public Renderer _displayRenderer;
    private int _currentCamIndex = 0;

    [DllImport("__Internal")]
    private static extern void GetSupportedResolutions();

    // 接收JS传递的分辨率列表
    public void OnResolutionsReceived(string jsonResolutions)
    {
        var resList = new List<string>(JsonUtility.FromJson<string[]>(jsonResolutions));
        var targetRatio = 16f / 9f;
        Vector2Int bestRes = Vector2Int.zero;
        float closestRatioDiff = float.MaxValue;

        foreach (var res in resList)
        {
            var parts = res.Split('x');
            if (parts.Length != 2) continue;
            
            if (int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
            {
                float currentRatio = (float)w / h;
                float diff = Mathf.Abs(currentRatio - targetRatio);
                
                // 优先选择比例最接近且分辨率较高的
                if (diff < closestRatioDiff || (diff == closestRatioDiff && w > bestRes.x))
                {
                    closestRatioDiff = diff;
                    bestRes = new Vector2Int(w, h);
                }
            }
        }

        // 启动摄像头,找不到匹配分辨率则 fallback 到1280x720
        StartCoroutine(InitCamera(bestRes.x > 0 ? bestRes.x : 1280, bestRes.y > 0 ? bestRes.y : 720));
    }

    private IEnumerator InitCamera(int targetWidth, int targetHeight)
    {
        // 清理旧的摄像头资源
        if (_camTexture != null)
        {
            _displayRenderer.material.mainTexture = null;
            _camTexture.Stop();
            _camTexture = null;
            yield return null;
        }

        // 初始化摄像头
        var device = WebCamTexture.devices[_currentCamIndex];
        _camTexture = new WebCamTexture(device.name, targetWidth, targetHeight, 24);
        _displayRenderer.material.mainTexture = _camTexture;
        _camTexture.Play();

        yield return new WaitForEndOfFrame();

        // 检查实际分辨率是否符合16:9,不符合则用RenderTexture缩放适配
        if (Mathf.Abs((float)_camTexture.width / _camTexture.height - 16f/9f) > 0.01f)
        {
            var rtWidth = Mathf.RoundToInt(_camTexture.height * 16f/9f);
            var renderTexture = new RenderTexture(rtWidth, _camTexture.height, 0);
            _displayRenderer.material.mainTexture = renderTexture;
            StartCoroutine(BlitCameraToRT(_camTexture, renderTexture));
        }
    }

    // 将摄像头画面实时 blit 到RenderTexture做适配
    private IEnumerator BlitCameraToRT(WebCamTexture source, RenderTexture dest)
    {
        while (source.isPlaying)
        {
            Graphics.Blit(source, dest);
            yield return null;
        }
        Destroy(dest);
    }

    private void Start()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        // WebGL平台下调用JS获取分辨率
        GetSupportedResolutions();
#else
        // 其他平台沿用原有逻辑
        StartCoroutine(InitCamera(1024, 576));
#endif
    }
}

3. 额外注意事项

  • WebGL平台需要HTTPS环境才能访问摄像头(本地localhost调试除外)。
  • 部分浏览器可能限制摄像头分辨率,需确保用户授权摄像头权限。
  • 若存在画面镜像问题,可通过设置_displayRenderer.material.mainTextureScale = new Vector2(-1, 1)修正。

内容的提问来源于stack exchange,提问作者Raphael Huot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:23:23