【iOS ARKit】PhysicsMotionComponent

      使用 Physics BodyComponent 组件,通过设置物理参数、物理材质、施加作用力,能完全模拟物体在真实世界中的行为,这种方式的优点是遵循物理学规律、控制精确,但缺点是不直观。使用 PhysicsMotion Component组件则可以通过直接设置速度进行物理模拟,但需要明白的是,对物体施加力与设置物体速度是两种完全不同且不相容的操作,无法混合使用。

     下面我们使用 PhysicsMotionComponent组件进行演示。在代上节码中,我们手工构建了模拟环境,这是件枯燥且容易出错的工作,而且很难构建复杂的场景,利用 Reality Composer 工具则可以快速地构建场最模型,本示例我们先使用 Reality Composer 构建基本的场景,然后通过设置速度的方式进行物理模拟。

     利用 Reality Composer 工具设置好各实体的大小、物理材质、碰撞属性和位置关系,然后在 Xcode 中导入 Reality 场景,具体代码如下。

//
//  PhysicsMotionView.swift
//  ARKitDeamo
//
//  Created by zhaoquan du on 2024/3/14.
//import SwiftUI
import RealityKit
import ARKitstruct PhysicsMotionView: View {var body: some View {PhysicsMotionViewContainer().navigationTitle("物理模拟2").edgesIgnoringSafeArea(.all)}
}struct PhysicsMotionViewContainer:UIViewRepresentable {func makeCoordinator() -> Coordinator {Coordinator()}func makeUIView(context: Context) -> some ARView {let arView = ARView(frame: .zero)let config = ARWorldTrackingConfiguration()config.planeDetection = .horizontalcontext.coordinator.arView = arViewcontext.coordinator.loadModel()arView.session.delegate  = context.coordinatorarView.session.run(config)return arView}func updateUIView(_ uiView: UIViewType, context: Context) {}class Coordinator: NSObject, ARSessionDelegate{var sphereEntity : ModelEntity!var arView:ARView? = nillet gameController = GameController()@MainActor func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {guard let anchor = anchors.first as? ARPlaneAnchor,let arView = arView else{return}let planeAnchor = AnchorEntity(anchor:anchor)planeAnchor.addChild(gameController.gameAnchor)arView.scene.anchors.append(planeAnchor)gameController.gameAnchor.backWall?.visit { entity inentity.components[ModelComponent.self] = nil}gameController.gameAnchor.frontWall?.visit { entity inentity.components[ModelComponent.self] = nil}gameController.Ball13?.physicsBody?.massProperties.centerOfMass = ([0.001,0,0.001],simd_quatf(angle: 0, axis:  [0,1,0]))gameController.Ball4?.physicsBody?.material = PhysicsMaterialResource.generate(friction: 0.3, restitution: 0.3)gameController.Ball6?.physicsBody?.mode = .kinematic//gameController.Ball6?.collision?.shapes.removeAll()arView.session.delegate = nilarView.session.run(ARWorldTrackingConfiguration())}@MainActor func loadModel(){gameController.gameAnchor = try! Ball.loadBallGame()if let ball = gameController.gameAnchor.motherBall as? Entity & HasCollision {let gestureRecognizers = arView?.installGestures(.translation, for: ball)if let gestureRecognizer = gestureRecognizers?.first as? EntityTranslationGestureRecognizer {gameController.gestureRecognizer = gestureRecognizergestureRecognizer.removeTarget(nil, action: nil)gestureRecognizer.addTarget(self, action: #selector(self.handleTranslation))}}}@objcfunc handleTranslation(_ recognizer: EntityTranslationGestureRecognizer) {guard let ball = gameController.motherBall else { return }let settings = gameController.settingsif recognizer.state == .ended || recognizer.state == .cancelled {gameController.gestureStartLocation = nilball.physicsBody?.mode = .dynamicreturn}guard let gestureCurrentLocation = recognizer.translation(in: nil) else { return }guard let gestureStartLocation = gameController.gestureStartLocation else {gameController.gestureStartLocation = gestureCurrentLocationreturn}let delta = gestureStartLocation - gestureCurrentLocationlet distance = ((delta.x * delta.x) + (delta.y * delta.y) + (delta.z * delta.z)).squareRoot()if distance > settings.ballPlayDistanceThreshold {gameController.gestureStartLocation = nilball.physicsBody?.mode = .dynamicreturn}ball.physicsBody?.mode = .kinematiclet realVelocity = recognizer.velocity(in: nil)let ballParentVelocity = ball.parent!.convert(direction: realVelocity, from: nil)var clampedX = ballParentVelocity.xvar clampedZ = ballParentVelocity.z// 夹断if clampedX > settings.ballVelocityMaxX {clampedX = settings.ballVelocityMaxX} else if clampedX < settings.ballVelocityMinX {clampedX = settings.ballVelocityMinX}// 夹断if clampedZ > settings.ballVelocityMaxZ {clampedZ = settings.ballVelocityMaxZ} else if clampedZ < settings.ballVelocityMinZ {clampedZ = settings.ballVelocityMinZ}let clampedVelocity: SIMD3<Float> = [clampedX, 0.0, clampedZ]ball.physicsMotion?.linearVelocity = clampedVelocity}}
}
extension Entity {func visit(using block: (Entity) -> Void) {block(self)for child in children {child.visit(using: block)}}
}
#Preview {PhysicsMotionView()
}

       在代码中,实现的功能如下:

    (1)加载模拟场景并进行相应的处理。

    (2) 通过设置物体速度,对物体运动进行物理模拟。

      在功能1中,我们首先使用 loadModel()方法加载 Reality 场景,然后通过 session(- session: ARSesion,didAdd anchors: [ARAnchor])方法对平面检测情况进行监视,当ARKit检测到符合要求的水平平面后,将加载的场景挂载到 ARAnchor 下显示,对不需要显示的四周围栏进行了隐藏处理,然后设置了各球体的物理参数、物理材质并重启了 ARSession(为更好组织代码,方便场景管理,我们使用了 GameController类,具体可以参看本节源码)。

     在功能2中为方便控制,我们使用了 RealityKit 中的平移手势EntityTranslationGesture Recognizer,通过计算使用者手指在屏幕上滑动的速度生成物体速度,并将其作为母球的速度(为防止速度过大,我们使用了 GameSettings 结构体并定义了几个边界值,具体可以参github源码),通过直接赋予母球速度值就可以观察母球与场景中其他球体在物理引擎作用下的运动效果。

      编译后测试,使用平移手势操作母球,当母球与场景中的其他球体发生碰撞时,会产生相应的物理效果。通过本例可以看到,在 Xcode中也可以修改 Reality Composer 工具中设定的各球体的物理属性,如代码清单中第15 行到第17所示,读者也可以修改不同属性看一看它们如何影响物体的行为,取消碰撞体,看一看还能不能发生撞。

具体代码地址:GitHub - duzhaoquan/ARkitDemo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/746763.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Orange3数据预处理(清理特征组件)

清理特征 移除未使用的属性值和无用的属性&#xff0c;并对剩余的值进行排序。 输入 数据: 输入数据集 输出 数据: 过滤后的数据集 命名属性定义有时包含在数据中不出现的值。即使原始数据中没有这种情况&#xff0c;数据过滤、选择示例子集等操作也可能移除…

用python开发一个性能压测框架(超级简单)

用python开发一个性能压测框架&#xff08;超级简单&#xff09; 该框架是一个基础框架&#xff0c;超级简单&#xff0c;已经跑通&#xff0c;可以进行优化扩展 由于工作需要&#xff0c;最近开发了一款python性能压测框架&#xff0c;主要是对后端接口进行多线程压测 主要…

(二十五)Flask之MTVMVC架构模式Demo【重点:原生session使用及易错点!】

目录&#xff1a; 每篇前言&#xff1a;MTV&MVC构建一个基于MTV模式的Demo项目&#xff1a;蹦出一个问题&#xff1a; 每篇前言&#xff1a; &#x1f3c6;&#x1f3c6;作者介绍&#xff1a;【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领…

性能工具部署 - 自动在30多台机器上部署发流工具,并自动配置各自的参数,一键控制所有节点工具的启动、停止、重启

需求1&#xff1a;脚本快速上传文件到制定目录并解压 import paramiko import scp import os import pexpect# SSH连接信息 ssh_host 162.14.xx ssh_port 22 # 默认的SSH端口 ssh_username root # 登录用户名 ssh_password xx # 登录密码 sudo_password xx # 登录密码…

关于Transfomer的思考

为何诞生 在说transformer是什么&#xff0c;有什么优势之类的之前&#xff0c;先谈一谈它因何而诞生。transformer诞生最重要的原因是早先的语言模型&#xff0c;比如RNN&#xff0c;由于其本身的训练机制导致其并行度不高&#xff0c;特别是遇到一些长句子的情况下。其次&…

抖音开放平台第三方开发,实现代小程序备案申请

大家好&#xff0c;我是小悟 抖音小程序备案整体流程总共分为五个环节&#xff1a;备案信息填写、平台初审、工信部短信核验、通管局审核和备案成功。 服务商可以代小程序发起备案申请。在申请小程序备案之前&#xff0c;需要确保小程序基本信息已填写完成、小程序至少存在一个…

硬件笔记(26)---- 高速电路中滤波电容的选取

先要知道电容的等效电路 其中ESL取决于电容的类型和封装&#xff0c;一般用贴片陶瓷电容为例&#xff0c;对于直插式电解电容&#xff0c;他们的ESL很大。按下表&#xff0c;封装越大&#xff0c;ESL越大&#xff0c;但是0612有些例外 0612和1206就是 长短边的区别&#xff0c;…

什么是MVC三层结构

1.MVC&#xff08;三层结构&#xff09; MVC&#xff08;Model-View-Controller&#xff09;是一种常见的软件设计模式&#xff0c;用于将应用程序的逻辑和界面分离成三个不同的组件。每个组件负责特定的任务&#xff0c;从而提高代码的可维护性和可扩展性。 以前的模式。 遇到…

力扣_动态规划3—地下城游戏

题目 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻…

一文解读ISO26262安全标准:功能安全管理

一文解读ISO26262安全标准&#xff1a;功能安全管理 1 安全生命周期1.1 概念阶段1.2 产品开发阶段1.3 生产发布后续阶段 2 安全管理的角色和职责3 安全活动的裁剪4 安全活动的评审5 安全活动的评估6 交付物 下文的表中&#xff0c;一些方法的推荐等级说明&#xff1a; “”表示…

【网络安全渗透】常见文件上传漏洞处理与防范

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属的专栏&#xff1a;网络安全渗透 景天的主页&#xff1a;景天科技苑 文章目录 1.文件上传漏洞1.1. 描述1.2. 危害1.3. 有关文件上传的知识1.4…

【兔子机器人】修改GO、车轮电机ID(软件方法、硬件方法)以及修正VMC腿部初始化夹角

一、GO电机修改ID 1、硬件方法 利用上位机直接修改GO电机的id号&#xff1a; 打开调试助手&#xff0c;点击“调试”&#xff0c;查询电机&#xff0c;修改id号&#xff0c;即可。 但先将四个GO电机连接线拔掉&#xff0c;不然会将连接的电机一并修改。 利用24V电源给GO电机…

Java_12 杨辉三角 II

杨辉三角 II 给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1] 示例 2: 输入: rowIndex 0 输出: [1] 示例 3: 输入: rowIndex 1 输…

