scihant / CTPanoramaView

A library that displays spherical or cylindrical panoramas with touch or motion based controls.
MIT License
1.04k stars 89 forks source link

Use the sphere to add buttons or views at a specific point in the photo. #25

Open leo1mml opened 6 years ago

leo1mml commented 6 years ago

I was wondering if I could make use of buttons or something like this to go through doors in a photo for example. Is it possible?

OlegPanfyorov commented 6 years ago

Same question from me

yakovlev0509 commented 5 years ago

I have the same question, currently trying to figure out how to place something on the sphere and add tap even to it. "to go through doors in a photo". -- is my main goal.

elibendavid commented 5 years ago

'Hotspots' functionality would definitely boost this project way up

yakovlev0509 commented 5 years ago

@elibendavid @OlegPanfyorov @leo1mml I was required to add hotspots to panoramas of the interior, to simulate navigation in the apartments.

For this, I added CTPanoramaView as files, and after it, I worked with SKScene object, this solution provides two objects in SKScene: sphere/cylinder and camera objects. You can easily add your own object(SKNode) within sphere/cylinder with these positions (x: from -5 to 5; y: from -5 to 5; z: from -5 to 5) and detect a tap on it. Using tag or name parameters you can detect which of the object was tapped and do some required actions. In my case, I change panorama photos and reload new hot spots for this panorama.

After I find this ability it saves a huge amount of time for me.

elibendavid commented 5 years ago

@yakovlev0509

Wow! Sounds good. Would be great if you can share some code

Thanks!

yakovlev0509 commented 5 years ago

@elibendavid

You need to read more info about SKScene and SKNode.

As you found in CTPanoramaView source code, it generates a SKScene with 2 objects in it: sphere/cylinder -- an object which applies to itself your panorama image and camera objects -- actually a camera object.

In my case, I worked with the sphere. As you can find sphere have coordinates (x: from -5 to 5; y: from -5 to 5; z: from -5 to 5) on the SKScene So creating and adding any SKNode objects within this range will add an object in your sphere.
And of course, you will need to adjust the angle for a created object so it will always look to the Camera object side. (this code can be easily found in StackOverflow), their texture, etc. In my case, I just used Plain SKNode objects and added a tag to them, so I can detect which of them was tapped. Because touch will also detect a sphere object (as it is SKNode object). Check Raywenderlich post about detecting objects from CameraNode in SKScene.

They're not so much code need to be added. If you will check CTPanoramaView code in more details you will understand how and where to place it. And creating SKNode object is a very easy task.

Please let me know if you will have any questions.

elibendavid commented 5 years ago

@yakovlev0509

Thanks! Eventually, your inspiration was enough :), we got it working.

SulimanHussain commented 3 years ago

@elibendavid @OlegPanfyorov @leo1mml I was required to add hotspots to panoramas of the interior, to simulate navigation in the apartments.

For this, I added CTPanoramaView as files, and after it, I worked with SKScene object, this solution provides two objects in SKScene: sphere/cylinder and camera objects. You can easily add your own object(SKNode) within sphere/cylinder with these positions (x: from -5 to 5; y: from -5 to 5; z: from -5 to 5) and detect a tap on it. Using tag or name parameters you can detect which of the object was tapped and do some required actions. In my case, I change panorama photos and reload new hot spots for this panorama.

After I find this ability it saves a huge amount of time for me.

Hello! Can you help me with some code sample. I have actually added nodes successfully but the nodes are not showing in the way i want. How can I add for example a small car image as node which will supposed to be tappable. Any Help......Thanks

KamaNext commented 1 year ago

@elibendavid

Вам нужно прочитать больше информации о SKScene и SKNode.

Как вы обнаружили в исходном коде CTPanoramaView, он генерирует SKScene с двумя объектами в нем: сфера/цилиндр - объект, который применяет к себе ваше панорамное изображение и объекты камеры - на самом деле объект камеры.

В моем случае я работал со сферой. Поскольку вы можете найти сферу с координатами (x: от -5 до 5; y: от -5 до 5; z: от -5 до 5) на SKScene, поэтому создание и добавление любых объектов SKNode в этом диапазоне добавит объект в ваша сфера. И, конечно же, вам нужно будет настроить угол созданного объекта, чтобы он всегда смотрел в сторону объекта камеры. (этот код легко найти в StackOverflow), их текстуру и т. д. В моем случае я просто использовал объекты Plain SKNode и добавил к ним тег, чтобы я мог определить, какой из них был нажат. Потому что касание также обнаружит объект сферы (поскольку это объект SKNode). Проверьте сообщение Raywenderlich об обнаружении объектов из CameraNode в SKScene.

Они не так много кода нужно добавить. Если вы более подробно изучите код CTPanoramaView, то поймете, как и где его размещать. А создание объекта SKNode — очень простая задача.

