Bake lightprobes in Scenekit programmatically - objective-c

I am facing issues baking lightprobes on iOS. The same logic bakes lightprobes on macOS successfully. iOS throws the following exception
[MTLDebugCommandBuffer waitUntilCompleted]:201: failed assertion `waitUntilCompleted on uncommitted command buffer'
Some specs : Runtime: iOS 15.4 - DeviceType: iPhone 13 Pro Max. Following is the code for lightprobe bake :
SCNScene* scene = [SCNScene scene];
SCNNode *ambientLight = [SCNNode node];
ambientLight.light = [SCNLight light];
ambientLight.light.type = SCNLightTypeAmbient;
ambientLight.light.color = [UIColor whiteColor];
ambientLight.light.intensity = 1000.0;
[scene.rootNode addChildNode:ambientLight];
scene.background.contents = [UIColor whiteColor];
scene.background.intensity = 2000.;
SCNNode *probe1 = [SCNNode node];
probe1.position = SCNVector3Make(-0.493530, 1.7285934, -0.150000);
probe1.light = [SCNLight light];
probe1.light.type = SCNLightTypeProbe;
[scene.rootNode addChildNode:probe1];
SCNRenderer* probeRenderer = [SCNRenderer rendererWithDevice:nil options:nil];
probeRenderer.scene = scene;
NSArray<SCNNode*> *probes = [NSArray arrayWithObjects: probe1, nil];
[probeRenderer updateProbes: probes atTime:1.0];
The crash occurs at updateProbes. Also, I have logged and checked the 27 floats and they are not garbage for macOS so essentially the bake is working as expected on macOS. Any help would be really appreciated!

Related

CAEmitterlayer crashing when birthrate over 5 in iOS 9

I'm using a particle emitter in an iPad project (not using SpriteKit), the particle emitter is generated inside a UIImageView and since iOS 9 this emitter is making the whole app crash. Actually, the whole iPad is crashing, the image freezes and nothing can make the iPad unfreeze short of restarting the iPad.
If I bring the birthrate down from 19.0f to 6.0f the iPad stops crashing.
The image I am using is a png of 256 × 256 in size, I'm not sure if that might play a role in it crashing.
Everything was working fine in iOS 8.
I'm currently on iOS 9.0.1 on an iPad Air 2, using Xcode 7.0.1.
+(void)smogGeneral:(UIImageView *)myView{
[myView setNeedsDisplay];
CALayer *rootLayer = [myView layer];
CALayer *emitterSuperLayer = [CALayer layer];
emitterSuperLayer.bounds = myView.bounds;
emitterSuperLayer.sublayerTransform = CATransform3DMakeScale(1.0f, -1.0f, 1.0f);
[rootLayer addSublayer:emitterSuperLayer];
CGFloat midX = floorf(CGRectGetMidX(myView.bounds));
CGFloat midY = floorf(CGRectGetMidY(myView.bounds));
[emitterSuperLayer setPosition:CGPointMake(midX, midY)];
CAEmitterLayer *whiteSmokeEmitter = [CAEmitterLayer layer];
[whiteSmokeEmitter setName:#"whiteSmokeEmitter"];
whiteSmokeEmitter.zPosition = 0.00f;
whiteSmokeEmitter.emitterPosition = CGPointMake(300, 300);
whiteSmokeEmitter.renderMode = kCAEmitterLayerBackToFront;
whiteSmokeEmitter.emitterSize = CGSizeMake(10.00f, 10.0f);
whiteSmokeEmitter.velocity = 0.05f;
whiteSmokeEmitter.emitterMode = kCAEmitterLayerOutline;
whiteSmokeEmitter.emitterShape = kCAEmitterLayerRectangle;
CAEmitterCell *puffCell = [CAEmitterCell emitterCell];
[puffCell setName:#"puffCell"];
puffCell.contents = (__bridge id)[[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"smokeCell" ofType:#"png"]] CGImage];;
CGColorRef colorRefPuffcell = [UIColor colorWithRed:0.99f green:0.98f blue:1.00f alpha:0.10f].CGColor;
puffCell.color = colorRefPuffcell;
puffCell.scale = 0.2f;
puffCell.emissionLongitude = 1.84f;
puffCell.emissionRange = 1.11f;
puffCell.lifetime = 16.0f;
puffCell.birthRate = 19.0f;
puffCell.scaleSpeed = 0.15f;
puffCell.velocity = 2.56f;
puffCell.velocityRange = 9.80f;
puffCell.xAcceleration = 9.15f;
puffCell.yAcceleration = -0.01f;
whiteSmokeEmitter.emitterCells = #[puffCell];
[emitterSuperLayer addSublayer:whiteSmokeEmitter];
}

physics body in Xcode

While I follow a tutorial on how to create a game using a sprite kit, I created a physics body for scene like this:
#implementation GameScene
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
self.backgroundColor = [SKColor whiteColor];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity = CGVectorMake(0,5);
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"nn_03"];
ball.position= CGPointMake(self.size.width/2, self.size.height/2);
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.height/2];
[self addChild:ball];
And when I checked it, it work just with upper and lower bounded of the scene and doesn't work with left and right side of the scene ? Where is the problem ?
And my second question when i downgrade my Xcode 6 to Xcode 5 , can i target iOS 8 IN XCODE 5 OR NOT ?

Sprite Kit turn node by Y

I have 2 nodes: SKShapeNode coin and SKSpriteNode hero with delegate and didBeginContact method. Contact works fine, but after i reverse my hero texture, nodes are don't interact.
The logic is: hero is go on line, under line and above line positioned coins. When hero is go above line all good, but when i use changeHeroSide method, hero reversed and go under line, didBeginContact method don't response.
- (void)changeHeroSide
{
self.yScale = -fabs(self.yScale); // this part don't interact under line
/** BUT THIS PART WORKS WELL AND INTERACTS UNDER LINE
self.zRotation = M_PI;
self.xScale = fabs(self.xScale);
**/
self.position = CGPointMake(self.position.x, self.position.y - self.frame.size.height);
self.physicsBody.affectedByGravity = NO;
}
Creating of nodes
- (void)create
{
self.hero = [[VZHero alloc] initAtPosition:CGPointZero withPlayer:nil];
self.hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.hero.frame.size];
self.hero.xScale = -fabs(self.hero.xScale);
SKShapeNode *platform = [self getCurrentPlatform];
self.hero.position = CGPointMake([self getHeroEdgeXCoordinateForPlatform:platform], platform.frame.size.height + _hero.frame.size.height/2);
self.hero.physicsBody.dynamic = YES;
self.hero.physicsBody.categoryBitMask = monsterCategory;
self.hero.physicsBody.contactTestBitMask = projectileCategory;
self.hero.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild:self.hero atWorldLayer:VZWorldLayerCharacter];
SKShapeNode *coin = [SKShapeNode shapeNodeWithCircleOfRadius:radius];
coin.name = #"coin";
coin.strokeColor = [SKColor blackColor];
coin.fillColor = [SKColor yellowColor];
coin.lineWidth = 1;
coin.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:radius];
coin.physicsBody.dynamic = NO;
coin.position = pos;
coin.physicsBody.categoryBitMask = projectileCategory;
coin.physicsBody.contactTestBitMask = monsterCategory;
// coin.physicsBody.collisionBitMask = 0;
coin.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild:coin atWorldLayer:VZWorldLayerCharacter];
}
Mirroring the y scale that way is messing up the physics body properties. Looks like a bug in SpriteKit (at least on iOS 7). You can solve this by wrapping your sprite in a container node. This related question might be of some help.

In SpriteKit, SKCropNode has no effect over a SKShapeNode

I've been trying to apply a mask to a SKShapeNode using SKCropNode, and so far without success. Thinking that it's a SpriteKit bug - Here is the code snippet:
SKNode* contentNode = [SKNode node];
// picture - use an image bigger than 50x50
SKSpriteNode *pictureNode = [SKSpriteNode spriteNodeWithImageNamed:#"tree"];
// triangle
SKShapeNode* triangleNode = [SKShapeNode node];
UIBezierPath* triangleNodeBezierPath = [[UIBezierPath alloc] init];
[triangleNodeBezierPath moveToPoint:CGPointMake(0.0, 0.0)];
[triangleNodeBezierPath addLineToPoint:CGPointMake(0.0, 100.0)];
[triangleNodeBezierPath addLineToPoint:CGPointMake(50.0, 100.0)];
[triangleNodeBezierPath closePath];
triangleNode.path = triangleNodeBezierPath.CGPath;
triangleNode.fillColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1];
// create a mask
SKSpriteNode *mask = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size: CGSizeMake(50, 50)]; //50 by 50 is the size of the mask
// create a SKCropNode
SKCropNode *cropNode = [SKCropNode node];
[cropNode addChild: contentNode];
[cropNode setMaskNode: mask];
[self addChild: cropNode];
[contentNode addChild:pictureNode]; // pictureNode is being cropped
[contentNode addChild:triangleNode]; // triangleNode is not
cropNode.position = CGPointMake( CGRectGetMidX (self.frame), CGRectGetMidY (self.frame));
Does anyone have a workaround about this issue? Thanks a lot!
This had been bugging me for most of the day. I had planned to create a timer similar to the excellent TCProgressTimer by Tony Chamblee. However, as my application uses multiple progress timers I didn't want to have to design dozens of different sized sprites for use at different resolutions.
My solution was to convert SKShapeNode objects to SKSpriteNode objects. I ended up having to go back to basics and use Core Graphics to do the heavy lifting. This is a rather messy way of doing things, I'm sure, but I wanted quick results to dynamically create objects that would resemble the results obtained when using SKShapeNode.
I am only interested in making circle objects at present, so I did it like this:
-(SKSpriteNode *)createSpriteMatchingSKShapeNodeWithRadius:(float)radius color:(SKColor *)color {
CALayer *drawingLayer = [CALayer layer];
CALayer *circleLayer = [CALayer layer];
circleLayer.frame = CGRectMake(0,0,radius*2.0f,radius*2.0f);
circleLayer.backgroundColor = color.CGColor;
circleLayer.cornerRadius = circleLayer.frame.size.width/2.0;
circleLayer.masksToBounds = YES;
[drawingLayer addSublayer:circleLayer];
UIGraphicsBeginImageContextWithOptions(CGSizeMake(circleLayer.frame.size.width, circleLayer.frame.size.height), NO, [UIScreen mainScreen].scale);
CGContextSetAllowsAntialiasing(UIGraphicsGetCurrentContext(), TRUE);
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [UIColor clearColor].CGColor);
CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0,0,circleLayer.frame.size.width,circleLayer.frame.size.height));
[drawingLayer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *layerImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImage:layerImage]];
return sprite;
}
The resulting sprite can now be masked by an SKCropNode as expected. As these sprites are all generated before the scene begins, I do not notice a performance hit. However, I would imagine this method is highly inefficient if you are generating multiple nodes on the fly.
I would be eager to hear solutions from other users. Hope that helps.
-DC
I have the similar task in my app. I need to draw multiple irregular shapes based on user input and then use them as crop node's masks.
The solution that works for me is to:
create a SKShapeNode with the required path
retrieve a SKTexture from it using SKView method textureFromNode:crop:
create a SKSpriteNode from that texture.
use SKSprite node as a mask.
Your title is correct. I've also discovered having a ShapeNode in the CropNode's hierarchy affects the children above it as well. I created a quick experiment. You can create a new game project and try it yourself. By commenting out one of the addChild:shapeContent lines you can see how it affects the cropping of the spaceship image.
As DoctorClod points out the current solution seems to be making sure all children of the cropNode are SpriteNodes.
-(void)didMoveToView:(SKView *)view {
SKSpriteNode* colorBackground = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(800, 600)];
SKSpriteNode *spaceshipImage = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
SKShapeNode* shapeContent = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 200, 100)];
shapeContent.fillColor = [SKColor greenColor];
SKSpriteNode *maskShape = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(500, 100)];
SKCropNode *cropNode = [SKCropNode new];
[cropNode addChild:colorBackground];
[cropNode addChild:shapeContent]; // comment this one out
[cropNode addChild:spaceshipImage];
[cropNode addChild:shapeContent]; // or comment this one out
[cropNode setMaskNode:maskShape];
cropNode.position = CGPointMake(CGRectGetMidX (self.frame), CGRectGetMidY(self.frame));
[self addChild:cropNode];
}

UIAlert with AddSubview replacement for iOS 7

Current code works perfectly before iOS 7, on iOS 7 there is no field to input the name of the user, from scanning these forums I noticed t changed on iOS7 something to do with the addsubview function, here is the current code;
Could anyone assist in converting this to work with iOS7 (ideally not breaking the iOS 6 link as would prefer to keep the app compatible with both OS versions)
- (void) createScoreInput {
changePlayerAlert = [UIAlertView new];
changePlayerAlert.title = #"Enter your name";
changePlayerAlert.message = #"\n\n";
changePlayerAlert.delegate = self;
[changePlayerAlert addButtonWithTitle:#"Save"];
[changePlayerAlert addButtonWithTitle:#"Cancel"];
CGRect frame = changePlayerAlert.frame;
frame.origin.y -= 100.0f;
changePlayerAlert.frame = frame;
changePlayerTextField = [[UITextField alloc] initWithFrame:CGRectMake(20, 50, 245, 27)];
changePlayerTextField.borderStyle = UITextBorderStyleRoundedRect;
[changePlayerAlert addSubview:changePlayerTextField];
changePlayerTextField.keyboardType = UIKeyboardTypeNamePhonePad;
changePlayerTextField.returnKeyType = UIReturnKeyDone;
changePlayerTextField.autocorrectionType = UITextAutocorrectionTypeNo;
changePlayerTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
changePlayerTextField.delegate = self;
}
This API has solution for your problem use this and have fun
https://github.com/Darktt/DTAlertView
https://github.com/Scott90/SDCAlertView
https://github.com/lmcd/LMAlertView
OR
Follow this tutorial and you can take input directly from UIAlertView