iPhoneショーケース立体

商品を3Dでくるっと見せるショーケースっぽいiPhoneアプリのサンプルコードを描いてみます。

#import “ViewController.h”

@import SceneKit;

@interface ViewController () <SCNSceneRendererDelegate>

@property (nonatomic, weak) SCNView *sceneView;

@property (nonatomic, weak) SCNScene *scene;

@end

@implementation ViewController

– (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor lightGrayColor];

    [self setupScene];

    [self createShowcase];

    [self createItems];

    [self createCamera];

    [self createLight];

}

– (void)setupScene {

    float w = CGRectGetMaxX(self.view.bounds);

    SCNView *sv = [[SCNView alloc] initWithFrame:CGRectMake(0, 0, w, w)];

    sv.backgroundColor = [UIColor colorWithRed:125.0/255.0 green:138.0/255.0 blue:46.0/255.0 alpha:1];

    sv.scene = [SCNScene scene];

    sv.delegate = self;

    [self.view addSubview:sv];

    

    self.scene = sv.scene;

    self.sceneView = sv;

}

– (void)createShowcase {

    for (int i=0; i<3; i++) {

        SCNCylinder *disk = [SCNCylinder cylinderWithRadius:2 height:0.2];

        disk.firstMaterial.diffuse.contents = [UIColor whiteColor];

        SCNNode *diskNode = [SCNNode nodeWithGeometry:disk];

        diskNode.name = [NSString stringWithFormat:@”disk%d”, i];

        diskNode.position = SCNVector3Make(i * 88, –10, 0);

        [self.scene.rootNode addChildNode:diskNode];

    }

    

    SCNCylinder *mainDisk = [SCNCylinder cylinderWithRadius:8 height:0.2];

    mainDisk.firstMaterial.diffuse.contents = [UIColor whiteColor];

    SCNNode *maindiskNode = [SCNNode nodeWithGeometry:mainDisk];

    maindiskNode.name = @”mainDisk”;

    [self.scene.rootNode addChildNode:maindiskNode];

}

– (void)createItems {

    SCNBox *box = [SCNBox boxWithWidth:4 height:4 length:4 chamferRadius:0];

    box.firstMaterial.diffuse.contents = [UIColor colorWithRed:201.0/255.0 green:215.0/255.0 blue:135.0/255.0 alpha:1];

    

    SCNTorus *ball = [SCNTorus torusWithRingRadius:2 pipeRadius:1];

    ball.firstMaterial.diffuse.contents = [UIColor colorWithRed:255.0/255.0 green:192.0/255.0 blue:169.0/255.0 alpha:1];

    

    SCNPyramid *pyramid = [SCNPyramid pyramidWithWidth:4 height:4 length:4];

    pyramid.firstMaterial.diffuse.contents = [UIColor colorWithRed:255.0/255.0 green:133.0/255.0 blue:152.0/255.0 alpha:1];

    

    NSArray *geometories = @[box, ball, pyramid];

    for (int i=0; i<3; i++) {

        SCNNode *disk = [self.scene.rootNode childNodeWithName:[NSString stringWithFormat:@”disk%d”, i] recursively:false];

        SCNNode *item = [SCNNode nodeWithGeometry:geometories[i]];

        item.name = @”item”;

        item.position = SCNVector3Make(disk.position.x, disk.position.y + 3, disk.position.z);

        [self.scene.rootNode addChildNode:item];

    }

}

– (void)createCamera {

    SCNNode *camera = [SCNNode node];

    camera.camera = [SCNCamera camera];

    camera.position = SCNVector3Make(0, 2, 25);

    [self.scene.rootNode addChildNode:camera];

}

– (void)createLight {

    SCNLight *light = [SCNLight light];

    light.type = SCNLightTypeOmni;

    SCNNode *lightNode = [SCNNode node];

    lightNode.light = light;

    lightNode.position = SCNVector3Make(0, 20, 60);

    [self.scene.rootNode addChildNode:lightNode];

}

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInView:self.sceneView];

    NSArray *hits = [self.sceneView hitTest:p options:nil];

    for (SCNHitTestResult *hit in hits) {

        if ([hit.node.name isEqual:@”item”]) {

            hit.node.physicsBody = [SCNPhysicsBody dynamicBody];

            [hit.node.physicsBody applyForce:SCNVector3Make(0, 5, 0) impulse:YES];

            [hit.node.physicsBody applyTorque:SCNVector4Make(0, 1, 0, 2.0) impulse:YES];

            

            [self showMainDisk:hit.node.geometry.copy];

        }

    }

}

– (void)showMainDisk:(SCNGeometry*)geometory {

    SCNNode *old = [self.scene.rootNode childNodeWithName:@”mainItem” recursively:NO];

    if (old) {

        [old removeFromParentNode];

    }

    

    SCNNode *mainItem = [SCNNode nodeWithGeometry:geometory];

    mainItem.name = @”mainItem”;

    mainItem.scale = SCNVector3Make(2.2, 2.2, 2.2);

    mainItem.position = SCNVector3Make(0, 8.0, 0);

    [mainItem runAction:[SCNAction repeatActionForever:[SCNAction sequence:@[[SCNAction rotateByX:0 y:1 z:0 duration:0.5], [SCNAction rotateByX:1 y:0 z:0 duration:0.5]]]]];

    [self.scene.rootNode addChildNode:mainItem];

}

– (void)renderer:(id<SCNSceneRenderer>)aRenderer updateAtTime:(NSTimeInterval)time

{

    [self.scene.rootNode enumerateChildNodesUsingBlock:^(SCNNode *child, BOOL *stop) {

        if ([child.name isEqual:@”item”]) {

            if (child.presentationNode.position.y < –10 && child.physicsBody) {

                child.physicsBody = nil;

                [child runAction:[SCNAction moveTo:SCNVector3Make(child.position.x, –7, child.position.z) duration:0.5]];

            }

        }

    }];

}

@end