iOS 使用陀螺仪实现裸眼3d效果

请添加图片描述

请添加图片描述

直接上完整代码

//
//  BannerView.m
//  Test
//
//  Created by liubo on 2023/7/20.
//#import "LB3DBannerView.h"
#import <Masonry/Masonry.h>
#import <CoreMotion/CoreMotion.h>@interface LB3DBannerView (){CGFloat maxOffset;CGFloat lastGravigyX;CGFloat lastGravityY;NSTimeInterval deviceMotionUpdateInterval;CGPoint frontImageViewCenter;CGPoint secondFrontImageViewCenter;CGPoint backImageViewCenter;
}@property (nonatomic, strong) UIImageView *frontImageView;@property (nonatomic, strong) UIImageView *secondFrontImageView;@property (nonatomic, strong) UIImageView *middleImageView;@property (nonatomic, strong) UIImageView *backImageView;@property (nonatomic, strong) CMMotionManager *motionManager;@end@implementation LB3DBannerView- (instancetype)initWithFrame:(CGRect)frame
{if (self = [super initWithFrame:frame]) {[self setUpUI];[self setUpContraints];self.clipsToBounds = YES;}return self;
}- (void)setUpUI
{maxOffset = 15;deviceMotionUpdateInterval = 1 / 120.0;frontImageViewCenter = CGPointZero;backImageViewCenter = CGPointZero;secondFrontImageViewCenter = CGPointZero;[self addSubview:self.backImageView];[self addSubview:self.middleImageView];[self addSubview:self.secondFrontImageView];[self addSubview:self.frontImageView];
}- (void)setUpContraints {[self.backImageView mas_makeConstraints:^(MASConstraintMaker *make) {make.width.equalTo(self.mas_width).with.offset(maxOffset * 2);make.height.equalTo(self.mas_height).with.offset(maxOffset * 2);make.centerX.mas_equalTo(0);make.centerY.mas_equalTo(0);}];[self.middleImageView mas_makeConstraints:^(MASConstraintMaker *make) {make.width.equalTo(self.mas_width).with.offset(maxOffset * 2/3);make.height.equalTo(self.mas_height).with.offset(maxOffset * 2/3);make.centerX.mas_equalTo(0);make.centerY.mas_equalTo(0);}];[self.secondFrontImageView mas_makeConstraints:^(MASConstraintMaker *make) {make.width.equalTo(self.mas_width).with.offset(maxOffset);make.height.equalTo(self.mas_height).with.offset(maxOffset);make.centerX.mas_equalTo(0);make.centerY.mas_equalTo(0);}];[self.frontImageView mas_makeConstraints:^(MASConstraintMaker *make) {make.width.equalTo(self.mas_width).with.offset(maxOffset *  2);make.height.equalTo(self.mas_height).with.offset(maxOffset * 2);make.centerX.centerY.mas_equalTo(0);}];
}- (void)layoutSubviews
{[super layoutSubviews];backImageViewCenter = self.center;frontImageViewCenter = self.center;
}- (void)start
{[self startMotion];
}- (void)stop
{[self.motionManager stopDeviceMotionUpdates];
}- (void)updateWithArray:(NSArray *)imageNames
{self.frontImageView.image = [UIImage imageNamed:imageNames[0]];self.secondFrontImageView.image = [UIImage imageNamed:imageNames[1]];self.middleImageView.image = [UIImage imageNamed:imageNames[2]];self.backImageView.image = [UIImage imageNamed:imageNames[3]];}- (void)startMotion
{if (!self.motionManager.isDeviceMotionAvailable) {return;}__weak LB3DBannerView *weakSelf = self;[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {if (!motion) {return;}[weakSelf updateWithGravityX:motion.gravity.xgravityY:motion.gravity.ygravityZ:motion.gravity.z];}];
}- (void)updateWithGravityX:(double)gravityXgravityY:(double)gravityYgravityZ:(double)gravityZ
{//因为在斜向上45度角的时候,gravity的值是-0.5,设计要求以这个位置为基准,所以要减去-0.5gravityY -= (-0.5);gravityY *= 2;//最大的便宜量是maxoffset,所以gravityY最大为1gravityY = MIN(1, MAX(-1, gravityY));gravityX *= 2;gravityX = MIN(1, MAX(-1, gravityX));double timeInterval = sqrt(pow((gravityX - lastGravigyX),2) + pow((gravityY - lastGravityY), 2)) * deviceMotionUpdateInterval;NSString *animationKey = @"positionAnimation";CGPoint newBackImageViewCenter = self.backImageView.center;newBackImageViewCenter.x = (newBackImageViewCenter.x - gravityX * maxOffset);newBackImageViewCenter.y = (newBackImageViewCenter.y + gravityY * maxOffset);CABasicAnimation *backImageViewAnimation = [CABasicAnimation animationWithKeyPath:@"position"];backImageViewAnimation.fromValue = [NSValue valueWithCGPoint:backImageViewCenter];backImageViewAnimation.toValue = [NSValue valueWithCGPoint:newBackImageViewCenter];backImageViewAnimation.duration = timeInterval;backImageViewAnimation.fillMode = kCAFillModeForwards;backImageViewAnimation.removedOnCompletion = NO;[self.backImageView.layer removeAnimationForKey:animationKey];[self.backImageView.layer addAnimation:backImageViewAnimation forKey:animationKey];CGPoint newFrontImageViewCenter = self.frontImageView.center;newFrontImageViewCenter.x += gravityX * maxOffset;newFrontImageViewCenter.y -= gravityY * maxOffset;CABasicAnimation *frontImageViewAnimation = [CABasicAnimation animationWithKeyPath:@"position"];frontImageViewAnimation.fromValue = [NSValue valueWithCGPoint:frontImageViewCenter];frontImageViewAnimation.toValue = [NSValue valueWithCGPoint:newFrontImageViewCenter];frontImageViewAnimation.duration = timeInterval;frontImageViewAnimation.fillMode = kCAFillModeForwards;frontImageViewAnimation.removedOnCompletion = NO;[self.frontImageView.layer removeAnimationForKey:animationKey];[self.frontImageView.layer addAnimation:frontImageViewAnimation forKey:animationKey];CGPoint newSecondFrontImageViewCenter = self.middleImageView.center;newSecondFrontImageViewCenter.x -= gravityX * maxOffset/3;newSecondFrontImageViewCenter.y += gravityY * maxOffset/3;CABasicAnimation *secondfrontImageViewAnimation = [CABasicAnimation animationWithKeyPath:@"position"];secondfrontImageViewAnimation.fromValue = [NSValue valueWithCGPoint:secondFrontImageViewCenter];secondfrontImageViewAnimation.toValue = [NSValue valueWithCGPoint:newSecondFrontImageViewCenter];secondfrontImageViewAnimation.duration = timeInterval;secondfrontImageViewAnimation.fillMode = kCAFillModeForwards;secondfrontImageViewAnimation.removedOnCompletion = NO;[self.middleImageView.layer removeAnimationForKey:animationKey];[self.middleImageView.layer addAnimation:secondfrontImageViewAnimation forKey:animationKey];backImageViewCenter = newBackImageViewCenter;frontImageViewCenter = newFrontImageViewCenter;secondFrontImageViewCenter = newSecondFrontImageViewCenter;
}#pragma mark - lazy load- (UIImageView *)frontImageView
{if (!_frontImageView) {_frontImageView = [[UIImageView alloc] init];_frontImageView.contentMode = UIViewContentModeScaleAspectFill;}return _frontImageView;
}- (UIImageView *)secondFrontImageView
{if (!_secondFrontImageView) {_secondFrontImageView = [[UIImageView alloc] init];_secondFrontImageView.contentMode = UIViewContentModeScaleAspectFill;}return _secondFrontImageView;
}- (UIImageView *)middleImageView
{if (!_middleImageView) {_middleImageView = [[UIImageView alloc] init];_middleImageView.contentMode = UIViewContentModeScaleAspectFill;}return _middleImageView;
}- (UIImageView *)backImageView
{if (!_backImageView) {_backImageView = [[UIImageView alloc] init];_backImageView.contentMode = UIViewContentModeScaleAspectFill;}return _backImageView;
}- (CMMotionManager *)motionManager
{if (!_motionManager) {_motionManager = [[CMMotionManager alloc] init];_motionManager.deviceMotionUpdateInterval = deviceMotionUpdateInterval;}return _motionManager;
}@end

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

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

