Xcode SceneKit Shadows Will Not Render - scenekit

I am creating a simple project using SceneKit and cannot get any shadows to appear in the Scene Editor or in the compiled application no matter what I try.
I have tried creating a simple box, placing it on a plane and adding a spot light. Code would be as follows:
// Create some properties
var scnView: SCNView!
var scnMasterScene: SCNScene!
var boxNode: SCNNode!
var cameraPerspNode: SCNNode!
var cameraOrthNode: SCNNode!
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
setupView()
createAndAddBoxScene()
setupCamera()
createAndAddSpotLight()
}
// Setup the view.
func setupView() {
scnView = self.sceneView as SCNView
// Set the scnView properties.
scnView.showsStatistics = true
scnView.autoenablesDefaultLighting = false
scnView.allowsCameraControl = true
// Create a Master scene.
scnMasterScene = SCNScene()
// Set the scene view's scene node to the master scene.
scnView.scene = scnMasterScene
}
// Setup the scene.
func createAndAddBoxScene() {
// Create a box of type SCNGeometry
let boxGeometry: SCNGeometry = SCNBox(width: 2000, height: 2000, length: 2000, chamferRadius: 100)
// Add a difuse colour to the box' first material.
boxGeometry.firstMaterial?.diffuse.contents = NSColor.redColor()
// Create a node of type SCNNode and attach the boxGeometry to it.
// Note: A node can only have 1 geometry object attached to it.
boxNode = SCNNode(geometry: boxGeometry)
// Add the new boxNode to the scene's root node.
scnMasterScene.rootNode.addChildNode(boxNode)
// Create a floor plane.
let floorGeometry: SCNGeometry = SCNPlane(width: 20000, height: 20000)
// Add a difuse colour to the floor's first material.
floorGeometry.firstMaterial?.diffuse.contents = NSColor.yellowColor()
// Create a floorPlaneNode and attach the floor plane to it.
let floorNode: SCNNode = SCNNode(geometry: floorGeometry)
// Tilt the floorPlaneNode in x.
let floorNodeTiltDegreesX: Double = -90
let floorNodeTiltRadiansX: Double = floorNodeTiltDegreesX * (π/180)
floorNode.rotation = SCNVector4Make(1, 0, 0, CGFloat(floorNodeTiltRadiansX))
// Add the floorPlaneNode to the master scene.
scnMasterScene.rootNode.addChildNode(floorNode)
}
// Create a camera, position it and add it to the scene.
func setupCamera() {
// Create a camera node which will be used to contain the camera.
cameraPerspNode = SCNNode()
// Create a new camera.
let cameraPersp: SCNCamera = SCNCamera()
// Set camera properties.
cameraPersp.name = "myPerspCamera"
cameraPersp.usesOrthographicProjection = false
cameraPersp.orthographicScale = 9
cameraPersp.xFov = 30
cameraPersp.zNear = 1
cameraPersp.zFar = 20000
// Assign the camera to the .camera property of the node.
cameraPerspNode.camera = cameraPersp
// Set the position and rotation of the camera node (NOT the camera).
cameraPerspNode.position = SCNVector3(x: 0, y: 4000, z: 6000)
let cameraPerspTiltDegrees: Double = -30
let cameraPerspTiltRadians: Double = cameraPerspTiltDegrees * (π/180)
cameraPerspNode.rotation = SCNVector4Make(1, 0, 0, CGFloat(cameraPerspTiltRadians))
// Add the new cameraNode to the scene's root.
scnMasterScene.rootNode.addChildNode(cameraPerspNode)
}
func createAndAddSpotLight() -> Void {
let spot = SCNLight()
spot.type = SCNLightTypeSpot
spot.castsShadow = true
spot.color = NSColor(hue: 1, saturation: 0, brightness: 0, alpha: 1)
spot.spotInnerAngle = 30
spot.spotOuterAngle = 60
let spotNode = SCNNode()
spotNode.light = spot
spotNode.position = SCNVector3(x: 0, y: 2000, z: 2000)
let lookAt = SCNLookAtConstraint(target: boxNode)
spotNode.constraints = [lookAt]
}
If I bring in a .dae filed add a spot light, or directional light, using the Scene Editor I can light the scene but there are no shadows when I set the Cast Shadows property in the Attributes Inspector.
Can anyone shine any light on my problem?
Thanks

