SceneKit AVPlayer only audio is playing - ios

I am trying to play a video in SceneKit. I can hear the audio but video is not rendering. The way i am using the scene is as follows. Please help.
SCNScene *scene = [SCNScene sceneNamed:#"art.scnassets/plane.scn"];
SCNNode *plane = [scene.rootNode childNodeWithName:#"plane" recursively:YES];
AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:#"https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_5mb.mp4"]];
plane.geometry.firstMaterial.diffuse.contents = player;
[player play];
SCNView *scnView = (SCNView *)self.view;
scnView.scene = scene;
scnView.allowsCameraControl = YES;
scnView.showsStatistics = YES;
scnView.backgroundColor = [UIColor blackColor];

You need to use a real iPhone not simulator to enjoy.
Another reason is the shading in the material panel should not be physical based. You may try Blinn. The code has no problem.
If using a physical based, you have to add an extra light to make it work.

you can keep PBR and get glass reflections with a non-rough material. use the emission instead of diffuse for the the video though
plane.geometry.firstMaterial.emission.contents = player

Related

How to prevent the camera from entering a SCNNode - Scenekit iOS

I have a problem whit the camera in SceneKit, by default i can move, rotate, zoom my camera whit this line :
myView.allowsCameraControl = YES;
But my camera can pass through walls and floor (which allows me to see the underside of the stage ) .
My first request: is it possible to apply constraints to the camera (position, rotation) ?
My second request: I thought making a cube encompassing stage and do my collision detection between my cube and my camera, but it does not work ...
code for viewDidLoad:
SCNView *myView = (SCNView *)self.view3D;
myView.scene = [SCNScene sceneNamed:#"art.scnassets/Pointe Marrin 3 def 3 def 2.dae"];
myView.scene.physicsWorld.contactDelegate = self;
myView.scene.physicsWorld.gravity = SCNVector3Make(0, 0, 0);
cubeLimite = [myView.scene.rootNode childNodeWithName:#"Cube" recursively:YES];
camera = [myView.scene.rootNode childNodeWithName:#"Caméra" recursively:YES];
cubeLimite.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:nil];
cubeLimite.physicsBody.mass = 0;
cubeLimite.categoryBitMask = SCNPhysicsCollisionCategoryDefault;
cubeLimite.physicsBody.collisionBitMask = SCNPhysicsCollisionCategoryAll;
//test camera
CGFloat boxSide = 0.001;
SCNBox *box = [SCNBox boxWithWidth:boxSide
height:boxSide
length:boxSide
chamferRadius:0];
SCNNode *boxNode = [SCNNode nodeWithGeometry:box];
SCNPhysicsShape *shape = [SCNPhysicsShape shapeWithGeometry:boxNode.geometry options:nil];
camera.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:shape];
camera.physicsBody.mass = 0;
camera.categoryBitMask = SCNPhysicsCollisionCategoryDefault;
camera.physicsBody.collisionBitMask = SCNPhysicsCollisionCategoryAll;
Code for delegate :
- (void)physicsWorld:(SCNPhysicsWorld *)world
didBeginContact:(SCNPhysicsContact *)contact{
NSLog(#"Contact debut");
}
- (void)physicsWorld:(SCNPhysicsWorld *)world
didUpdateContact:(SCNPhysicsContact *)contact{
NSLog(#"Contact milieu");
}
- (void)physicsWorld:(SCNPhysicsWorld *)world didEndContact:(SCNPhysicsContact *)contact{
NSLog(#"Contact fin");
}
The delegate :
SCNPhysicsContactDelegate
is declared in the .h file
Ideas ?
thank you beforehand
It's not possible, as far as I know, to constrain the default camera when allowsCameraControl is enabled.
The answer to Rotate SCNCamera node looking at an object around an imaginary sphere outlines an approach that might work for you, depending on what constraints you need to build.

Inserting an AVPlayerLayer below GLKView Layer

All I am trying to accomplish is to place an AVPlayerLayer behind an active OpenGL layer.
I am using a GLKViewController (with respective GLKView). I load a video with AVPlayer and establish a corresponding AVPlayerLayer. Both my GL Layer and AVPlayerLayer appear, however, regardless of what form of "insert sublayer" I call (above, below, at index, etc.), the GL Layer always appears behind the AVPlayerLayer.
_videoData = playerItem;
_videoPlayer = [[AVPlayer alloc] initWithPlayerItem:_videoData];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_videoPlayer];
_playerLayer.frame = CGRectMake(250, 250, 300, 300);
[self.view.layer insertSublayer:_playerLayer below:self.view.layer];
Solved this by inserted a GLKViewController as a child of a UIView with the video player. After much experimentation it appears you cannot place anything (subviews or layers) behind the GL layer when using GLKViewController independently.

run scene (scene kit )?

is it possible to run this code on Apple Watch:
SCNScene *scene = [SCNScene sceneNamed:#"art.scnassets/ship.dae"];
// retrieve the ship node
SCNNode *ship = [scene.rootNode childNodeWithName:#"ship" recursively:YES];
// animate the 3d object
[ship runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:0 y:2 z:0 duration:1]]];
// retrieve the SCNView
SCNView *scnView = (SCNView *)self.view;
// set the scene to the view
scnView.scene = scene;
// allows the user to manipulate the camera
scnView.allowsCameraControl = YES;
// show statistics such as fps and timing information
scnView.showsStatistics = YES;
I can not put scene on main controller.
SCNView *scnView = (SCNView *)self.view;
Please, help.
The only way to make apps for Apple Watch is WatchKit. WatchKit does not include the ability to present any iOS view on the watch, only the specific set of UI controls defined in the WatchKit framework. See WatchKit Programming Guide for details.

Particle Effects Disappear When Transitioning to a New SKScene

I'm working on a game using Sprite Kit. I have a particle effect that runs when an object collides with another object; however, this particle effect seems to disappear when I add a transition to another SKScene. What's causing this disappearance, and how do I solve this issue?
Edit: By disappear I mean that it does not appear in the current scene when the scene is still transitioning with all the sprites still showing. It has a 2 second time interval, so shouldn't I be able to see it?
Here's the code for the particle effect and scene transition:
- (void)player:(SKSpriteNode *)player didCollideWithEnemy:(SKSpriteNode *)enemy {
Enemy *monster = (Enemy *)enemy;
if(!monster.isMoving){
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"MyParticle" ofType:#"sks"]];
emitter.position = player.position;
[self addChild: emitter];
isAlive = FALSE;
NSLog(#"Hit");
CrowdedData *crowdedData = [CrowdedData sharedManager];
crowdedData.score = score;
[player removeFromParent];
SKTransition *reveal = [SKTransition fadeWithDuration:2];
GameOver *scene = [GameOver sceneWithSize:self.view.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:scene transition:reveal];
}
}
SKTransition has two properties that are relevant to this:
[transition setPausesOutgoingScene:NO];
[transition setPausesIncomingScene:NO];
Both default to YES, causing either the outgoing in incoming scenes to be paused, which in turn pauses your emitter. For your purposes, setting the pausesOutgoingScene property to NO should be enough to fix this. More info in the docs:
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKView/Reference/Reference.html

Regulating the volume of SKAction playSoundFileNamed:

Is there a way to regulate the volume of sound played via SKAction playSoundFileNamed:waitForCompletion:.
I would like to implement a simple music & sound effects slider in my game. I can easily control background music since i play it via AVAudioPlayer, but all sound effects are played via SKAction.
Here is my code for how i handled this problem
NSError *error;
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"pew-pew-lei" withExtension:#"caf"];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
[player setVolume:masterVolume];
[player prepareToPlay];
SKAction* playAction = [SKAction runBlock:^{
[player play];
}];
SKAction *waitAction = [SKAction waitForDuration:player.duration+1];
SKAction *sequence = [SKAction sequence:#[playAction, waitAction]];
[self runAction:sequence];
The masterVolume variable is just some preset variable i have that the user can change from 0.0-1.0
The waitAction ensures that the player doesn't get removed before it has played the entire sound
Hope this helps!
Unfortunately you can't modify the volume using SKAction, so you have to use AVAudioPlayer for your effects too.
You could implement a custom playSoundFileNamed:waitForCompletion:volume: using runBlock as you already thought, so your code won't be very different then using playSoundFileNamed:waitForCompletion:.
Swift:
Since iOS 9.0 you can change the volume to your node running another action if you have already runned your audio (remember that this one obviusly cannot work if you have something that run with repeatForever):
let changeVolumeAction = SKAction.changeVolume(to: 0.3, duration: 0.3)
node.run(changeVolume)
Or you can create a group and launching your audio with the correct volume:
let effectAudioAction = SKAction.playSoundFileNamed("electricshockLow.mp3", waitForCompletion: false)
let changeVolumeAction = SKAction.changeVolume(to: 0.3, duration: 0.3)
let effectAudioGroup = SKAction.group([effectAudioAction,changeVolumeAction])
node.run(effectAudioGroup)

Resources