soft shadow, shadow blur in SceneKit - ios

I add one node and try to setting shadow blur with SceneKit
here's my light config, I did try to set shadowRadius
light = [SCNLight light];
light.type = SCNLightTypeDirectional;
light.castsShadow = true;
light.shadowMode = SCNShadowModeForward;
light.shadowRadius = 5;
light.shadowMapSize=CGSizeMake(4000, 4000);
light.orthographicScale=25;
light.zNear=1;
light.zFar=1000;
but the result is not softer than when I not set shadowRadius
it' here:
I did try to add samplecount
light = [SCNLight light];
light.type = SCNLightTypeDirectional;
light.castsShadow = true;
light.shadowMode = SCNShadowModeForward;
light.shadowRadius = 5;
// add samplecount
light.shadowSampleCount = 5;
light.shadowMapSize=CGSizeMake(4000, 4000);
light.orthographicScale=25;
light.zNear=1;
light.zFar=1000;
result look like following
shadow seem soft but this shadow start from bottom of the node (z coordinate is 0). I spend a lot of time to set soft shadow only in the edge of node, not from bottom. But no result.
This problem also occurred when add two node cross over(not only node and geometry as SCNFloor)
My problem is how to get shadow blur(soft shadow) with direction light.
any help would be appreciated!

Swift 4 / Xcode 9.2
I got a pretty good result with these settings:
light2.castsShadow = true
light2.automaticallyAdjustsShadowProjection = true
light2.maximumShadowDistance = 20.0
light2.orthographicScale = 1
light2.shadowMapSize = CGSize(width: 2048, height: 2048)
light2.shadowMode = .forward
light2.shadowSampleCount = 128
light2.shadowRadius = 3
light2.shadowBias = 32
Increasing the shadowRadius to 12 helped a lot with my model, but then I needed to increase shadowSampleCount and shadowBias to not get artifacts.

I really can make shadow blur with orthographicScale. I don't know why, but this trick work for me. Hope can help someone
light.shadowMapSize=CGSizeMake(4000, 4000);
light.orthographicScale=100; // bigger is softer
I also change shadowMapSize to bigger value and setting isJitteringEnabled antialiasingMode to reduce aliasing.

Related

Optimization Opportunities: UISwitch mask - custom offTintColor

While debugging the View Hierarchy, I came across this optimization warning about a UISwitch control with a mask view. Though I have no clear picture what would be the benefits of addressing this warning (insights please), I tried to fix it with no success.
Optimization Opportunities: The layer is using a simple layer with background color set as a mask. Instead, use a container layer of the same frame and cornerRadius as the mask, but with masksToBounds set to YES.
let maskedSwitch: UISwitch = UISwitch()
maskedSwitch.translatesAutoresizingMaskIntoConstraints = false
maskedSwitch.tintColor = .black
maskedSwitch.onTintColor = .green
maskedSwitch.backgroundColor = .black
let maskView = UIView(frame: maskedSwitch.frame)
maskView.backgroundColor = .black
maskView.layer.cornerRadius = maskedSwitch.frame.height / 2
maskView.layer.masksToBounds = true
maskView.clipsToBounds = true
maskedSwitch.mask = maskView
let scale: CGFloat = 2.5 / 3
maskedSwitch.transform = CGAffineTransform(scaleX: scale, y: scale)
As suggested, I tried removing the maskView and directly applying the cornerRadius and offTintColor on switch. But it ended up messing the scale transformation, and it is kind of important to retain the UI.
How can I further optimise the code and make sure all these conditions addressed: 1. set offTintColor to black, 2. scale the switch and 3. Avoid the optimization opportunity warning?
Note: Please do share if there is an Apple doc to study more on the topic Optimization Opportunities. Thanks!

SceneKit and ARKit – Soft shadows or blurred shadows