【应急响应靶场web2】

文章目录 前言 一、应急响应 1、背景 2、webshell查杀 3、日志排查 1&#xff09;apache日志 2&#xff09;nginx日志 3&#xff09;ftp日志 4、隐藏账户 5、文件筛选 二、漏洞复现 总结 前言 靶场来源&#xff1a;知攻善防实验室 一、应急响应 1、背景 小李在某…

VMware 配置虚拟机网络

之前需要完成的任务 &#xff08;1&#xff09;、下载和安装VMware-Workstation-Pro.exe软件&#xff0c;推荐16.0版本 &#xff08;2&#xff09;、下载centOS7镜像&#xff0c;可以在阿里云下载。 &#xff08;3&#xff09;、VM创建一个虚拟机&#xff0c;并且使用本地已下载…

中东社媒Snapchat如何注册?

Snapchat是一款图片分享软件应用。利用该应用程序&#xff0c;用户可以拍照、录制影片、撰写文字和图画,并传送到自己在该应用上的好友列表。现如今&#xff0c;Snapchat也成为独立战引流然而&#xff0c;即使如此受欢迎&#xff0c;Snapchat的注册使用仍然是新手的难题&#x…

Elasticsearch8.x版本Java客户端Elasticsearch Java API Client中常用API练习

Es的java API客户端 在Es7.15版本之后&#xff0c;es官方将它的高级客户端RestHighLevelClient标记为弃用状态。同时推出了全新的java API客户端Elasticsearch Java API Client&#xff0c;该客户端也将在Elasticsearch8.0及以后版本中成为官方推荐使用的客户端。 Elasticsea…

Java基于 Springboot+Vue 的招生管理系统,前后端分离

博主介绍&#xff1a;✌程序员徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【全志H616】1 --用orangepi控制硬件

【全志H616】1 --用orangepi控制硬件 本文介绍了如歌用orangepi 控制蜂鸣器&超声波模块&#xff0c;通过键盘输入1、2、3、4来控制转动角度舵机模块&#xff1b;同时还介绍了利用全志如何配置定时器&#xff1b;以及查看H616引脚状态的命令等… 超声波模块和舵机模块的讲解…

德人合科技 | 公司办公终端、电脑文件资料 \ 数据透明加密防泄密管理软件系统

天锐绿盾是一款全面的企业级数据安全解决方案&#xff0c;它专注于为企业办公终端、电脑文件资料提供数据透明加密防泄密管理。 首页 德人合科技——www.drhchina.com 这款软件系统的主要功能特点包括&#xff1a; 1. **透明加密技术**&#xff1a; 天锐绿盾采用了透明加密技…