I am experimenting with ARKit and SceneKit and have been able to place boxes or custom shapes using UIBezierPath. What I’d like to do next is draw text and place images on the surface of these shapes. I’ve tried adding an image to the material property but this just fills the shape with an image. I’d like to have control over the size and position of the image / text relative to the shape. Is this possible?
You can do so by creating a new node for your text or image, and add it as a child node of your existing SCNNode (addChildNode). You can then position it as needed relative to your parent node, much as you have already done with your SCNNode.
For text you can make your SCNNode from an SCNText, or render the text into a bitmap and use it as a texture material of an SCNPlane.
Related
I have a placement marker (a simple plane with green corners) to visualize detected planes (via ARRaycastResult) in an ARView. This placement marker uses UnlitMaterial with a texture. Everything works fine as long as there is no other object added.
When I add another object, RealityKit also adds grounding shadow (invisible plane) right under the object. It works as a shadow plane and occludes everything behind it - including my placement marker.
Here is a picture of the placement marker (part of which is hidden under the shadow plane):
Is there any way to prevent this clipping? I was lookig for something like rendering order (as ARKit does have one), but have not fond anything in RealityKit yet.
I would like to keep the shadow plane if possible.
Edit: Added official name of the invisible plane (grounding shadow)
Reality kit automatically adds "grounding shadows" if the AnchoringComponent.Target is of type "plane". According to an Apple Engineer this can be aso simulated using a DirectionalLight with a Shadow and placing a plane (with an OcclusionMaterial) under the model. So the grounding shadow is probably also made out of OcclusionMaterial. This also explains why this grounding shadow occludes other objects.
There is an option to disable rendering of these grounding shadows. It can be done by inserting of disableGroundingShadows option into ARView's renderOptions property.
arView.renderOptions.insert(.disableGroundingShadows)
I have not yet found a way to override OcclusionMaterial (if any).
I'm new using the SpriteKit Editor within XCode. I applied a resizeToWidth action to a simple Color Sprite Node. The Node has a physics body of the type bounding rectangle. The problem is the graphical representation is resizing but not it's body. The body just stays the same. See the result after applying the action, red is the sprite and the blue line it's bounding box.
How can I make sure that the physics body is resizing like the sprite?
I'm working on a sprite kit game and I'm trying to create a particular silhouette lighting effect whenever objects pass in front of a particular object (in this case a red sun). I want anything in front of it to appear black, and everything else to appear as normal (so if an object is partially in front, only that part should be black).
But I'm not sure how to do it in an efficient way. I've tried playing around with different SKBlendModes but so far haven't had much success. The major challenge seems to be achieving the effect whilst preserving the colour of the sun behind.
I'm not sure if it's possible to achieve this with the existing SKBlendModes, or if something else will be required.
I've attached a diagram to illustrate what I'm going for and an image of the current best fit.
You can create the silhouette effect with an SKCropNode, a mask node, and a background node. An SKCropNode selectively mask pixels of the sprite nodes in its node tree. Here, it will provide the silhouette effect by hiding/revealing portions of a black circle.
First, create the following objects:
A shape node (yellow circle) with its zPosition set to -1
A sprite node (black circle) with the same size as the yellow one
A crop node (SKCropNode) and a mask node (SKNode)
Next,
Add the yellow circle at the center of the scene
Add the black sprite as a child of the crop node
Assign the mask node to the maskNode property of the crop node
Add the crop node at the center of the scene
Since the mask node currently has no children, the black circle will be completely hidden and the entire yellow circle beneath it will be visible. As we add sprites to the mask node, the pixels of the black circle that intersect with the sprite will be unmasked (shown in black), producing the silhouette effect.
All that's left is to add a "presentation" node that will be displayed when the mask node's sprite is outside of the black circle. The presentation node will mirror the mask node's sprite's position and rotation. This should be done in didSimulatePhysics to ensure that the presentation and mask-node sprites are synchronized after the physics and actions have been updated.
But wait...if the presentation node moves over the yellow circle, won't it eclipse the Sun? Not if we set its presentation node's zPosition to -2.
The following shows an implementation of the above:
This problem was interesting to me, so I came up with a simple solution. It's not perfect nor does it scale very well, but the basics fulfill your need I believe and it may point others in the right direction.
I don't use any special SKBlendMode. Instead, I am using a duplicate object for the object which moves in front of the sun. This duplicate object is cropped using an SKCropNode with a duplicate of the sun as the maskNode. So, my node tree is as follows:
SKSpriteNode (sun) (the white sun)
SKSpriteNode (object1) (the rotating purple square with alpha 0.25)
SKCropNode
maskNode: SKSpriteNode (sunDuplicate = [sun copy])
SKSpriteNode (object1duplicate, same size as object1 but with [SKColor blackColor])
Inside the update method, align the duplicate with the original to ensure animation is properly forwarded.
- (void)update:(CFTimeInterval)currentTime {
self.object1duplicate.position = self.object1.position;
self.object1duplicate.zRotation = self.object1.zRotation;
}
As I said, this doesn't scale very well since you'll manually have to add duplicate objects and keep track of them for each object moving in front of the sun object. Perhaps SKShader can be of more elegant use.
I'm trying to make a ViewController that presents info from a webpage like this:
However, I'm confused on one thing. How did they get the imageView to display an image that's cut off at the corner, i.e. not rectangular? Do you think they created that player card in Photoshop and used it as the background for the imageView image, or did they create it programmatically?
I wonder because the image is behind the picture of the bear, so I imagine if they created the background in Photoshop, how would they get the image behind the bear head? They can't have just created the card with the player's picture as part of it, then loaded the whole image because if they traded the player, because I'm sure they pull the player info and picture from the web so they can have a card for all players, even if they trade or acquire a new player mid-season, without having to update the app (and add the finished image to images.xcassets).
This can be composed from two CALayers at runtime. Put the picture on the bottom layer; the picture can come from anywhere - the web, the bundle, etc. the image source could be dynamic.
Put another CALayer on top, with the frame rendered with opaque colors, and a transparent cut-out for the picture in the middle:
There are a bunch of ways to do this. A simple and flexible way to do it is to create a CAShapeLayer that's the same size as the image view, with it's origin at 0,0, and add it as the UIImageView's layer's mask.
You'd create a filled UIBezierPath that maps out the part of the image you want to show, and install the bezier path's CGPath into the mask layer's path property.
The result would be that the image view is cropped so that only the part inside the shape is drawn.
So I am trying to get a very basic "flashlight"-style thing going in one of my games.
The way I was getting it to work, was having a layer on top of my game screen, and this layer would draw a black rectangle with ~ 80% opacity, creating the look of darkness on top of my game scene.
ccDrawSolidRect(ccp(0,0), ccp(480,320), ccc4f(0, 0, 0, 0.8));
What I want to do is draw this rectangle EVERYWHERE on the screen, except for around a cone of vision that will represent the "light source".
What this would create would be a dark overlay on top of everything except for the light, giving it the illusion of a torch/light/flashlight.
The only way I can foresee this happening is by using ccDrawSolidPoly(), but since the position of the light source changes, so would the vertices for the poly.
Any suggestions on how to achieve this would be great.
You can use ccDrawSolidPoly() and avoid having to manually update vertices. For this you can create a new subclass of CCNode representing your light object, and do your custom shape drawing in its -(void)draw method.
The ccDraw...() functions will draw relative to the local sprite coordinates, so you can then move and rotate your new sprite to suit your needs and cocos2d will do the vertices transformations for you.
Update: I found out that you might be better off subclassing CCDrawNode instead of CCNode, as it has some facilities for raw OpenGL drawing (OpenGL's vertexArrayBuffer and vertexBufferObject internal variables and a buffer for vertices, their colors and their texCoords). If your stuff is very simple, maybe subclassing the plain CCNode is enough.
Could a png be used instead as a mask, as the layer above
Like that binocular vision you sometimes see in cartoons?
Or a filter similar to a photoshop mask that darkens as it grows outwardly to wards the edge of the screen
Just a thought anyway...
A picture of more of what your trying to explain might be good too