objective-c - 使用 SceneKit 在 3D 空间中旋转 SCNode 对象

标签 objective-c macos 3d scenekit

我正在尝试学习使用 SceneKit 的方式,例如,我想我会尝试使用 SDK 构建一个太阳系。我能够添加 SCNode 对象并配置其 Material 属性,如图案和照明。此外,我能够旋转行星,但我似乎无法理解如何沿着特定路径“旋转”它们。

到目前为止,我的代码如下所示:

// create a new scene
SCNScene *scene = [SCNScene scene];

// create and add a camera to the scene
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
[scene.rootNode addChildNode:cameraNode];

// place the camera
cameraNode.position = SCNVector3Make(0, 0, 2);

// create and add a 3d sphere - sun to the scene
SCNNode *sphereNode = [SCNNode node];
sphereNode.geometry = [SCNSphere sphereWithRadius:0.3];
[scene.rootNode addChildNode:sphereNode];

// create and configure a material
SCNMaterial *material = [SCNMaterial material];
material.diffuse.contents = [NSImage imageNamed:@"SunTexture"];
material.specular.contents = [NSColor whiteColor];
material.specular.intensity = 0.2;
material.locksAmbientWithDiffuse = YES;

// set the material to the 3d object geometry
sphereNode.geometry.firstMaterial = material;

// create and add a 3d sphere - earth to the scene
SCNNode *earthNode = [SCNNode node];
earthNode.geometry = [SCNSphere sphereWithRadius:0.15];
NSLog(@"Sun position = %f, %f, %f", sphereNode.position.x, sphereNode.position.y, sphereNode.position.z);
earthNode.position = SCNVector3Make(0.7, 0.7, 0.7);
NSLog(@"Earth position = %f, %f, %f", earthNode.position.x, earthNode.position.y, earthNode.position.z);
//earthNode.physicsBody = [SCNPhysicsBody dynamicBody];
[scene.rootNode addChildNode:earthNode];

SCNMaterial *earthMaterial = [SCNMaterial material];
earthMaterial.diffuse.contents = [NSImage imageNamed:@"EarthTexture"];

earthNode.geometry.firstMaterial = earthMaterial;

我在 AppleDocs 的某处读到您需要在太阳的坐标系中而不是在根节点中添加行星,但我不确定我是否理解正确。

请告诉我您是如何做到这一点的。

最佳答案

SceneKit 不提供动画沿路径 API。不过,有几种方法可以建立类似太阳系的东西。

  1. 见过 orrery ?这是 SCNNode 中的模型文档正在谈论;这也是 WWDC presentation 的内容在“场景图摘要”幻灯片上执行。诀窍是您使用一个节点来表示行星绕太阳公转的引用系——就像在太阳系仪中固定行星的电枢一样,如果您使该节点绕其中心轴旋转,则您附加到的任何子节点它将遵循一个循环路径。与此相关的代码位于该示例代码项目的 ASCSceneGraphSummary.m 中(浓缩为仅在此处显示节点层次结构设置):

    // Sun
    _sunNode = [SCNNode node];
    _sunNode.position = SCNVector3Make(0, 30, 0);
    [self.contentNode addChildNode:_sunNode];
    
    // Earth-rotation (center of rotation of the Earth around the Sun)
    SCNNode *earthRotationNode = [SCNNode node];
    [_sunNode addChildNode:earthRotationNode];
    
    // Earth-group (will contain the Earth, and the Moon)
    _earthGroupNode = [SCNNode node];
    _earthGroupNode.position = SCNVector3Make(15, 0, 0);
    [earthRotationNode addChildNode:_earthGroupNode];
    
    // Earth
    _earthNode = [_wireframeBoxNode copy];
    _earthNode.position = SCNVector3Make(0, 0, 0);
    [_earthGroupNode addChildNode:_earthNode];
    
    // Moon-rotation (center of rotation of the Moon around the Earth)
    SCNNode *moonRotationNode = [SCNNode node];
    [_earthGroupNode addChildNode:moonRotationNode];
    
    // Moon
    _moonNode = [_wireframeBoxNode copy];
    _moonNode.position = SCNVector3Make(5, 0, 0);
    [moonRotationNode addChildNode:_moonNode];
    
  2. 您无法制作遵循您在 3D 空间中建模的特定路径的动画,但您可以制作在 3D 空间中的多个位置之间插值的关键帧动画。下面的(未经测试的)代码围绕 xz 平面中的正方形移动节点...添加更多点以获得更圆的形状。

    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPaths:@"position"];
    anim.values = @[
        [NSValue valueWithSCNVector3:SCNVector3Make(0, 0, 1)],
        [NSValue valueWithSCNVector3:SCNVector3Make(1, 0, 0)],
        [NSValue valueWithSCNVector3:SCNVector3Make(0, 0, -1)],
        [NSValue valueWithSCNVector3:SCNVector3Make(-1, 0, 0)],
    ];
    [node addAnimation:anim forKey:"orbit"];
    
  3. 使用物理学! SCNPhysicsField类模型径向重力,因此您只需将重力场放入场景中,为行星添加一些物理实体,然后坐下来观看您的太阳系灾难性地 self 毁灭 重生!在这里获得真实的行为需要大量的试验和错误——你需要为每个行星设置一个与你期望的轨道相切的初始速度,并调整该速度以使其正确。研究我们太阳系的一些星历数据可能会有所帮助。

关于objective-c - 使用 SceneKit 在 3D 空间中旋转 SCNode 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24320456/

相关文章:

ios - 在动态 TableView 中添加静态单元格

ios - OCMock 和 block 测试,执行

c++ - 如何在 Qt/C++ 中构建自定义原生 OSX webkit 小部件?

objective-c - Access Finder 别名图标

javascript - 可以在没有服务器端的情况下通过 paraviewweb 或 vtk.js 渲染 .pvd 文档/场景吗?

iphone - FBConnect 演示应用程序

ios - 从另一个应用程序 ios 链接到设置应用程序的声音部分

javascript - 在 Chrome/Mac 上强制 DOM 重绘/刷新

c++ - 为什么 mipmapping 对我的 3D 纹理不起作用? (opengl)

python - 使用 vtkTubeFilter 创建闭环