Пожалуйста, дайте мне знать, если у вас возникнут вопросы.

friend tell me please screenshots how you did it or share the code

KamaNext commented 1 year ago

@elibendavid

Вам нужно прочитать больше информации о SKScene и SKNode.

Как вы обнаружили в исходном коде CTPanoramaView, он генерирует SKScene с двумя объектами в нем: сфера/цилиндр — объект, который применяет к себе ваше панорамное изображение и объекты камеры — на самом деле объект камеры.

В моем случае я работал со сферой. Поскольку вы можете найти сферу с координатами (x: от -5 до 5; y: от -5 до 5; z: от -5 до 5) на SKScene, поэтому создание и добавление любых объектов SKNode в этом диапазоне добавит объект в ваша сфера. И, конечно же, вам нужно будет настроить угол созданного объекта, чтобы он всегда смотрел в сторону объекта камеры. (этот код легко найти в StackOverflow), их текстуру и т. д. В моем случае я просто использовал объекты Plain SKNode и добавил к ним тег, чтобы я мог определить, какой из них был нажат. Потому что касание также обнаружит объект сферы (поскольку это объект SKNode). Проверьте сообщение Raywenderlich об обнаружении объектов из CameraNode в SKScene.

Они не так много кода нужно добавить. Если вы более подробно изучите код CTPanoramaView, то поймете, как и где его размещать. А создание объекта SKNode — очень простая задача.

Пожалуйста, дайте мне знать, если у вас возникнут вопросы.

Друг можешь дать пожалуйста образец кода, как ты добавил несколько изображений

yakovlev0509 commented 1 year ago

@KamaNext Please check the comments above:

Here is info about SKNode: https://developer.apple.com/documentation/spritekit/sknode There should be a huge amount of example code on the internet.

I don't have the project source code with me, but you can ask if you have specific questions. And please also follow this advice from my previous comment: "You need to read more info about SKScene and SKNode." It should be a quick task when you understand how it works.

yakovlev0509 commented 1 year ago

@SulimanHussain

Please check Raywenderlich post about detecting objects from CameraNode in SKScene(in case if you need to detect taps on the SKNode object). Also, they described how to add image to SKNode, and how to make images of SKNode always follow the camera object.

KamaNext commented 1 year ago

@yakovlev0509 Please check the comments above:

Here is info about SKNode: https://developer.apple.com/documentation/spritekit/sknode There should be a huge amount of example code on the internet.

I don't have the project source code with me, but you can ask if you have specific questions. And please also follow this advice from my previous comment: "You need to read more info about SKScene and SKNode." It should be a quick task when you understand how it works.

I'm trying to add points, but it doesn't work out, could you make a small example, if you don't mind, or help me figure it out, I would thank you

yakovlev0509 commented 1 year ago

@yakovlev0509 Please check the comments above:

Here is info about SKNode: https://developer.apple.com/documentation/spritekit/sknode There should be a huge amount of example code on the internet. I don't have the project source code with me, but you can ask if you have specific questions. And please also follow this advice from my previous comment: "You need to read more info about SKScene and SKNode." It should be a quick task when you understand how it works.

I'm trying to add points, but it doesn't work out, could you make a small example, if you don't mind, or help me figure it out, I would thank you

@KamaNext please post here the code part related to this, maybe something wrong with it.

KamaNext commented 1 year ago

@yakovlev0509 class MarkPoinScene: SKScene { override init() { let markPoint = SKSpriteNode(imageNamed: "mark") markPoint.name = "markP" super.init()

addChild(markPoint) }

required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func moveMark(){ let markP = childNode(withName: "markP") } } var anchorPoint: CGPoint = CGPoint( x: 0.5, y: 0.5) { didSet { let translateX = ( anchorPoint.x - 0.5 ) let translateY = ( anchorPoint.y - 0.5 ) let translateZ = ( anchorPoint.y - 0.5 ) } }

Artem If you don’t mind, you can download the CTPanorama library and add 1 point I think I can understand by looking at your code

yakovlev0509 commented 1 year ago

@KamaNext try something like this:

//your CTPanoramaView
var panoramaWalkView: CTPanoramaView  

//setup child node
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: spot["yourNodeImageName"]!)
material.isDoubleSided = true // Optional

let planeGeometry = SCNPlane(width: 0.4,height: 0.7)
planeGeometry.materials = [material]
let routNode = SCNNode(geometry: planeGeometry)

routNode.position = SCNVector3(x,y,z) // Place your node in space
routNode.name = "Spot" // Better to have as later you can sort or work with them by their names
routNode.look(at: panoramaWalkView.cameraNode.position) // Make your node look always at camera object
spotsArray.append(routNode) // Optional
panoramaWalkView.scene.rootNode.addChildNode(routNode) // Here we add node to Panorama view

