WWDC 2014: What's new in SceneKit
Loading a 3D Scene
- COLLADA .dae
- Alembic .abc(animation)
SceneKit Editor
Loading a DAE
SCNScene *scene = [SCNScene sceneNamed:@"demo.dae"];
SceneKit Assets Catalog
.scnassets folders
Displaying the Scene
// Assign the scene
aSCNView.scene = aScene;
// modifiy a node
aNode.position = SCNVector3Make(0,0,0);
aNode.scale = SCNVector3Make(2,2,2);
aNode.rotation = SCNVector4Make(x,y,z,angle);
aNode.opacity = 0.5;
Animating a Scene
- Per-frame updates
- Animations
- Actions
*new*
- Physics
- Constraints
Animations
// Begin a transaction
[SCNTransaction begin];
[SCNTransation setAnimationDuration:2.0];
// Change properties
aNode.opacity = 1.0;
aNode.rotation = SCNVector4(0,1,0,M_PI*4);
// Commit
[SCNTransaction commit];
or
// Create a animation
animation = [CABasicAnimation animationWithKeyPath:@"rotation"];
// Configure
animation.duration = 2.0;
animation.toValue = [NSValue valueWithSCNVector4:SCNVector4Make(0,1,0,M_PI*2)];
animation.repeatCount = MAXFLOAT;
// Play the animation
[aNode addAnimation:animation forKey:@"myAnimation"];
Animation Events
Smooth transitions
// 音效 Playing a sound at 60 percent
SCNAnimationEvent *anEvent = [SCNAnimationEvent animationEventWithKeyTime:0.6 block:aSoundBlock];
anAnimation.animationEvents = @[anEvent, anotherEvent];
// 轉換動作(idle->attack->idle)加上淡入淡出
anAnimation.fadeInDuration = 0.3;
anAnimation.fadeOutDuration = 0.3;
Actions
Easy to sequence, group, and repeat
[aNode runAction:[SCNAction repeatActionForever:[SCNAtion rotateByX:0 y:M_PI*2 z:0 duration:5.0]]];
// 如果需要取得移動中物件位置,可以用 presentationNode.position
node.position != node.presentationNode.position
Physics
// Dynamic body: Make a node dynamic
aNode.physicsBody = [SCNPhysicsBody dynamicBody];
// Manipulate with forces
// Apply an impulse
[aNode.phsicsBody appleyForce:aVector3 atPosition:aVector3 impulse:YES];
// Staic bodies: Make a node static
aNode.physicsBody = [SCNPhysicsBody staticBody];
// Kinematic body: Make a node kinematic(不受碰撞/重力影響,但是可以用程式的方式加入速度)
aNode.physicsBody = [SCNPhysicsBody kinematicBody];
// Physics shape: SceneKit 會自動建立,也可以用手動的方式指定,如下:
aNode.physicsBody.physicsShape = [SCNPhysicsShape shapeWithGeometry:aGeometry options:options];
// Physics behavior
SCNPhysicsHingeJoint *joint = [SCNPhysicsHingeJoint
jointWithBodyA:nodeA.physicsBody axisA:[...] anchorA:[...]
jointWithBodyB:nodeB.physicsBody axisB:[...] anchorB:[...]];
[scene.physicsWorld addBehavior:joint];
// Remove behavior
[scene.physicsWorld removeBehavior:joint];
Constraints
Applied sequentially at render time
Only affect presentation values
aNode.constraints = @[aConstraints, anotherConstraints, ...];
// Custom constraint on a node's transform
aConstrains = [SCNTransformConstrain transformConstrainInWorldSpace:Yes withBlock:
^SCNMatrix4(SCNNode *node, SCNMatrix4 transform) {
transform.m43 = 0.0;
return transform;
}];
// Makes a node to look at another node: 頭部/眼睛/攝影機都適用
nodeA.constraints = @[SCNLookAtConstraint lookAtConstrainWithTarget:nodeB];
// SCNIKConstraint: 拳頭朝目標物體揮動,連帶會牽動手臂及全身
Scriptability
可與 javascript 整合
- Javascript bridge
- Tools
- Debugging
Rendering
- geometry(shape)
- material(visually nice, color/transparency/light/diffuse/specular reflections)
// Color
material.diffuse.contents = [UIColor redColor];
// Image
material.diffuse.contents = @"slate.jpg";
// SKTexture
material.normal.content = [SKTexture textureByGeneratingNormalMap];
// Dynamic content:Video using SKVideo node
// Cube map
/*
Top
Left Back Right Front
Bottom
*/
material.reflective.contents = @[@"right.png",@"left.png",...@"front"];
// Custom material: Shader Modifier
// 常用在液體流動材質的呈現或是光暈的表現
material.shaderModifiers = @{<Entry Point>:<GLSL Code>};
// SpriteKit Overlays
sceneView.overlaySKScene = aSKScene;
Effects
Particles
SCNParticleSystem
Shadows
- static: 效能最好,但不會隨著物體轉動或移動,而跟著變化
- Dynamic: 最吃效能
- Projected: 效能介於 static 與 Dynamic 中間,可以指定圖形來呈現陰影
// Static
aMaterial.multiply.contents = aShadowMap;
// Dynamic
aLight.castsShadow = YES;
// Projected
aLight.shadowMode = SCNShadowModeModulated;
aLight.gobo = anImage;
Fog
aScene.fogColor = aColor;
aScene.fogStartDistance = 50;
aScene.fogEndDistance = 100;
Depth of Field
// 景深
aCamera.focalDistance = 16.0;
aCamera.focalBlurRadius = 8.0;
Core Image Filters
aNode.filters = @[gaussianBlurs, distortion, pixelate];
Multi-Pass Effects
合併多種效果
// Load a technique
SCNTechnique *technique = [SCNTechnique techniqueWithDictionary:aDictionary];
// Chain techniques
technique = [SCNTechnique techniqueBySequencingTechniques:@[t1,t2...]];
// Set a technique
aSCNView.technique = technique;
Summary
- SceneKit available on iOS
- Casual game ready
- Full featured rendering
- Extendable
Morphing
- Can be loaded from DAE
- Can be created programmatically
- topology must match
Skinning
- Can be loaded from DAE
- Can not be created programmatically
Performance
Lighting
- Minimize the number of lights
- Prefer staic to dynamic shadows
- Use the "multiply" material property
Texturing
- Avoid unnecessarily large images
- Lock ambient with diffuse
aMaterial.locksAmbientWithDiffuse = YES;
- Use mipmaps
aMaterial.diffuse.mipFilter = SCNFilterModeLinear;
- Levels of Detail(依遠近呈現不同精細度的物件)