Anonymous
Цвета становятся черными после сочетания множественных вращений слоя в кубике Scenekit Rubik (SWIFT), но не индивидуальн
Сообщение
Anonymous » 26 фев 2025, 03:58
Я сталкиваюсь с проблемой, когда цвета кубилетов становятся черными после объединения вращений нескольких слоев, но не после отдельных вращений или конкретной комбинации вращения левого слоя + вращения верхнего слоя. Индивидуально каждое вращение слоя (вверху, внизу, справа, слева, спереди, сзади) работает правильно, поддерживая цвета (зеленый для спереди, красный для правого, синий для спины, оранжевый для левого, белый для сверху, желтый для дна). Однако, когда я выполняю такие последовательности, как верхний + справа, спереди + вправо или внизу + слева, цвета некоторых или всех кубилетов становятся черными после второго вращения, но комбинация левого + версия сохраняет цвета. Вот мой код до сих пор: < /p>
cubescene: < /p>
Код: Выделить всё
import SwiftUI
import SceneKit
class CuboScene: SCNScene, ObservableObject {
override init() {
super.init()
rootNode.eulerAngles = SCNVector3(0, 0, 0) // Ensure rootNode is not rotated
rootNode.position = SCNVector3(0, 0, 0) // Ensure rootNode is at the origin
rootNode.scale = SCNVector3(1, 1, 1) // Ensure no unexpected scaling
configureLights()
createRubikCube()
}
private func createRubikCube() {
let size: CGFloat = 0.8
let spacing: CGFloat = 0.78
for x in -1...1 {
for y in -1...1 {
for z in -1...1 {
let cubelet = SCNBox(width: size, height: size, length: size, chamferRadius: 0.10)
let cubeletNode = SCNNode(geometry: cubelet)
cubeletNode.position = SCNVector3(Float(x) * Float(spacing),
Float(y) * Float(spacing),
Float(z) * Float(spacing))
cubeletNode.eulerAngles = SCNVector3(0, 0, 0)
cubelet.materials = getFaceMaterial(x: x, y: y, z: z)
rootNode.addChildNode(cubeletNode)
}
}
}
}
private func getFaceMaterial(x: Int, y: Int, z: Int) -> [SCNMaterial] {
let colors: [UIColor] = [
(z == 1) ? .green : .black, // Front face (+Z)
(x == 1) ? .red : .black, // Right face (+X)
(z == -1) ? .blue : .black, // Back face (-Z)
(x == -1) ? .orange : .black, // Left face (-X)
(y == 1) ? .white : .black, // Top face (+Y)
(y == -1) ? .yellow : .black // Bottom face (-Y)
]
return colors.map { createMaterial(color: $0) }
}
private func createMaterial(color: UIColor) -> SCNMaterial {
let material = SCNMaterial()
material.diffuse.contents = color.withAlphaComponent(1.0)
material.specular.contents = UIColor.white
material.shininess = 100
material.lightingModel = .phong
return material
}
private func configureLights() {
// Ambient light for base illumination
let ambientLight = SCNLight()
ambientLight.type = .ambient
ambientLight.intensity = 500
let ambientLightNode = SCNNode()
ambientLightNode.light = ambientLight
rootNode.addChildNode(ambientLightNode)
// Array of positions and directions for the 6 lights
let positions: [(SCNVector3, SCNVector3)] = [
(SCNVector3(0, 10, 0), SCNVector3(0, -1, 0)), // Top
(SCNVector3(0, -10, 0), SCNVector3(0, 1, 0)), // Bottom
(SCNVector3(10, 0, 0), SCNVector3(-1, 0, 0)), // Right
(SCNVector3(-10, 0, 0), SCNVector3(1, 0, 0)), // Left
(SCNVector3(0, 0, 10), SCNVector3(0, 0, -1)), // Front
(SCNVector3(0, 0, -10), SCNVector3(0, 0, 1)) // Back
]
for (position, direction) in positions {
let light = SCNLight()
light.type = .directional
light.intensity = 1000
light.color = UIColor.white
let lightNode = SCNNode()
lightNode.light = light
lightNode.position = position
lightNode.eulerAngles = SCNVector3(
atan2(direction.y, direction.z),
atan2(direction.x, direction.z),
0)
rootNode.addChildNode(lightNode)
}
}
func rotateLayer(cubelets: [SCNNode], axis: SCNVector3, angle: CGFloat) {
let tempNode = SCNNode()
var originalMaterials: [SCNNode: [SCNMaterial]] = [:]
var originalPositions: [SCNNode: SCNVector3] = [:]
var originalEulerAngles: [SCNNode: SCNVector3] = [:]
for cubelet in cubelets {
if let geometry = cubelet.geometry as? SCNBox {
originalMaterials[cubelet] = geometry.materials
}
originalPositions[cubelet] = cubelet.position
originalEulerAngles[cubelet] = cubelet.eulerAngles
cubelet.removeFromParentNode()
tempNode.addChildNode(cubelet)
}
rootNode.addChildNode(tempNode)
let rotationAction = SCNAction.rotate(by: angle, around: axis, duration: 0.2)
tempNode.runAction(rotationAction) {
for cubelet in cubelets {
let worldPosition = cubelet.worldPosition
tempNode.removeFromParentNode()
let localPosition = self.rootNode.convertPosition(worldPosition, from: nil)
cubelet.position = localPosition
if eje.x != 0 {
cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x + Float(angle), cubelet.eulerAngles.y, cubelet.eulerAngles.z)
} else if eje.y != 0 {
cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x, cubelet.eulerAngles.y + Float(angle), cubelet.eulerAngles.z)
} else if eje.z != 0 {
cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x, cubelet.eulerAngles.y, cubelet.eulerAngles.z + Float(angle))
}
if let geometry = cubelet.geometry as? SCNBox {
geometry.materials = originalMaterials[cubelet] ?? geometry.materials
}
self.rootNode.addChildNode(cubelet)
}
tempNode.removeFromParentNode()
}
}
func rotateTopLayer() {
let axis = SCNVector3(x: 0, y: 1, z: 0)
let angle: CGFloat = .pi / 2
let topCubelets = rootNode.childNodes.filter { node in
abs(node.position.y - 0.78) < 0.01
}
rotateLayer(cubelets: topCubelets, axis: axis, angle: angle)
}
func rotateBottomLayer() {
let axis = SCNVector3(x: 0, y: 1, z: 0)
let angle: CGFloat = -.pi / 2
let bottomCubelets = rootNode.childNodes.filter { node in
abs(node.position.y + 0.78) < 0.01
}
rotateLayer(cubelets: bottomCubelets, axis: axis, angle: angle)
}
func rotateRightLayer() {
let axis = SCNVector3(x: 1, y: 0, z: 0)
let angle: CGFloat = .pi / 2
let rightCubelets = rootNode.childNodes.filter { node in
abs(node.position.x - 0.78) < 0.02
}
rotateLayer(cubelets: rightCubelets, axis: axis, angle: angle)
}
func rotateLeftLayer() {
let axis = SCNVector3(x: 1, y: 0, z: 0)
let angle: CGFloat = -.pi / 2
let leftCubelets = rootNode.childNodes.filter { node in
abs(node.position.x + 0.78) < 0.02
}
rotateLayer(cubelets: leftCubelets, axis: axis, angle: angle)
}
func rotateFrontLayer() {
let axis = SCNVector3(x: 0, y: 0, z: 1)
let angle: CGFloat = .pi / 2
let frontCubelets = rootNode.childNodes.filter { node in
abs(node.position.z - 0.78) < 0.01
}
rotateLayer(cubelets: frontCubelets, axis: axis, angle: angle)
}
func rotateBackLayer() {
let axis = SCNVector3(x: 0, y: 0, z: 1)
let angle: CGFloat = -.pi / 2
let backCubelets = rootNode.childNodes.filter { node in
abs(node.position.z + 0.78) < 0.01
}
rotateLayer(cubelets: backCubelets, axis: axis, angle: angle)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
< /code>
changekitview: < /p>
import SwiftUI
import SceneKit
struct SceneKitView: UIViewRepresentable {
@ObservedObject var cubeScene: CuboScene
func makeUIView(context: Context) -> SCNView {
let view = SCNView()
view.scene = cubeScene
view.allowsCameraControl = true
view.autoenablesDefaultLighting = true
view.backgroundColor = .gray
// Configure an initial camera
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 5, y: 5, z: 5) // Diagonal position to see all faces
cameraNode.look(at: SCNVector3(0, 0, 0)) // Point to the cube's center
view.pointOfView = cameraNode
return view
}
func updateUIView(_ uiView: SCNView, context: Context) {
uiView.scene = cubeScene
}
}
#Preview {
SceneKitView(cubeScene: CuboScene()) // Or RubikCubeScene if preferred
}
< /code>
contenview: < /p>
import SwiftUI
struct ContentView: View {
@StateObject private var cubeScene = CuboScene() // Or use RubikCubeScene if preferred
var body: some View {
VStack {
SceneKitView(cubeScene: cubeScene)
.frame(height: 400)
.ignoresSafeArea()
}
Button("Rotate Top Layer") {
cubeScene.rotateTopLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Right Layer") {
cubeScene.rotateRightLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Left Layer") {
cubeScene.rotateLeftLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Bottom Layer") {
cubeScene.rotateBottomLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Front Layer") {
cubeScene.rotateFrontLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Back Layer") {
cubeScene.rotateBackLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
#Preview {
ContentView()
}
Вот видео о проблеме:
https://www.youtube.com/shorts/7q8xcdjdoce
Подробнее здесь:
https://stackoverflow.com/questions/794 ... -rubik-s-c
1740531502
Anonymous
Я сталкиваюсь с проблемой, когда цвета кубилетов становятся черными после объединения вращений нескольких слоев, но не после отдельных вращений или конкретной комбинации вращения левого слоя + вращения верхнего слоя. Индивидуально каждое вращение слоя (вверху, внизу, справа, слева, спереди, сзади) работает правильно, поддерживая цвета (зеленый для спереди, красный для правого, синий для спины, оранжевый для левого, белый для сверху, желтый для дна). Однако, когда я выполняю такие последовательности, как верхний + справа, спереди + вправо или внизу + слева, цвета некоторых или всех кубилетов становятся черными после второго вращения, но комбинация левого + версия сохраняет цвета. Вот мой код до сих пор: < /p> cubescene: < /p> [code]import SwiftUI import SceneKit class CuboScene: SCNScene, ObservableObject { override init() { super.init() rootNode.eulerAngles = SCNVector3(0, 0, 0) // Ensure rootNode is not rotated rootNode.position = SCNVector3(0, 0, 0) // Ensure rootNode is at the origin rootNode.scale = SCNVector3(1, 1, 1) // Ensure no unexpected scaling configureLights() createRubikCube() } private func createRubikCube() { let size: CGFloat = 0.8 let spacing: CGFloat = 0.78 for x in -1...1 { for y in -1...1 { for z in -1...1 { let cubelet = SCNBox(width: size, height: size, length: size, chamferRadius: 0.10) let cubeletNode = SCNNode(geometry: cubelet) cubeletNode.position = SCNVector3(Float(x) * Float(spacing), Float(y) * Float(spacing), Float(z) * Float(spacing)) cubeletNode.eulerAngles = SCNVector3(0, 0, 0) cubelet.materials = getFaceMaterial(x: x, y: y, z: z) rootNode.addChildNode(cubeletNode) } } } } private func getFaceMaterial(x: Int, y: Int, z: Int) -> [SCNMaterial] { let colors: [UIColor] = [ (z == 1) ? .green : .black, // Front face (+Z) (x == 1) ? .red : .black, // Right face (+X) (z == -1) ? .blue : .black, // Back face (-Z) (x == -1) ? .orange : .black, // Left face (-X) (y == 1) ? .white : .black, // Top face (+Y) (y == -1) ? .yellow : .black // Bottom face (-Y) ] return colors.map { createMaterial(color: $0) } } private func createMaterial(color: UIColor) -> SCNMaterial { let material = SCNMaterial() material.diffuse.contents = color.withAlphaComponent(1.0) material.specular.contents = UIColor.white material.shininess = 100 material.lightingModel = .phong return material } private func configureLights() { // Ambient light for base illumination let ambientLight = SCNLight() ambientLight.type = .ambient ambientLight.intensity = 500 let ambientLightNode = SCNNode() ambientLightNode.light = ambientLight rootNode.addChildNode(ambientLightNode) // Array of positions and directions for the 6 lights let positions: [(SCNVector3, SCNVector3)] = [ (SCNVector3(0, 10, 0), SCNVector3(0, -1, 0)), // Top (SCNVector3(0, -10, 0), SCNVector3(0, 1, 0)), // Bottom (SCNVector3(10, 0, 0), SCNVector3(-1, 0, 0)), // Right (SCNVector3(-10, 0, 0), SCNVector3(1, 0, 0)), // Left (SCNVector3(0, 0, 10), SCNVector3(0, 0, -1)), // Front (SCNVector3(0, 0, -10), SCNVector3(0, 0, 1)) // Back ] for (position, direction) in positions { let light = SCNLight() light.type = .directional light.intensity = 1000 light.color = UIColor.white let lightNode = SCNNode() lightNode.light = light lightNode.position = position lightNode.eulerAngles = SCNVector3( atan2(direction.y, direction.z), atan2(direction.x, direction.z), 0) rootNode.addChildNode(lightNode) } } func rotateLayer(cubelets: [SCNNode], axis: SCNVector3, angle: CGFloat) { let tempNode = SCNNode() var originalMaterials: [SCNNode: [SCNMaterial]] = [:] var originalPositions: [SCNNode: SCNVector3] = [:] var originalEulerAngles: [SCNNode: SCNVector3] = [:] for cubelet in cubelets { if let geometry = cubelet.geometry as? SCNBox { originalMaterials[cubelet] = geometry.materials } originalPositions[cubelet] = cubelet.position originalEulerAngles[cubelet] = cubelet.eulerAngles cubelet.removeFromParentNode() tempNode.addChildNode(cubelet) } rootNode.addChildNode(tempNode) let rotationAction = SCNAction.rotate(by: angle, around: axis, duration: 0.2) tempNode.runAction(rotationAction) { for cubelet in cubelets { let worldPosition = cubelet.worldPosition tempNode.removeFromParentNode() let localPosition = self.rootNode.convertPosition(worldPosition, from: nil) cubelet.position = localPosition if eje.x != 0 { cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x + Float(angle), cubelet.eulerAngles.y, cubelet.eulerAngles.z) } else if eje.y != 0 { cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x, cubelet.eulerAngles.y + Float(angle), cubelet.eulerAngles.z) } else if eje.z != 0 { cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x, cubelet.eulerAngles.y, cubelet.eulerAngles.z + Float(angle)) } if let geometry = cubelet.geometry as? SCNBox { geometry.materials = originalMaterials[cubelet] ?? geometry.materials } self.rootNode.addChildNode(cubelet) } tempNode.removeFromParentNode() } } func rotateTopLayer() { let axis = SCNVector3(x: 0, y: 1, z: 0) let angle: CGFloat = .pi / 2 let topCubelets = rootNode.childNodes.filter { node in abs(node.position.y - 0.78) < 0.01 } rotateLayer(cubelets: topCubelets, axis: axis, angle: angle) } func rotateBottomLayer() { let axis = SCNVector3(x: 0, y: 1, z: 0) let angle: CGFloat = -.pi / 2 let bottomCubelets = rootNode.childNodes.filter { node in abs(node.position.y + 0.78) < 0.01 } rotateLayer(cubelets: bottomCubelets, axis: axis, angle: angle) } func rotateRightLayer() { let axis = SCNVector3(x: 1, y: 0, z: 0) let angle: CGFloat = .pi / 2 let rightCubelets = rootNode.childNodes.filter { node in abs(node.position.x - 0.78) < 0.02 } rotateLayer(cubelets: rightCubelets, axis: axis, angle: angle) } func rotateLeftLayer() { let axis = SCNVector3(x: 1, y: 0, z: 0) let angle: CGFloat = -.pi / 2 let leftCubelets = rootNode.childNodes.filter { node in abs(node.position.x + 0.78) < 0.02 } rotateLayer(cubelets: leftCubelets, axis: axis, angle: angle) } func rotateFrontLayer() { let axis = SCNVector3(x: 0, y: 0, z: 1) let angle: CGFloat = .pi / 2 let frontCubelets = rootNode.childNodes.filter { node in abs(node.position.z - 0.78) < 0.01 } rotateLayer(cubelets: frontCubelets, axis: axis, angle: angle) } func rotateBackLayer() { let axis = SCNVector3(x: 0, y: 0, z: 1) let angle: CGFloat = -.pi / 2 let backCubelets = rootNode.childNodes.filter { node in abs(node.position.z + 0.78) < 0.01 } rotateLayer(cubelets: backCubelets, axis: axis, angle: angle) } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } < /code> changekitview: < /p> import SwiftUI import SceneKit struct SceneKitView: UIViewRepresentable { @ObservedObject var cubeScene: CuboScene func makeUIView(context: Context) -> SCNView { let view = SCNView() view.scene = cubeScene view.allowsCameraControl = true view.autoenablesDefaultLighting = true view.backgroundColor = .gray // Configure an initial camera let cameraNode = SCNNode() cameraNode.camera = SCNCamera() cameraNode.position = SCNVector3(x: 5, y: 5, z: 5) // Diagonal position to see all faces cameraNode.look(at: SCNVector3(0, 0, 0)) // Point to the cube's center view.pointOfView = cameraNode return view } func updateUIView(_ uiView: SCNView, context: Context) { uiView.scene = cubeScene } } #Preview { SceneKitView(cubeScene: CuboScene()) // Or RubikCubeScene if preferred } < /code> contenview: < /p> import SwiftUI struct ContentView: View { @StateObject private var cubeScene = CuboScene() // Or use RubikCubeScene if preferred var body: some View { VStack { SceneKitView(cubeScene: cubeScene) .frame(height: 400) .ignoresSafeArea() } Button("Rotate Top Layer") { cubeScene.rotateTopLayer() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) Button("Rotate Right Layer") { cubeScene.rotateRightLayer() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) Button("Rotate Left Layer") { cubeScene.rotateLeftLayer() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) Button("Rotate Bottom Layer") { cubeScene.rotateBottomLayer() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) Button("Rotate Front Layer") { cubeScene.rotateFrontLayer() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) Button("Rotate Back Layer") { cubeScene.rotateBackLayer() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) } } #Preview { ContentView() } [/code] Вот видео о проблеме: https://www.youtube.com/shorts/7q8xcdjdoce Подробнее здесь: [url]https://stackoverflow.com/questions/79468258/colors-turn-black-after-combining-multiple-layer-rotations-in-scenekit-rubik-s-c[/url]