SceneKit_中级04_约束的使用

2022-05-13 15:57:31 浏览数 (2)

SceneKit_入门01_旋转人物

SceneKit_入门02_如何创建工程

SceneKit_入门03_节点

SceneKit_入门04_灯光

SceneKit_入门05_照相机

SceneKit_入门06_行为动画

SceneKit_入门07_几何体

SceneKit_入门08_材质

SceneKit_入门09_物理身体

SceneKit_入门10_物理世界

SceneKit_入门11_粒子系统

SceneKit_入门12_物理行为

SceneKit_入门13_骨骼动画

SceneKit_中级01_模型之间的过渡动画

SceneKit_中级02_SCNView 详细讲解

SceneKit_中级03_切换照相机视角

SceneKit_中级04_约束的使用

SceneKit_中级05_力的使用

SceneKit_中级06_场景的切换

SceneKit_中级07_动态修改属性

SceneKit_中级08_阴影详解

SceneKit_中级09_碰撞检测

SceneKit_中级10_滤镜效果制作

SceneKit_中级11_动画事件

SceneKit_高级01_GLSL

SceneKit_高级02_粒子系统深入研究

SceneKit_高级03_自定义力

SceneKit_高级04_自定义场景过渡效果

SceneKit_高级05 检测手势点击到节点

SceneKit_高级06_加载顶点、纹理、法线坐标

SceneKit_高级07_SCNProgram用法探究

SceneKit_高级08_天空盒子制作

SceneKit_高级09_雾效果

SceneKit_大神01_掉落的文字

SceneKit_大神02_弹幕来袭

SceneKit_大神03_navigationbar上的3D文字

让学习成为一种习惯

先告诉你

我们在做应用开发的时候,也会用到约束,应用中的约束,就是当一个视图变化的时候,让和他之间有约束关系的其他视图,按照一定的约束规则变化,那在游戏中,我们的约束是用来干什么的?

官方的解释:

约束能够根据你定义的规则,自动调整这些变化(位置 旋转 和 比例)

认识新朋友
  • SCNConstraint

这个是游戏中的约束类,是一个抽象的类,我们不能直接使用,但是它有3个子类可以供我们使用。

我们看这个类有哪些属性

代码语言:javascript复制
 /* 
  * 作用: 影响因子,决定约束的强度
  * 工作原理: 如果设置为1 那么在游戏每一帧渲染的时候,系统都会调整这个约束,如果你设置为0.5 在游戏的某些帧,系统不会进行约束调整 0 完全忽略约束
  * 注意 SCNTransformConstraint  对这类约束不起作用
  */
 var influenceFactor: CGFloat,默认值为 1,这是为0 时,则

接下来我们分析三个子类

  • SCNLookAtConstraint

1.作用:

让一个节点的方向,总是指向另外一个一个节点

2.怎么用? 我举个简单的例子,帮助大家理解它的用法

如果你想要玩第一视角的游戏,这是我们需要让摄像机捕捉到人物移动时的位置,这是需要给照相机节点添加一个SCNLookAtConstraint 类型的约束,就能实现这个效果。

3.原理:

其实这个约束的原理是更改节点的transform的属性

4.怎么创建

代码语言:javascript复制
 // target 就是指向的那个目标节点 
  (instancetype)lookAtConstraintWithTarget:(SCNNode *)target;

5.我们如果想要照相机的视野保持在水平面上,也就是说只沿在Y轴转动跟随目标节点,我们应该怎么做呢?

代码语言:javascript复制
// 设置下面的属性为YES,就能实现上面的效果,默认为NO
var gimbalLockEnabled: Bool
  • SCNTransformConstraint

1.作用:

创建一个转换约束(提供给节点一个新的转换的计算),当系统进行下一次渲染的时候,会重新计算这个块中的约束,然后调整节点的状态

2.创建方法