相关文章

基于GBDT+Tkinter+穷举法按排队时间预测最优路径的智能导航推荐系统——机器学习算法应用(含Python工程源码)+数据集(四)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境Pycharm 环境Scikit-learnt 模块实现1. 数据预处理2. 客流预测3. 百度地图API调用4. GUI界面设计5. 路径规划6. 智能推荐 系统测试1. 训练准确率2. 测试效果3. 程序应用 相关其它博客工程源代码下载其它资料下载 …

eslint代码校验及修复(Vue项目快速上手)

项目中配置eslint校验 文章目录 项目中配置eslint校验前言1. webpack5搭建 Vue项目如下🔗(可以查看)2. eslint+prettier Vue项目如下🔗(暂时未更新)一、什么是 ESLint?二、为什么要使用 ESLint?三、如何在 Vue 项目中集成 ESLint?3.1.安装依赖代码如下:如下图所示3…

PASCAL VOC2012数据集详细介绍

PASCAL VOC2012数据集详细介绍 0、数据集介绍2、Pascal VOC数据集目标类别3、 数据集下载与目录结构4、目标检测任务5、语义分割任务6、实例分割任务7、类别索引与名称对应关系 0、数据集介绍 2、Pascal VOC数据集目标类别 在Pascal VOC数据集中主要包含20个目标类别&#xff…