The scene is large because the 3D model has been created at 1:1 and it depicts a large building. After much trial and error I finally found the solution - I changed the scale of the light to 10, 10, 10 and the shadows appeared.

the dimensions in your scene are huge (in SceneKit 1 unit = 1 meter). You'll want to change your light's zFar property (and probably zNear too) accordingly.

Related

How to create a border for SCNNode to indicate its selection in iOS 11 ARKit-Scenekit?

How to draw a border to highlight a SCNNode and indicate to user that the node is selected?
In my project user can place multiple virtual objects and user can select any object anytime. Upon selection i should show the user highlighted 3D object. Is there a way to directly achieve this or draw a border over SCNNode?
You need to add a tap gesture recognizer to the sceneView.
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
Then, handle the tap and highlight the node:
#objc
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as! SCNView
// check what nodes are tapped
let p = gestureRecognize.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
// check that we clicked on at least one object
if hitResults.count > 0 {
// retrieved the first clicked object
let result = hitResults[0]
// get its material
let material = result.node.geometry!.firstMaterial!
// highlight it
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
// on completion - unhighlight
SCNTransaction.completionBlock = {
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
material.emission.contents = UIColor.black
SCNTransaction.commit()
}
material.emission.contents = UIColor.red
SCNTransaction.commit()
}
}
The snippet above highlights the whole node. You'd have to adjust it to highlight the borders only, if that's what you're looking for.
Disclaimer:
This code was taken directly from Xcode's template code created when opening a new game (SceneKit) project.

clipped image not visible on Tablet EaselJS + sourceRect used

i am working on a Mobile project (iPad with iOS 8.0.2);
I want to make clipping of my immage in order to display less from it.
When displaying on PC it works perfectly well, while we test it on the tablet the clipped image is not displayed at all.
Do you have any suggestions
this.background = new createjs.Bitmap('some_image.png');
//create a clipping of drawn image!
var dims = this.background.getBounds();
this.background.sourceRect = new createjs.Rectangle(0, 15, dims.width, dims.height);
this.background.x = 248;
this.background.y = 86;
this.stage.addChild(this.background);
I met the same trouble like this.I have given up using Bitmap to clipping the image. I have found another solution ,here is "
easeljs splitting an image into pieces
".Good luck.
I am working out, the code like this:
var img, stage;
function init() {
//wait for the image to load
img = new Image();
img.onload = handleImageLoad;
img.src = "./res/image.png";
}
function handleImageLoad(evt) {
// create a new stage and point it at our canvas:
stage = new createjs.Stage("canvas");
// create a new Bitmap, and slice out one image from the sprite sheet:
var bmp = new createjs.Bitmap(evt.target).set({x:200, y:200});
bmp.sourceRect = new createjs.Rectangle(916, 101, 84, 84);
//x,y,width,height
stage.addChild(bmp);
stage.update();
}
This is the example:
https://github.com/CreateJS/EaselJS/blob/master/examples/Filters_animated.html

Plot 3D with specific x and y ILNumerics

I have a 3D array, I want to plot it as a surface in ILNumerics. Here is my code:
ILArray<float> plot = ILMath.tosingle(hasil);
var scene = new ILScene();
ILColormap cm = new ILColormap(Colormaps.Jet);
ILArray<float> data = cm.Data;
scene.Add(
new ILPlotCube(twoDMode: false){
new ILSurface(plot[":;:;2"]){
Wireframe = { Color = Color.FromArgb(50, Color.LightGray)},
Colormap = new ILColormap(data),
Children = { new ILColorbar()}
}
}
);
ilPanel1.Scene = scene;
And here is the result:
Actually my array includes the x posisition (plot[":;:;0"]) and y position (plot[":;:;1"]). How to use that for ILSurface in order to get the correct grid positions and value? Rather than indexed value in the range 0-100?
Well, it was simply. I already got the answer.
new ILSurface(plot[":;:;2"],plot[":;:;0"],plot[":;:;1"])

How to get an array of coordinates that make up a circle in canvas?