Later, you can access your child nodes via:

panoramaWalkView.scene.rootNode.enumerateChildNodes { (node, stop) in ...

To handle taps or actions on your nodes, you can use something like this:

  1. Add gesture recognizer to PanoramaView
  2. And use:
    
    let tapLocation = sender.location(in: panoramaWalkView?.sceneView)
    let hitTestResults = panoramaWalkView?.sceneView.hitTest(tapLocation)

let node = hitTestResults!.first?.node // Your tapped by user Node



It is not the best implementation or solution. But I hope it helps you solve your task/goal. 
KamaNext commented 1 year ago

@KamaNext try something like this:

//your CTPanoramaView
var panoramaWalkView: CTPanoramaView  

//setup child node
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: spot["yourNodeImageName"]!)
material.isDoubleSided = true // Optional

let planeGeometry = SCNPlane(width: 0.4,height: 0.7)
planeGeometry.materials = [material]
let routNode = SCNNode(geometry: planeGeometry)

routNode.position = SCNVector3(x,y,z) // Place your node in space
routNode.name = "Spot" // Better to have as later you can sort or work with them by their names
routNode.look(at: panoramaWalkView.cameraNode.position) // Make your node look always at camera object
spotsArray.append(routNode) // Optional
panoramaWalkView.scene.rootNode.addChildNode(routNode) // Here we add node to Panorama view

Later, you can access your child nodes via:

panoramaWalkView.scene.rootNode.enumerateChildNodes { (node, stop) in ...

To handle taps or actions on your nodes, you can use something like this:

  1. Add gesture recognizer to PanoramaView
  2. And use:
let tapLocation = sender.location(in: panoramaWalkView?.sceneView)
let hitTestResults = panoramaWalkView?.sceneView.hitTest(tapLocation)

let node = hitTestResults!.first?.node // Your tapped by user Node

It is not the best implementation or solution. But I hope it helps you solve your task/goal. @yakovlev0509 Friend, thank you very much for trying to help me, I really appreciate it and would like to thank you. Unfortunately, I still have problems with adding hotspots, I didn't have these problems in JavaScript and somehow it turned out easily, Swift is still a little unclear in terms of Object-Oriented Programming. If you could download the sources of CTPanoramaView and add 1 point, it would make me happy.

KamaNext commented 1 year ago

@yakovlev0509 Friend, please help me, I can't add an object in any way, I'm trying to use your instructions and I get errors

yakovlev0509 commented 1 year ago

@KamaNext

Friend, please help me, I can't add an object in any way, I'm trying to use your instructions and I get errors

Please share more info

KamaNext commented 1 year ago

@yakovlev0509 @objc public class BetterOnboardingScene: SKScene{ override public init() { let markSpriteView = SKSpriteNode(imageNamed: "mark") markSpriteView.name = "markPoint" let material = SCNMaterial() material.isDoubleSided = true // Optional let planeGeometry = SCNPlane(width: 0.4,height: 0.7) planeGeometry.materials = [material] let routNode = SCNNode(geometry: planeGeometry) routNode.position = SCNVector3(1,1,1) // Place your node in space routNode.name = markSpriteView.cameraNode.position) spotsArray.append(routNode) // Optional markSpriteView.scene.rootNode.addChildNode(routNode) super.init() addChild(markSpriteView) }

eror ( Value of type 'SKSpriteNode' has no member 'cameraNode' )
eror (Value of type 'SKScene?' has no member 'rootNode')
KamaNext commented 1 year ago

@yakovlev0509 please download the panorama project and add 1 point, I will thank you

KamaNext commented 1 year ago

@yakovlev0509 @objc public class markSpriteView: SKScene{ public override func didMove(to view: SKView) { let markSpriteView = SKNode() markSpriteView.name = "markPoint" let markPoint = SKSpriteNode(imageNamed: "mark") let material = SCNMaterial() material.isDoubleSided = true // Optional let planeGeometry = SCNPlane(width: 0.4,height: 0.7) planeGeometry.materials = [material] let routNode = SCNNode(geometry: planeGeometry) routNode.position = SCNVector3(1,1,1) routNode.name = "Spot" self.addChild(markSpriteView) } is this true?

KamaNext commented 1 year ago

@yakovlev0509 public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() }

public override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
}
eror (Property 'self.MarkSpriteView' not initialized at super.init call)
yakovlev0509 commented 1 year ago

@yakovlev0509 public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() }

public override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
}
eror (Property 'self.MarkSpriteView' not initialized at super.init call)

@KamaNext your error totally not related to CTPanoramaView. This is not suitable for this Issue thread. Please post a question in Stackoverflow.

You have some MarkSpriteView (naming - would be better to "markSriteView"), which should be initialized during init, and you are not doing this. First Google/Stackoverflow link will explain in details why this happen.