尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从点击到选中座位:Shinkansen 3D Seat Booking Prototype 的 SceneKit HitTest 与位掩码交互技巧

从点击到选中座位:Shinkansen 3D Seat Booking Prototype 的 SceneKit HitTest 与位掩码交互技巧 从点击到选中座位Shinkansen 3D Seat Booking Prototype 的 SceneKit HitTest 与位掩码交互技巧【免费下载链接】shinkansen-3d-seat-booking-prototypeExample of 3D Integration to Visualize Train Seat Map in iOS项目地址: https://gitcode.com/gh_mirrors/sh/shinkansen-3d-seat-booking-prototypeShinkansen 3D Seat Booking Prototype是一个用苹果原生SceneKit3D 引擎打造的 iOS 开源示例把日本新干线的车厢座椅图渲染成实时 3D 场景。这个项目最精彩的部分就是它如何让手指点中座位通过hitTest命中测试精确定位按下的 3D 对象并用categoryBitMask位掩码给不同对象划分通道优雅地解决了两个棘手问题——点错对象以及透视视角下屏幕拖动如何换算成深度位移。本文面向新手拆解这条点击 → 高亮 → 选中 → 震动反馈的完整交互链路。3D 座位图交互为什么 3D 场景里触摸很难听到移动端 3D大多数人会想到 3D 游戏。而本项目的目标更朴素把真实空间可视化让用户看着真实的 3D 车厢来决定选哪个座位。在 README.md 中作者提到 SceneKit 的SCNView本身就是UIView的子类因此 3D 场景能无缝嵌入原生 UIKit 流程。座位图页面有两个核心交互点按座位高亮 → 选中 → 震动 → 自动推近到座位位置 上下拖动屏幕整节车厢沿深度方向流动带惯性与软边界难点在第一个交互3D 场景里有成百上千个节点座架、坐垫、扶手、地板、阴影……手指按到的往往只是模型的某个小零件而不是座位对象本身。HitTest 命中测试快速上手如何找到手指按下的对象SceneKit 提供了hitTest(_:options:)方法给它一个屏幕二维坐标它返回按距相机由近到远排序的SCNHitTestResult列表——第一个元素就是手指按到的最上层对象。新手陷阱一个座位模型是几十个小几何节点组成的树不做过滤直接命中测试返回的可能是坐垫子节点根本判断不出用户点的是哪个座位。本项目用两层设计解决这个问题位掩码过滤 递归找父节点categoryBitMask 位掩码给节点分频道SceneKit 中每个节点都有一个categoryBitMask32 位整数。做命中测试时可以传入.categoryBitMask选项只命中位匹配上的节点——相当于给对象类型分频道各取所需。项目里定义了关键的两类频道频道值分配给用途1 12隐形地板节点HitTestFloorNode.swift拖动时屏幕坐标 → 深度坐标换算1 24所有可交互座位InteractiveNode.swift座位点选的命中测试两个关键细节地板看不见却参与命中测试。HitTestFloorNode.swift 把SCNFloor材质transparency设为 0完全透明、reflectivity设为 0无反射放在y 1.3的高度——用户看不见它但它仍是命中测试的标尺。位掩码要递归打满。NodeFactory.swift 中的applyInteractiveCategoryBitmask会递归遍历子节点树把同一个掩码盖到座位模型的每一片几何上确保点中哪个零件都能被过滤命中。从点击到选中三步搭出精确选座链路交互核心在 SeatMapSceneView.swift它直接继承SCNView自己接管触摸事件。第 1 步手指按下先高亮候选座位touchesBegan中对每个手指调用filterReservationNodeFromSeatMapSceneView.swift#L543-L555核心逻辑就一行let firstHitTestResult hitTest(touch.location(in: self), options: [.categoryBitMask: SeatNode.defaultBitMask]).first掩码选项SeatNode.defaultBitMask即1 2保证只命中座位这一频道只取.first即离相机最近的对象——手指按到的是最上层。命中的座位被加入highlightedSeatNodes集合集合的didSet只更新差集新增的高亮、移除的取消高亮多点触控也不会闪烁。第 2 步手指抬起确认选中 震动反馈touchesEnded时再次把手指和高亮集合做匹配只有起点就按在高亮座位上的那次点击才算有效选中。选中成功后项目一口气做三件事触发UIImpactFeedbackGenerator轻震动反馈 屏幕顶部弹出 HeadsUp 提示Seat X in car Y has been selected.平滑推近动画把选中座位移动到屏幕中心第 3 步findParent 递归——从零件找回座位即使加了位掩码命中的也可能是座位模型的叶子节点坐垫、靠背……。项目用一个递归小工具兜底func findParent(of node: SCNNode?) - SeatNode? { guard let node node else { return nil } if let node node as? SeatNode { return node } return findParent(of: node.parent) }从命中节点一路向上爬直到找到SeatNode容器为止。无论你点在座位的哪个部位最终都会得到携带座位数据reservableEntity的完整座位对象。透视相机 trick用隐形地板测量拖动距离这是项目里位掩码最巧妙的一处用法。常见错误拖动时把手指屏幕位移点/像素直接换算成场景 Z 位移。正交相机下没问题但本项目用的是透视相机CameraNode.swiftFOV 64°——同一屏幕位移在深度近处和远处对应完全不同的世界位移手感会忽快忽慢。项目方案拿隐形地板频道1 1当标尺拖动开始时对地板做一次命中测试记录起点世界坐标拖动过程中对当前位置再命中一次地板取当前世界坐标两者的z差值就是当前深度层应有的场景位移手感恒定。对应实现positionOfFloorHitTestSeatMapSceneView.swift#L563-L566let hitTests hitTest(point, options: [.categoryBitMask : 1 1]) return hitTests.first?.worldCoordinates随后zPositionClamp用对数函数做软边界修正接近边界时位移逐渐衰减拖不出去却还能带一点手感自然手指抬起后SCNAction.customAction配合衰减函数实现惯性漂移并在越界时自动回弹到合法区间。五态状态机normal、highlighted、selected、disabled、focus座位的视觉状态由 InteractiveNode.swift 中的State状态机管理共五种normal / highlighted / selected / disabled / focus。巧妙之处在于初始化时把座位模型的所有SCNMaterial递归收集进materialMap材质命名遵循xxx-normal、xxx-highlighted、xxx-selected等约定状态切换时只按状态名替换材质并播放一次微动画无需重建节点暗色模式还额外处理了-darkMode后缀材质。状态与模型彻底解耦同一份座位模型靠材质命名约定获得 5 套外观交互代码只改状态即可。复用这套思路的 6 条清单想把命中测试 位掩码模式搬进自己的 SceneKit 项目照着做按交互类型给节点分类可交互对象、测量用辅助几何、纯装饰各占一个独立的位1 n位掩码必须递归应用到整棵节点树——SceneKit 的命中测试发生在几何体粒度命中结果永远取.first最近的对象才是最上层用递归findParent把叶子节点映射回业务对象透视场景里用隐形平面地板命中测试做屏幕 → 世界坐标换算别直接乘系数硬算采用按下高亮 → 抬起确认两阶段触摸并叠加震动反馈选座成功率与质感都会明显提升 ✅相关源码索引3D 场景视图、手势与选座主链路SeatMapSceneView.swift隐形命中测试地板HitTestFloorNode.swift交互节点与五态状态机InteractiveNode.swift节点工厂与位掩码递归应用NodeFactory.swift透视相机参数设置CameraNode.swift小结Shinkansen 3D Seat Booking Prototype 用一个小巧的项目证明好的 3D 交互不依赖重型框架而在于把基础工具用巧。hitTest命中测试 categoryBitMask位掩码 一块隐形命中地板就把点一下座位拆成了一条清晰、可维护的交互流水线。对想入门 SceneKit 交互开发的新手来说这个项目堪称实用而非炫技的教科书案例。【免费下载链接】shinkansen-3d-seat-booking-prototypeExample of 3D Integration to Visualize Train Seat Map in iOS项目地址: https://gitcode.com/gh_mirrors/sh/shinkansen-3d-seat-booking-prototype创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表