So, if this is the code I'm using to draw a circle on my canvas:
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.lineWidth = 3;
ctx.strokeStyle = "black";
ctx.stroke();
... how could I get an array of coordinates of the points that make up this circle so I can save them in a database and load on canvas later using the context.moveTo() and context.lineTo() methods to connect the dots, drawing the same circle?
I guess I'm asking if it's possible to draw this kind of circle using not .arc() method but by connecting dots with lines, if I only know my center coordinates and circle radius (and of course the width of the line and color). This should enable me to save each dot coordinates in an array as I loop through.
#Octopus is on the right track:
var centerX=100;
var centerY=100;
var radius=40;
// an array to save your points
var points=[];
for(var degree=0;degree<360;degree++){
var radians = degree * Math.PI/180;
var x = centerX + radius * Math.cos(radians);
var y = centerY + radius * Math.sin(radians);
points.push({x:x,y:y});
}
Then you can draw the circle using the point objects in the points array:
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++){
ctx.lineTo(points[i].x,points[i].y);
}
ctx.closePath();
ctx.fillStyle="skyblue";
ctx.fill();
ctx.strokeStyle="lightgray";
ctx.lineWidth=3;
ctx.stroke()
A suggestion, however...
Instead of saving all the points in the database, just save the centerX/Y and radius in the database.
Then you can use this same math to create the points and draw the circle.
You are asking for the formula for a circle which is:
radius*radius = (x-centerX)*(x-centerX) + (y-centerY)*(y-centerY)
Or if you want to generate n points do something like this:
for (i=0;i<n;i++) {
x[i] = centerX + radius* Math.cos( (i*2*Math.PI)/n );
y[i] = centerY + radius*-Math.sin( (i*2*Math.PI)/n );
}

F# WPF - displaying a simple object in Viewport3D

I'm trying to get into generating 3D graphics in F# (as was apparent from my previous question) with very little time and very little initial knowledge of F#. I'm studying Tomas Petricek's fractal example, but I can't really make heads or tails of it. I've managed to define a window with a Viewport3D object in XAML, initialize and display it from F#. But as far as creating 3d objects in F# and displaying them goes, I'm lost in a sea of fractal generation, coordinate translation, and other calculations.
Could somebody provide a simple example, of creating one really simple object in F# (a single cube, or just a triangle) and display it in the WPF window? That would be huge help.
Thank you.
Here's a simple example with two triangles making a single square:
#if INTERACTIVE
#r "PresentationCore"
#r "PresentationFramework"
#r "WindowsBase"
#r "System.Xaml"
#endif
open System.Windows
open System.Windows.Controls
open System.Windows.Media
open System.Windows.Media.Media3D
let grp = Model3DGroup()
let geo = MeshGeometry3D()
// Point collection
for x,y,z in [0.5, 0.0, 0.0;
1.0, 0.0, 0.0;
0.5, 0.5, 0.0;
1.0, 0.5, 0.0] do
geo.Positions.Add(Point3D(x,y,z))
// First triangle
for i in [0;1;2] do geo.TriangleIndices.Add(i)
// Second triangle - order matters for deciding front vs. back
for i in [2;1;3] do geo.TriangleIndices.Add(i)
// Create a model with the mesh and a front and back material
let model =
GeometryModel3D(
Geometry = geo,
Material = DiffuseMaterial(Brushes.Black),
BackMaterial = DiffuseMaterial(Brushes.Red))
grp.Children.Add(model)
// add light so back color is visible
grp.Children.Add(AmbientLight())
// set up a continuous rotation around the y-axis
let rotation = AxisAngleRotation3D(Axis = Vector3D(0.,1.,0.))
let anim =
Animation.DoubleAnimation(0.0, 360., Duration(System.TimeSpan.FromSeconds 2.),
RepeatBehavior = Animation.RepeatBehavior.Forever)
rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, anim)
// apply the rotation to the geometry
grp.Transform <- RotateTransform3D(rotation)
// create a camera pointing at the triangle
let cam = PerspectiveCamera(Point3D(0.,0.,2.), Vector3D(0., 0., -1.), Vector3D(0., 1., 0.), 60.)
// set the viewport up with the camera and geometry
let vprt = Viewport3D(Camera = cam)
vprt.Children.Add(ModelVisual3D(Content = grp))
// add the viewport to a window
let wnd = Window(Content = vprt, Title = "3D", Visibility = Visibility.Visible)

Resources