実現したいこと
球体の中にカメラを置き、自由に視点を動かせるようにしたい
そうすることで、360度に画像が広がっているように見せたい。
発生している問題・分からないこと
球体の中にカメラを配置するようにコードを書いたつもりが、思った通りに動かない
解決法を知りたい
該当のソースコード
TestUniverse02
1import SwiftUI 2import SceneKit 3import Firebase 4import FirebaseAuth 5import FirebaseFirestore 6 7class MyImage { 8 var image: UIImage! 9 let size: CGSize = UIScreen.main.bounds.size 10 var constellations: [Constellation] = [] 11 12 init(constellations: [Constellation]) { 13 self.constellations = constellations 14 let universe = UIImage(named: "starysky02")! 15 image = makeImage(universe) 16 } 17 18 func makeImage(_ universe0Image: UIImage) -> UIImage { 19 var image = UIImage() 20 UIGraphicsBeginImageContextWithOptions(size, false, 3) 21 let context = UIGraphicsGetCurrentContext() 22 23 context?.translateBy(x: 0, y: size.height) 24 context?.scaleBy(x: 1.0, y: -1.0) 25 26 universe0Image.draw(in: CGRect(origin: .zero, size: size)) 27 28 for constellation in constellations { 29 let originalPoints = constellation.points 30 let minX = originalPoints.map { $0.x }.min() ?? 0 31 let minY = originalPoints.map { $0.y }.min() ?? 0 32 let maxX = originalPoints.map { $0.x }.max() ?? size.width 33 let maxY = originalPoints.map { $0.y }.max() ?? size.height 34 35 let width = size.width 36 let height = size.height 37 38 let randomX = CGFloat.random(in: -width/2...width/2) // ランダムなXオフセットを追加 39 let randomY = CGFloat.random(in: -height/2...height/2) // ランダムなYオフセットを追加 40 41 let scaledPoints = originalPoints.map { CGPoint(x: $0.x + randomX, y: $0.y + randomY) } 42 43 let myPath = MyPath(points: scaledPoints) 44 context?.saveGState() 45 context?.addPath(myPath.getPath()) 46 UIColor.white.setStroke() 47 context?.setLineWidth(1) 48 context?.drawPath(using: .stroke) 49 context?.restoreGState() 50 } 51 52 image = UIGraphicsGetImageFromCurrentImageContext()! 53 UIGraphicsEndImageContext() 54 return image 55 } 56} 57 58struct MyPath: Shape { 59 let points: [CGPoint] 60 61 func path(in rect: CGRect) -> Path { 62 let scaledPath = Path(getPath()) 63 return scaledPath 64 } 65 66 func getPath() -> CGMutablePath { 67 let path = CGMutablePath() 68 69 var scaledPoints = points // スケーリングするためのコピーを作成 70 71 // スケーリング係数 72 let scaleFactor: CGFloat = 0.5 // 例として0.5とします 73 74 // ポイントを一律にスケーリング 75 scaledPoints = scaledPoints.map { CGPoint(x: $0.x * scaleFactor, y: $0.y * scaleFactor) } 76 77 guard let firstPoint = scaledPoints.first else { 78 return path 79 } 80 81 path.move(to: firstPoint) 82 83 for point in scaledPoints.dropFirst() { 84 path.addLine(to: point) 85 } 86 87 path.closeSubpath() 88 89 return path 90 } 91} 92 93struct TestUniverse02: View { 94 @State private var showingConstellations = false 95 @State private var constellations: [Constellation] = [] 96 @State var selectedConstellations: [Constellation] = [] 97 @State private var cameraNode: SCNNode? // カメラノードを保持するState 98 99 var body: some View { 100 101 102 103 ZStack{ 104 VStack { 105 if !selectedConstellations.isEmpty { 106 // 修正: 画像を3Dシーンの背景に表示する 107 SceneView(scene: createScene(selectedConstellations: selectedConstellations)) 108 .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) 109 .edgesIgnoringSafeArea(.all) 110 .onAppear { 111 // シーンが表示されたときにカメラをセットアップする 112 setupCamera() 113 } 114 } else { 115 Image(uiImage: MyImage(constellations: []).image) 116 .padding() 117 } 118 } 119 .padding() 120 121 Button(action: { 122 self.showingConstellations.toggle() 123 if self.showingConstellations { 124 self.fetchConstellations() 125 } 126 }) { 127 Text("+") 128 .foregroundColor(.white) 129 .padding() 130 .background(Color.blue) 131 .cornerRadius(8) 132 } 133 .position(x: UIScreen.main.bounds.width - 40, y: UIScreen.main.bounds.height - 40) 134 135 if showingConstellations { 136 ConstellationListView(constellations: constellations, selectedConstellations: $selectedConstellations, showingConstellations: $showingConstellations) 137 } 138 } 139 } 140 141 // Firestoreの情報 142 func fetchConstellations() { 143 guard let user = Auth.auth().currentUser else { 144 print("User is not logged in") 145 return 146 } 147 148 let db = Firestore.firestore() 149 db.collection("users").document(user.uid).collection("constellations").getDocuments { querySnapshot, error in 150 guard let documents = querySnapshot?.documents else { 151 print("No documents") 152 return 153 } 154 155 self.constellations = documents.map { queryDocumentSnapshot in 156 let data = queryDocumentSnapshot.data() 157 let id = queryDocumentSnapshot.documentID 158 let name = data["name"] as? String ?? "" 159 let points = (data["points"] as? [[String: CGFloat]])?.map { CGPoint(x: $0["x"] ?? 0, y: $0["y"] ?? 0) } ?? [] 160 161 return Constellation(id: id, name: name, points: points) 162 } 163 } 164 } 165 166 // 3Dシーンを作成する 167 func createScene(selectedConstellations: [Constellation]) -> SCNScene { 168 let scene = SCNScene() 169 170 // 球体を作成する 171 let sphereGeometry = SCNSphere(radius: 50.0) 172 173 // 画像をテクスチャとして使用する 174 let textureImage = MyImage(constellations: selectedConstellations).image 175 let material = SCNMaterial() 176 material.diffuse.contents = textureImage 177 sphereGeometry.materials = [material] 178 material.isDoubleSided = true 179 180 // 球体ノードを作成し、シーンに追加する 181 let sphereNode = SCNNode(geometry: sphereGeometry) 182 scene.rootNode.addChildNode(sphereNode) 183 184 185 186 187 return scene 188 } 189 190 // カメラをセットアップする 191 func setupCamera() { 192 let camera = SCNCamera() 193 cameraNode = SCNNode() 194 cameraNode!.camera = camera 195 cameraNode!.position = SCNVector3(x: 0, y: 0, z: -10) 196 197 198 let scene = createScene(selectedConstellations: selectedConstellations) 199 scene.rootNode.addChildNode(cameraNode!) 200 201 202 } 203 204 205 // 星座リスト 206 struct ConstellationListView: View { 207 let constellations: [Constellation] 208 @Binding var selectedConstellations: [Constellation] 209 @Binding var showingConstellations: Bool 210 211 var body: some View { 212 VStack { 213 Text("星座") 214 .font(.title) 215 .padding() 216 217 List(constellations) { constellation in 218 Button(action: { 219 selectedConstellations.append(constellation) 220 showingConstellations = false 221 }) { 222 Text(constellation.name) 223 .padding() 224 } 225 } 226 } 227 .background(Color.white) 228 .cornerRadius(10) 229 .padding() 230 .shadow(radius: 5) 231 } 232 } 233} 234 235struct TestUniverse02_Previews: PreviewProvider { 236 static var previews: some View { 237 TestUniverse02() 238 } 239} 240 241 242 243
試したこと・調べたこと
上記の詳細・結果
視点の位置や球体の大きさを変更しようとしたが何も変わらない
補足
特になし
0 コメント