STM32 OLED屏幕显示详解

目录 1.OLED介绍 2.OLED如何显示一个点&#xff1f; 内存管理​编辑​编辑 页地址模式 水平地址模式​编辑 垂直地址模式 ​编辑 3.OLED显示图片 用到的库函数&#xff1a; 向OLED写命令的封装&#xff1a; 显示图片代码示例&#xff1a; 1.OLED介绍 OLED是有机发光…

代码随想录算法训练营第三十六天| 435. 无重叠区间 763.划分字母区间 56. 合并区间

今天的三道题目&#xff0c;都算是 重叠区间 问题&#xff0c;大家可以好好感受一下。 都属于那种看起来好复杂&#xff0c;但一看贪心解法&#xff0c;惊呼&#xff1a;这么巧妙&#xff01; 还是属于那种&#xff0c;做过了也就会了&#xff0c;没做过就很难想出来。 不过大…

macos (M2芯片)搭建flutter环境

安装的版本3.13.4、电脑上没有安装过android studio、安装过brew 1.在终端运行sudo softwareupdate --install-rosetta --agree-to-license&#xff0c;下图展示安装成功的效果 2.下载以下安装包来获取最新的 stable Flutter SDK 3.解压&#xff0c;⚠️注意下载安装sdk的包名…

利用fiddler正向代理前端请求到本地后端

前景&#xff1a;在实际开发测试环境中&#xff0c;&#xff08;前后端均已上线到测试服务器或前端以上线而后端还在开发中)。在测试过程中&#xff08;前端页面点击&#xff0c;功能测试&#xff09;发现了bug或异常点。 正常排查问题可能是先利用浏览器检查工具查看接口的返回…

Redis 面试题

Redis 面试题 Q:Redis有哪些优势&#xff1f; 速度快&#xff0c;因为数据存在内存中支持丰富数据类型&#xff0c;支持string&#xff0c;list&#xff0c;set&#xff0c;sorted set&#xff0c;hash支持事务&#xff0c;操作都是原子性&#xff0c;所谓的原子性就是对数据…

交换机端口镜像详解