代码语言:javascript复制
 /*
  * world 设置为YES 使用世界坐标系,设置为NO 使用自身坐标系 
  (instancetype)transformConstraintInWorldSpace:(BOOL)world  withBlock:(SCNMatrix4 (^)(SCNNode *node,  SCNMatrix4 transform))block
  • SCNIKConstraint(反向运动约束)

1.作用:

将一个节点链移动到一个目标位置

给张图理解一下:

让学习成为一种习惯

2.使用步骤:

1.创建一个节点链 2.给根节点添加 SCNIKConstraint 约束对象(胳膊) 3.添加约束給执行器(手) 3.限定链式节点移动的范围 4.设置目标位置,这个值可以动态的改变

3.举个例子理解一下

比如机器人的组成身体 上臂 胳膊 和 手,身体是上臂的根节点,上臂是胳膊的根节点,胳膊是手的根节点,手是身体的根节点,如果我们要实现上面的约束的话,需要将约束的根节点设置为上臂,那我们把这个约束应该添加到手(执行)这个节点上去

4.创建反向运动约束

代码语言:javascript复制
- (instancetype)initWithChainRootNode:(SCNNode *)chainRoot  
  inverseKinematicsConstraintWithChainRootNode:

5.设置约束的最大旋转角度

代码语言:javascript复制
- (void)setMaxAllowedRotationAngle:(CGFloat)angle
                      forJoint:(SCNNode *)node

6.设置目标位置

代码语言:javascript复制
var targetPosition: SCNVector3
走进代码的世界

友情提示:

第一种约束和第二种约束都很简单,在这里就不写代码了,我们重点研究一下,第三种约束的实现。

制作一个机器手模型

1.创建工程(略)

2.添加模型文件(略)

3.添加框架<SceneKit/SceneKit.h>

4.创建游戏场景

代码语言:javascript复制
scnView = [[SCNView alloc]initWithFrame:self.view.bounds];
scnView.backgroundColor = [UIColor blackColor];
scnView.allowsCameraControl = true;
scnView.scene = [SCNScene scene];
scnView.scene.physicsWorld.gravity = SCNVector3Make(0, 90, 0);// 添加一个重力,我们让其方向朝上
[self.view addSubview:scnView];

5.添加照相机

代码语言:javascript复制
 SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
cameraNode.camera.automaticallyAdjustsZRange = true;
cameraNode.position = SCNVector3Make(0, 0,1000);
[scnView.scene.rootNode addChildNode:cameraNode];

6.添加机器手臂并设置约束

代码语言:javascript复制
-(void)addArmToScene{

// 创建手掌
SCNNode *handNode = [SCNNode node];
handNode.geometry = [SCNBox boxWithWidth:20 height:20 length:20 chamferRadius:0];
handNode.geometry.firstMaterial.diffuse.contents = [UIColor purpleColor];
handNode.position = SCNVector3Make(0, -50, 0);

// 创建小手臂
SCNNode *lowerArm = [SCNNode node];
lowerArm.geometry = [SCNCylinder cylinderWithRadius:1 height:100];
lowerArm.geometry.firstMaterial.diffuse.contents = [UIColor redColor];
lowerArm.position = SCNVector3Make(0, -50, 0);
lowerArm.pivot = SCNMatrix4MakeTranslation(0, 50, 0); // 连接点
[lowerArm addChildNode:handNode];

// 创建上臂
SCNNode *upperArm = [SCNNode node];
upperArm.geometry = [SCNCylinder cylinderWithRadius:1 height:100];
upperArm.geometry.firstMaterial.diffuse.contents = [UIColor greenColor];
upperArm.pivot = SCNMatrix4MakeTranslation(0, 50, 0);
[upperArm addChildNode:lowerArm];

// 创建控制点
SCNNode *controlNode = [SCNNode node];
controlNode.geometry = [SCNSphere sphereWithRadius:10];
controlNode.geometry.firstMaterial.diffuse.contents = [UIColor blueColor];
[controlNode addChildNode:upperArm];
controlNode.position= SCNVector3Make(0, 100, 0);

// 添加到场景中去
[scnView.scene.rootNode addChildNode:controlNode];
scnView.delegate = self;

// 创建约束
 ikContrait =[SCNIKConstraint inverseKinematicsConstraintWithChainRootNode:controlNode];

// 给执行器添加约束
handNode.constraints = @[ikContrait];
}

7.添加一个手,每次点击屏幕,随机增加一个球

代码语言:javascript复制
// 添加手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapHandle)];
[scnView addGestureRecognizer:tap];
-(void)tapHandle{
[self createNodeToScene:scnView.scene andConstraint:ikContrait];
}

-(void)createNodeToScene:(SCNScene*)scene andConstraint:(SCNIKConstraint*)ikConstrait{
SCNNode *node = [SCNNode node];
node.position = SCNVector3Make(arc4random_uniform(100), arc4random_uniform(100), arc4random_uniform(100));
[scene.rootNode addChildNode:node];
node.geometry = [SCNSphere sphereWithRadius:10];
node.geometry.firstMaterial.diffuse.contents = [UIColor colorWithRed:arc4random_uniform(255.0)/255.0 green:arc4random_uniform(255.0)/255.0 blue:arc4random_uniform(255.0)/255.0 alpha:1];
// 创建动画,当手掌接触到小球时,给小球添加一个动态身体
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.5];
ikConstrait.targetPosition = node.position;
[SCNTransaction commit];
node.physicsBody = [SCNPhysicsBody dynamicBody];  
}

运行一下试试看:

让学习成为一种习惯

总结

今天我们使用了反向运动约束,不知道你学会了没有,其他两种约束都比较简单,请自行进行学习,如有疑问,请联系我!


代码库,听说经常给人点赞都当老板了!

0 人点赞