I have set up shadow in ARKit, But it's not satisfied results, we have required the same shade as quick view in safari. Please help me how to set up it. We have attached two images.
Code
var light = SCNLight()
var lightNode = SCNNode()
light.castsShadow = true
light.automaticallyAdjustsShadowProjection = true
light.maximumShadowDistance = 20.0
light.orthographicScale = 1
light.type = .directional
light.shadowMapSize = CGSize(width: 2048, height: 2048)
light.shadowMode = .deferred
light.shadowSampleCount = 128
light.shadowRadius = 3
light.shadowBias = 32
light.zNear = 1
light.zFar = 1000
light.shadowColor = UIColor.black.withAlphaComponent(0.36)
lightNode.light = light2
lightNode.eulerAngles = SCNVector3(-Float.pi / 2, 0, 0)
self.sceneView.scene.rootNode.addChildNode(lightNode)
Provide shadow offset and increase the shadow radius. Play with these values to get the desired output.
light.shadowOffset = CGSize(width: 1, height: 1) //controls spread
light.shadowOpacity = 0.5 // controls opacity
light.shadowRadius = 5.0 // controls blur level
If you need a more blurry shadows in your scene use a greater values for shadowRadius instance property. shadowRadius specifies the sample radius used to render the receiver’s shadow.
Default value is 3.0.
var shadowRadius: CGFloat { get set }
...in real code it looks like this:
lightNode.light?.shadowRadius = 20.0
Apple documentation says:
shadowRadius is a number that specifies the amount of blurring around the edges of shadows cast by the light. SceneKit produces soft-edged shadows by rendering the silhouettes of geometry into a 2D shadow map and then using several weighted samples from the shadow map to determine the strength of the shadow at each pixel in the rendered scene. This property controls the radius of shadow map sampling. Lower numbers result in shadows with sharply defined, pixelated edges, higher numbers result in blurry shadows.
Also, use a spotlight instead of directional light, `cause the first one produces nice and blurry shadows.
lightNode.light?.type = .spot
And one more tip: keep you spotlight fixture at the distance of more than 2 meters from model, and assign a value of 179 degrees to spotOuterAngle instance property:
lightNode.light?.spotOuterAngle = 179.0 /* default is 45 degrees */
P.S.
If you wanna know how to use blurred shadows in RealityKit, please read this post.

SpriteKit Shadow falloff does not work

So I have a simple light node and an object and I get this result.
and this is my code.
let light = SKLightNode()
light.categoryBitMask = 1
light.falloff = ... //I tried many values but nothing seems to change
addChild(light)
let block = SKSpriteNode(color: .black(), size: CGSize(90, 160))
block.zPosition = 2
block.shadowCastBitMask = 1
addChild(block)
I want to achieve this kind of look.
You can see the difference. Here the shadow gradually fades.
Am I doing something wrong? If not is there a 3rd party plugin that could work?
Thanks

How to increase the size of an SKLightNode in iOS

I'm playing around with SKLightNodes and attempting to have an object (sun) shine light on anything around it. The problem is that when I add the SKLightNode to the sun node, the SKLightNode only appears in the very center of the sun. I've tried scaling the SKLightNode, but it seems to have no effect on the size or range of the SKLightNode. Here is how The SKLightNode is implemented.
let light = SKLightNode()
light.categoryBitMask = 1;
light.falloff = 1;
light.ambientColor = UIColor.whiteColor();
light.setScale(50)
star!.addChild(light)
If anyone has any input on how I can increase the effectiveness of the light source, I sure would appreciate it.
I think the only way to increase the "size" of an SKLightNode is decreasing the falloff value. You must need to set some value between 0 and 1.0.
// very bright
light?.falloff = 0.1
// a little less bright
light?.falloff = 0.5
// the default brightness
light?.falloff = 1.0
// a little darker
light?.falloff = 2.0
// very dark
light?.falloff = 5.0

Visible duration and actual duration of animation of shape along arc is different

I have a very odd issue, trying to animate a triangle shape along a circular arc, from -π/2 to 2π-π/2 (to start from vertical position). Like this:
// Construct the invisible animation path
var path = UIBezierPath.FromArc(new PointF(rect.GetMidX(), rect.GetMidY()), (rect.Height - 20) / 2, (float)(- Math.PI / 2), (float)(2*Math.PI - Math.PI / 2), true);
var pathLayer = new CAShapeLayer();
pathLayer.Frame = rect;
pathLayer.Path = path.CGPath;
pathLayer.FillColor = UIColor.Clear.CGColor;
pathLayer.StrokeColor = UIColor.Clear.CGColor;
view.AddSublayer(pathLayer); // It appears that I need to create and add a layer to be able to animate along the path?
// Create the shape to animate
var triangleLayer = new CAShapeLayer();
var triangle = CreateTriangle();
triangleLayer.Frame = triangle.Bounds;
triangleLayer.Path = triangle.CGPath;
triangleLayer.StrokeColor = UIColor.Orange.CGColor;
triangleLayer.FillColor = UIColor.Red.CGColor;
var triangleAnim = CAKeyFrameAnimation.GetFromKeyPath("position");
triangleAnim.Path = path.CGPath;
triangleAnim.Duration = 60;
triangleAnim.RotationMode = CAKeyFrameAnimation.RotateModeAuto;
triangleAnim.RemovedOnCompletion = false;
triangleLayer.AddAnimation(triangleAnim, "progress");
view.AddSublayer(triangleLayer);
The full round should take 60 seconds, but it finishes in about 45 seconds, then does nothing for 15 seconds, and then completes the animation. So the animation does seem to take 60 seconds, but the visual animation is only 45 seconds. The odd thing is that if I change the arc from 0 to 2π, the timing is correct. What could cause this issue?
The code is C# with Xamarin.iOS, but Objective C/Swift code would be similar.
Edit:
I found out that it works if I create a UIBezierPath arc from 0 - 2π and then rotate it with -π/2. So I suspect that there is something fishy going on with Xamarin.iOS and UIBezierPath with negative angles.
I made a quick prototype app to test this. For simplicity, I used an image instead of a shape layer. Here is the outcome:
Animating from -M_PI_2 to 3 * M_PI_2 works as expected
There is no need to add the invisible layer (just use the path you created)
This leads me to believe that perhaps your problem is buried in Xamarin.iOS. There have been some quirks with the CGFloat type, so maybe if you could cast the arguments explicitly somehow this might help.

Resources