After long time with iOS, I never had 3D experience, and now I need to create 1 cube that can be rotated.
I am trying to figure out how to create a cube from an image , and rotate it in swift.
This link https://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl has made exactly that but its not swift.
His other tutorials for swift are much more complex.
I am looking to have 2 functions :
create a 3d cube from image
rotate it to a certain x,y,z
Is there a simple Apple 3D animation class to that ?
import UIKit
import SceneKit
import QuartzCore
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let scnView = self.view as! SCNView
scnView.scene = scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15) //where will be situated a cube
scnView.allowsCameraControl = true //that's for you can spin it any direction with your finger if you are bored
scnView.autoenablesDefaultLighting = true //Lightting
var geometries = [
SCNBox(width: 4.0, height: 4.0, length: 4.0, chamferRadius: 0),
] //This is the cube with parameters of 4
var materials = [SCNMaterial]()
for i in 1...6 {
let material = SCNMaterial()
if i == 1 { material.diffuse.contents = UIImage (named: "qr.png") }
if i == 2 { material.diffuse.contents = UIColor(red: 0.6784, green: 0.698, blue: 0.7412, alpha: 1.0) }
if i == 3 { material.diffuse.contents = UIColor(red: 0.6784, green: 0.698, blue: 0.7412, alpha: 1.0) }
if i == 4 { material.diffuse.contents = UIColor(red: 0.6784, green: 0.698, blue: 0.7412, alpha: 1.0) }
if i == 5 { material.diffuse.contents = UIColor(red: 0.6784, green: 0.698, blue: 0.7412, alpha: 1.0) }
if i == 6 { material.diffuse.contents = UIColor(red: 0.7882, green: 0.7961, blue: 0.8863, alpha: 1.0) }
materials.append(material)
} //this is to coloring each side of cube
for i in 0..<geometries.count {
let geometry = geometries[i]
let node = SCNNode(geometry: geometry)
node.geometry?.materials = materials
node.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 1, y: 1, z: 1, duration: 5)))
scene.rootNode.addChildNode(node)
}
}
Related
I have this code which creates a gradient background.
When I rotate the deviace to landscape mode, the gradient background doesnt fill up to the whole size of the screen, some parts are white.
My goal is the whenever the orrientation changes, the gradient should fill the whole screen.
let gradient: CAGradientLayer = CAGradientLayer()
let color1 = UIColor(red: 198.0/255.0 , green: 255.0/255.0, blue: 221.0/255.0, alpha: 1.0).cgColor
let color2 = UIColor(red: 251.0/255.0, green: 215.0/255.0, blue: 134.0/255.0, alpha: 1.0).cgColor
let color3 = UIColor(red: 247.0/255.0, green: 121.0/255.0, blue: 125.0/255.0, alpha: 1.0).cgColor
gradient.name="asd"
gradient.colors = [color1,color2,color3]
gradient.locations = [0.0 , 1.0]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
gradient.frame = CGRect(x: 0.0, y: 0.0, width: wid, height: heu)
self.view.layer.insertSublayer(gradient, at: 0)
}
Hold the gradient layer as a property and update its frame in layoutSubview()
var gradientLayer: CAGradientLayer?
override func viewDidLoad() {
super.viewDidLoad()
///
/// YOUR CODE
///
gradientLayer = gradient
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer?.frame = self.view.bounds
}
Switch statement works but won't reset view background colours etc.
I have a UIImage (icon) and a UIButton embedded within a UIView (of custom type DropShadowCircleView) as per image below.
When the walking button is tapped a var navigationOption is set to either walking or driving and setupNavigationSelectionView() is executed.
Problem is: case "walking" of the switch works perfectly, but case "driving" doesn't reset the UIView and icon tint color witcback to their original setting eg; background color etc.. any ideas why?
func setupNavigationSelectionView(){
switch navigationOption {
case "walking":
walkingBg.setGradientBackground(colourOne: softGreen, ColourTwo: softBlue)
walkingBg.layer.cornerRadius = walkingBg.frame.width / 2
walkingBg.clipsToBounds = true
walkingIcon.tintColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
case "driving":
walkingBg.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
walkingBg.layer.cornerRadius = walkingBg.frame.width / 2
walkingBg.clipsToBounds = true
walkingIcon.tintColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
default:
break
}
}
EDIT: this is my DropShadowCircleView class
class DropShadowCircleView: UIView {
override func awakeFromNib() {
setupView()
super.awakeFromNib()
}
func setupView(){
self.layer.shadowOpacity = 0.50
self.layer.shadowRadius = 20
self.layer.shadowColor = UIColor.black.cgColor
self.layer.cornerRadius = self.frame.width / 2
}
}
EDIT: This is my setGradientBackground function which is within an extension file to UIView
func setGradientBackground(colourOne: UIColor, ColourTwo: UIColor) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = [colourOne.cgColor, ColourTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 1.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.0)
layer.insertSublayer(gradientLayer, at: 0)
}
You need to remove your gradient layer when you reset your icon.
Add this to your extension UIView:
func removeGradientBackground() {
guard
let idx = layer.sublayers?.index(where: { $0 is CAGradientLayer })
else { return }
layer.sublayers?.remove(at: idx)
}
and call it when you are resetting your icon.
I am not sure if I understand the concept of Masking correctly but I am trying to recreate the Twitter logo expansion animation in their app:
Twitter Logo expansion
I have this code so far:
class LaunchScreenViewController: UIViewController {
var mask: CALayer!
override func viewDidLoad() {
setUpViewMask()
}
func setUpViewMask() {
mask = CALayer()
mask.contents = UIImage(named: "logo_mask")?.cgImage
mask.contentsGravity = kCAGravityResizeAspect
mask!.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
mask!.anchorPoint = CGPoint(x: 0.5, y: 0.5)
mask!.position = CGPoint(x: view.frame.size.width/2, y: view.frame.size.height/2)
view.layer.backgroundColor = UIColor(red: 70/255, green: 154/255, blue: 233/255, alpha: 1).cgColor
view.layer.mask = mask
}
}
The output of this is:
How would I change the black background to be blue? I tried doing but it didn't seem to work:
view.layer.backgroundColor = UIColor(red: 70/255, green: 154/255, blue: 233/255, alpha: 1).cgColor
Create an intermediate layer where you apply mask. Set the background of your view to the desired background, and set background color of the intermediate layer to the color that you wish your mask to appear in. Something like this,
view.backgroundColor = UIColor(red: 70/255, green: 154/255, blue: 233/255, alpha: 1) // set background of the view portion that do not include mask
let parentLayer = CALayer()
parentLayer.frame = view.bounds
parentLayer.backgroundColor = UIColor.white.cgColor // sets background of mask
view.layer.addSublayer(parentLayer)
let mask = CALayer()
mask.contents = UIImage(named: "twitter.png")?.cgImage
mask.contentsGravity = kCAGravityResizeAspect
mask.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
mask.anchorPoint = CGPoint(x: 0.5, y: 0.5)
mask.position = CGPoint(x: view.frame.size.width/2, y: view.frame.size.height/2)
parentLayer.mask = mask
This can be achieved by changing the background color of appDelegate's window...
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window!.backgroundColor = UIColor.blue
I have encountered a problem involving setting gradients for labels and buttons. I know this question has been asked a lot, but no answer has seemed to solve my problem. Here is the screen as I want it to look:
This is my code:
#IBOutlet weak var loginButton: UIButton!
#IBOutlet weak var signUpButton: UIButton!
#IBOutlet weak var logoLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
loginButton.backgroundColor = UIColor.clear
let loginButtonGradient = createBlueGreenGradient(from: loginButton.bounds)
self.view.layer.insertSublayer(loginButtonGradient, at: 0)
signUpButton.backgroundColor = UIColor.clear
let signUpButtonGradient = createBlueGreenGradient(from: signUpButton.bounds)
self.view.layer.insertSublayer(signUpButtonGradient, at: 0)
logoLabel.backgroundColor = UIColor.clear
let logoLabelGradient = createBlueGreenGradient(from: logoLabel.bounds)
self.view.layer.insertSublayer(logoLabelGradient, at: 0)
loginButton.layer.cornerRadius = 100
signUpButton.layer.cornerRadius = 100
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func createBlueGreenGradient(from bounds: CGRect) -> CAGradientLayer{
let topColor = UIColor(red: 84/255, green: 183/255, blue: 211/255, alpha: 1)
let bottomColor = UIColor(red: 119/255, green: 202/255, blue: 151/255, alpha: 1)
let gradientColors: [UIColor] = [topColor, bottomColor]
let gradientLocations: [NSNumber] = [0.0, 1.0]
let gradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations
gradientLayer.frame = bounds
return gradientLayer
}
And this is the wrong result:
Somebody please help me. I'm not sure what I'm doing wrong.
There are lots of issue with your code.
Divide the color with Float number instead of Int means it should be 255.0 not 255.
Now for colors property of CAGradientLayer you need to set array of CGColor not array of UIColor.
Also set startPoint and endPoint property of CAGradientLayer to make horizontal gradient color.
Currently you are adding this GradientLayer in your self.view instead of its specific button.
Set the cornerRadius of your button on basis of its height not with some constant 100 also after setting cornerRadius you need to also set masksToBounds property of layer to true.
Now for your logo label, you cannot set textColor as Gradient color directly what you need to do is draw the desired gradient on a UIImage and then use that UIImage to set the color pattern for your Label check this SO reference for that.
After making all this changes your code should be like.
func createBlueGreenGradient(from bounds: CGRect) -> CAGradientLayer{
let topColor = UIColor(red: 84/255.0, green: 183/255.0, blue: 211/255.0, alpha: 1).cgColor
let bottomColor = UIColor(red: 119/255.0, green: 202/255.0, blue: 151/255.0, alpha: 1).cgColor
let gradientColors = [topColor, bottomColor]
let gradientLocations: [NSNumber] = [0.0, 1.0]
let gradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations
//Set startPoint and endPoint property also
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
gradientLayer.frame = bounds
return gradientLayer
}
Now set gradientLayer in viewDidLoad this way.
override func viewDidLoad() {
super.viewDidLoad()
let loginButtonGradient = createBlueGreenGradient(from: loginButton.bounds)
self.loginButton.layer.insertSublayer(loginButtonGradient, at: 0)
let signUpButtonGradient = createBlueGreenGradient(from: signUpButton.bounds)
self.signUpButton.layer.insertSublayer(signUpButtonGradient, at: 0)
loginButton.layer.cornerRadius = loginButton.frame.size.height / 2
loginButton.layer.masksToBounds = true
signUpButton.layer.cornerRadius = signUpButton.frame.size.height / 2
signUpButton.layer.masksToBounds = true
}
Your method like this:
func createBlueGreenGradient(from bounds: CGRect) -> CAGradientLayer{
let topColor = UIColor(red: 84/255, green: 183/255, blue: 211/255, alpha: 1).cgColor
let bottomColor = UIColor(red: 119/255, green: 202/255, blue: 151/255, alpha: 1).cgColor
let gradientColors = [topColor, bottomColor]
let gradientLocations: [NSNumber] = [0.0, 1.0]
let gradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations
gradientLayer.frame = bounds
return gradientLayer
}
Oh my goodness I had the same problem, but played around with it. This is caused because you didnt add .cgcolor. For example :
let topColor = UIColor(red: 84/255, green: 183/255, blue: 211/255, alpha: 1).cgColor
let bottomColor = UIColor(red: 119/255, green: 202/255, blue: 151/255, alpha: 1).cgColor
let gradientColors = [topColor, bottomColor]
Let me know if it works.
I have an 'attach node' that has 2 child nodes that are Blender models. I have added a third node to this attach node that is a SCNCone. For some reason, I can't change the color of the cone node, only the transparency. I can't seem to see anything wrong with the code, but during runtime the cone is always a black color no matter what color I set it to.
let coneGeo = SCNCone(topRadius: 0.1, bottomRadius: 0.7, height: 4)
let coneMaterial = SCNMaterial()
coneMaterial.diffuse.contents = UIColor(red: 255.0/255.0, green: 108.0/255.0, blue: 91.0/255.0, alpha: 0.2)
coneGeo.materials = [coneMaterial]
let coneNode = SCNNode(geometry: coneGeo)
coneNode.position = SCNVector3(0, -1.5, 0)
coneNode.name = "coneNode"
AttachNode.addChildNode(coneNode)
Replace coneMaterial.diffuse.contents = UIColor(red: 255.0/255.0, green: 108.0/255.0, blue: 91.0/255.0, alpha: 0.2) with coneGeo.geometry?.firstMaterial?.diffuse.contents.diffuse.contents = UIColor(red: 255.0/255.0, green: 108.0/255.0, blue: 91.0/255.0, alpha: 0.2). Instead of changing the cone's material color without geometry, you have to access it's material color through it's geometry parameter.
coneGeo.materials = [coneMaterial]
This will also work. I tested your code by adding the cone node to an empty scene.
I just get a black screen.
But if I change the alpha value to say 0.5, this is what I get.
The code.
override func viewDidLoad()
{
super.viewDidLoad()
// create a new scene
let scene = SCNScene()
let coneGeo = SCNCone(topRadius: 0.1, bottomRadius: 0.7, height: 4)
let coneMaterial = SCNMaterial()
coneMaterial.diffuse.contents = UIColor(red: 255.0 / 255.0,
green: 108.0 / 255.0,
blue: 91.0 / 255.0, alpha: 0.5)
coneGeo.materials = [coneMaterial]
let coneNode = SCNNode(geometry
: coneGeo)
coneNode.position = SCNVector3(0, -1.5, 0)
coneNode.name = "coneNode"
scene.rootNode.addChildNode(coneNode)
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.black
}
So I would say, check your alpha value in UIColor(red: 255.0/255.0, green: 108.0/255.0, blue: 91.0/255.0, alpha: 0.2)