交换机端口镜像是一种网络监控技术&#xff0c;它允许将一个或多个交换机端口的网络流量复制并重定向到另一个端口上&#xff0c;以便进行流量监测、分析和记录。通过端口镜像&#xff0c;管理员可以实时查看特定端口上的流量&#xff0c;以进行网络故障排查、安全审计和性能优…

Vue.js vs React:哪一个更适合你的项目?

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

[NLP] LLM---<训练中文LLama2(五)>对SFT后的LLama2进行DPO训练

当前关于LLM的共识 大型语言模型&#xff08;LLM&#xff09;使 NLP 中微调模型的过程变得更加复杂。最初&#xff0c;当 ChatGPT 等模型首次出现时&#xff0c;最主要的方法是先训练奖励模型&#xff0c;然后优化 LLM 策略。从人类反馈中强化学习&#xff08;RLHF&#xff09…

优化系统报错提示信息,提高人机交互(一)

1、常规报错及处理 package com.example.demo.controller;import com.example.demo.service.IDemoService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.w…

【JAVA】idea初步使用+JDK详细配置

1、官方下载idea 官网&#xff1a;Download IntelliJ IDEA – The Leading Java and Kotlin IDE (1)、下载教程 我下载没截屏&#xff0c;详细教程请看 原文&#xff1a;手把手教你JDKIDEA的安装和环境配置_idea配置jdk_快到锅里来呀的博客-CSDN博客 2、启动项目时候需要配置J…

Spring事件机制之ApplicationEvent

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

全栈性能测试工具:RunnerGo

随着自动化测试技术的不断进步&#xff0c;自动化测试已成为企业级应用的重要组成部分。然而&#xff0c;传统的性能测试工具往往复杂、繁琐&#xff0c;让企业陷入了两难的境地。软件测试正逐渐从手动测试向自动化测试转变&#xff0c;各种自动化测试工具和框架层出不穷&#…

手撕 LFU 缓存

大家好&#xff0c;我是 方圆。LFU 的缩写是 Least Frequently Used&#xff0c;简单理解则是将使用最少的元素移除&#xff0c;如果存在多个使用次数最小的元素&#xff0c;那么则需要移除最近不被使用的元素。LFU 缓存在 LeetCode 上是一道困难的题目&#xff0c;实现起来并不…

【Godot】解决游戏中的孤立/孤儿节点及分析器性能问题的分析处理

Godot 4.1 因为我在游戏中发现&#xff0c;越运行游戏变得越来越卡&#xff0c;当你使用 Node 节点中的 print_orphan_nodes() 方法打印信息的时候&#xff0c;会出现如下的孤儿节点信息 孤儿节点信息是以 节点实例ID - Stray Node: 节点名称(Type: 节点类型) 作为格式输出&a…

腾讯mini项目-【指标监控服务重构】2023-08-23

今日已办 进度和问题汇总 请求合并 feature/venus tracefeature/venus metricfeature/profile-otel-baserunner-stylebugfix/profile-logger-Syncfeature/profile_otelclient_enable_config 完成otel 开关 trace-采样metrice-reader 已经都在各自服务器运行&#xff0c;并接入…

创造性地解决冲突

1、冲突的根本原因是矛盾双方存在不可调和的目标冲突。 2、要知己知彼&#xff1a; 知己&#xff1a;就是对自己的问题、需求进行客观定义&#xff0c;说明需求和问题的意义或价值、阐述解决方案和期望效果&#xff1b; 知彼&#xff1a;站在对方立场&#xff0c;深挖对方真…

根据3d框的八个顶点坐标,求他的中心点,长宽高和yaw值(Python)

要从一个3D框的八个顶点求出它的中心点、长、宽、高和yaw值&#xff0c;首先需要明确框的几何形状和坐标点的顺序。通常这样的框是一个矩形体&#xff08;长方体&#xff09;&#xff0c;但其方向并不一定与坐标轴平行。 以下是一个步骤来解决这个问题&#xff1a; 求中心点&a…