using Aisu.SIM1.Face.Core; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace Aisu.SIM1.Face.Samples.FaceDetectionDemo { /// /// 人脸检测 Demo 场景 UI 动态构建器。 /// public sealed class FaceDetectionDemoBootstrap : MonoBehaviour { private Font m_font; // UI 字体。 private void Awake() { Build(); } /// /// 构建 MVP 测试页面。 /// public void Build() { m_font = Resources.GetBuiltinResource("Arial.ttf"); EnsureEventSystem(); var manager = FindObjectOfType() ?? new GameObject("FaceModuleManager").AddComponent(); var camera = gameObject.AddComponent(); var logger = gameObject.AddComponent(); var userList = gameObject.AddComponent(); var controller = gameObject.AddComponent(); var canvasGo = Create("FaceDetectionDemoCanvas", transform); var canvas = canvasGo.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvasGo.AddComponent(); var scaler = canvasGo.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1280, 720); var root = Create("Root", canvasGo.transform); Stretch(root.GetComponent()); var rootLayout = root.AddComponent(); rootLayout.padding = new RectOffset(16, 16, 16, 16); rootLayout.spacing = 10; rootLayout.childControlWidth = true; rootLayout.childForceExpandWidth = true; var title = Text(root.transform, "SI-M1 Face Detection Demo", 28, TextAnchor.MiddleLeft); title.color = new Color(0.05f, 0.07f, 0.1f); var statusText = Text(root.transform, "摄像头未打开 | 模组未连接", 20, TextAnchor.MiddleLeft); statusText.color = new Color(0.12f, 0.18f, 0.24f); var body = Create("Body", root.transform); body.AddComponent().flexibleHeight = 1f; var bodyLayout = body.AddComponent(); bodyLayout.spacing = 12; bodyLayout.childControlHeight = true; bodyLayout.childForceExpandHeight = true; var left = Panel(body.transform, "LeftPanel", new Color(0.95f, 0.97f, 1f)); left.AddComponent().flexibleWidth = 1f; var leftLayout = left.AddComponent(); leftLayout.padding = new RectOffset(10, 10, 10, 10); leftLayout.spacing = 8; leftLayout.childControlWidth = true; leftLayout.childForceExpandWidth = true; var right = Panel(body.transform, "RightPanel", new Color(0.98f, 0.98f, 0.96f)); right.AddComponent().preferredWidth = 430; var rightLayout = right.AddComponent(); rightLayout.padding = new RectOffset(10, 10, 10, 10); rightLayout.spacing = 8; rightLayout.childControlWidth = true; rightLayout.childForceExpandWidth = true; var cameraDropdown = Dropdown(left.transform, "未发现摄像头"); var cameraRow = Row(left.transform); var refreshCameraButton = Button(cameraRow.transform, "刷新摄像头"); var openCameraButton = Button(cameraRow.transform, "打开摄像头"); var closeCameraButton = Button(cameraRow.transform, "关闭摄像头"); var previewFrame = Panel(left.transform, "CameraPreview", Color.black); previewFrame.AddComponent().flexibleHeight = 1f; var preview = Create("Preview", previewFrame.transform).AddComponent(); preview.color = Color.white; var previewRect = preview.GetComponent(); previewRect.anchorMin = Vector2.zero; previewRect.anchorMax = Vector2.one; previewRect.offsetMin = Vector2.zero; previewRect.offsetMax = Vector2.zero; var aspect = preview.gameObject.AddComponent(); aspect.aspectMode = AspectRatioFitter.AspectMode.FitInParent; Text(right.transform, "串口 / 模组", 22, TextAnchor.MiddleLeft); var serialDropdown = Dropdown(right.transform, "手动输入串口"); var serialInput = Input(right.transform, "串口名,例如 COM3 或 /dev/ttyUSB0"); var baudInput = Input(right.transform, "115200"); var serialRow = Row(right.transform); var refreshSerialButton = Button(serialRow.transform, "刷新串口"); var connectButton = Button(serialRow.transform, "连接模组"); var disconnectButton = Button(serialRow.transform, "断开模组"); Text(right.transform, "人脸操作", 22, TextAnchor.MiddleLeft); var userNameInput = Input(right.transform, "User"); var adminToggle = Toggle(right.transform, "管理员", false); var faceRow = Row(right.transform); var enrollButton = Button(faceRow.transform, "录入人脸"); var verifyButton = Button(faceRow.transform, "检测人脸"); var resultText = Text(right.transform, "结果: -", 20, TextAnchor.UpperLeft); resultText.gameObject.AddComponent().preferredHeight = 58; Text(right.transform, "人脸数据", 22, TextAnchor.MiddleLeft); var userButtonRow = Row(right.transform); var refreshUsersButton = Button(userButtonRow.transform, "刷新用户列表"); var userScroll = ScrollView(right.transform, out var userContent); userScroll.GetComponent().preferredHeight = 170; Text(root.transform, "操作日志", 22, TextAnchor.MiddleLeft); var logRow = Row(root.transform); var clearLogButton = Button(logRow.transform, "清空日志"); var logScroll = ScrollView(root.transform, out var logContent); logScroll.GetComponent().preferredHeight = 150; var logText = Text(logContent, string.Empty, 18, TextAnchor.UpperLeft); logText.font = m_font; logText.color = Color.white; logText.horizontalOverflow = HorizontalWrapMode.Wrap; logText.verticalOverflow = VerticalWrapMode.Overflow; logText.gameObject.AddComponent().flexibleWidth = 1f; logContent.gameObject.GetComponent().color = new Color(0.07f, 0.08f, 0.09f); camera.Bind(preview, aspect, logger); logger.Bind(logText, logScroll); userList.Bind(userContent, m_font, controller.DeleteUser); controller.Bind(manager, camera, logger, userList, cameraDropdown, serialDropdown, serialInput, baudInput, userNameInput, adminToggle, statusText, resultText); refreshCameraButton.onClick.AddListener(controller.RefreshCameras); openCameraButton.onClick.AddListener(controller.OpenCamera); closeCameraButton.onClick.AddListener(controller.CloseCamera); refreshSerialButton.onClick.AddListener(controller.RefreshSerialPorts); connectButton.onClick.AddListener(controller.ConnectModule); disconnectButton.onClick.AddListener(controller.DisconnectModule); enrollButton.onClick.AddListener(controller.EnrollFace); verifyButton.onClick.AddListener(controller.VerifyFace); refreshUsersButton.onClick.AddListener(controller.RefreshUsers); clearLogButton.onClick.AddListener(logger.Clear); } private static void EnsureEventSystem() { if (FindObjectOfType() != null) { return; } var eventSystem = new GameObject("EventSystem"); eventSystem.AddComponent(); eventSystem.AddComponent(); } private GameObject Panel(Transform parent, string name, Color color) { var go = Create(name, parent); go.AddComponent().color = color; return go; } private GameObject Row(Transform parent) { var row = Create("Row", parent); var layout = row.AddComponent(); layout.spacing = 8; layout.childControlWidth = true; layout.childForceExpandWidth = true; row.AddComponent().preferredHeight = 44; return row; } private Button Button(Transform parent, string text) { var go = Create(text, parent); go.AddComponent().color = new Color(0.78f, 0.86f, 0.95f); var button = go.AddComponent