admin管理员组文章数量:1277910
I am developing a 3D Rubik's Cube using SceneKit in Swift, and I’m encountering an issue where the colors of the cube’s faces are not rendering as solid 3x3 faces as expected. Instead of each face of the 3x3x3 cube (e.g., the front face in green, the left face in orange, etc.) being uniformly colored across all 9 cublets, the colors appear fragmented or misplaced, often showing up in rows or columns rather than covering the entire face. For example, I see the green color (intended for the front face, +Z) correctly on the top row, but it shifts to the bottom row or adjacent faces instead of forming a solid green 3x3 face.
Here’s an overview of my setup and the issue:
Objective: I want each face of the Rubik’s Cube (front, back, left, right, top, bottom) to be a solid color for the 9 cublets that make up that face (e.g., all cublets with z = 1 should have their front face painted green).
Current Behavior: Colors are applied partially or in fragmented patterns (e.g., a row of green at the top, then a row of green below, but not a solid 3x3 green face). This happens for all faces (red for +X, orange for -X, white for +Y, yellow for -Y, green for +Z, blue for -Z).
Suspected Issue: I suspect the cublets (SCNBox) might be rotated, causing the materials to apply to the wrong faces or in the wrong orientation, but I’ve been unable to confirm or fix this.
Here is my code:
CubeScene:
import SwiftUI
import SceneKit
class CuboScene: SCNScene {
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
// let light = SCNLight()
// light.type = .omni
// light.intensity = 2000
// let lightNode = SCNNode()
// lightNode.light = light
// lightNode.position = SCNVector3(x: 5, y: 5, z: 5)
// rootNode.addChildNode(lightNode)
configureLights()
createRubikCube()
}
private func createRubikCube() {
let size: CGFloat = 0.8
let spacing: CGFloat = 1.05
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.0) // No rounded edges
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) // Ensure no rotation
print("Cubelet at position: (\(Float(x) * Float(spacing)), \(Float(y) * Float(spacing)), \(Float(z) * Float(spacing)) with materials: \(getFaceMaterial(x: x, y: y, z: z).map { $0.diffuse.contents as? UIColor ?? .gray }) and eulerAngles: \(cubeletNode.eulerAngles), rotation: \(cubeletNode.rotation)")
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] = [
// Right face (+X): red if x = 1, gray for x = 0 or -1
(x == 1) ? .red : .gray,
// Left face (-X): orange if x = -1, gray for x = 0 or 1
(x == -1) ? .orange : .gray,
// Top face (+Y): white if y = 1, gray for y = 0 or -1
(y == 1) ? .white : .gray,
// Bottom face (-Y): yellow if y = -1, gray for y = 0 or 1
(y == -1) ? .yellow : .gray,
// Front face (+Z): green if z = 1, gray for z = 0 or -1
(z == 1) ? .green : .gray,
// Back face (-Z): blue if z = -1, gray for z = 0 or 1
(z == -1) ? .blue : .gray
]
// print("Position (\(x), \(y), \(z)): Colors = \(colors)") // Debugging
return colors.map { createMaterial(color: $0) }
}
private func createMaterial(color: UIColor) -> SCNMaterial {
let material = SCNMaterial()
print("Applying material with color: \(color)")
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
) // Orient toward the center
rootNode.addChildNode(lightNode)
}
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
SceneKitView:
import SwiftUI
import SceneKit
struct SceneKitView: UIViewRepresentable {
func makeUIView(context: Context) -> SCNView {
let view = SCNView()
view.scene = CuboScene() // Use the created scene
view.allowsCameraControl = true // Allow camera movement with touch
view.autoenablesDefaultLighting = false // Disable default lighting
view.backgroundColor = .clear
// 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 cubes center
view.pointOfView = cameraNode
return view
}
func updateUIView(_ uiView: SCNView, context: Context) {}
}
#Preview {
SceneKitView()
}
Here is how the Rubik's cube colors are generating:
I've tried a lot of different things, but I cannot make it right.
I am developing a 3D Rubik's Cube using SceneKit in Swift, and I’m encountering an issue where the colors of the cube’s faces are not rendering as solid 3x3 faces as expected. Instead of each face of the 3x3x3 cube (e.g., the front face in green, the left face in orange, etc.) being uniformly colored across all 9 cublets, the colors appear fragmented or misplaced, often showing up in rows or columns rather than covering the entire face. For example, I see the green color (intended for the front face, +Z) correctly on the top row, but it shifts to the bottom row or adjacent faces instead of forming a solid green 3x3 face.
Here’s an overview of my setup and the issue:
Objective: I want each face of the Rubik’s Cube (front, back, left, right, top, bottom) to be a solid color for the 9 cublets that make up that face (e.g., all cublets with z = 1 should have their front face painted green).
Current Behavior: Colors are applied partially or in fragmented patterns (e.g., a row of green at the top, then a row of green below, but not a solid 3x3 green face). This happens for all faces (red for +X, orange for -X, white for +Y, yellow for -Y, green for +Z, blue for -Z).
Suspected Issue: I suspect the cublets (SCNBox) might be rotated, causing the materials to apply to the wrong faces or in the wrong orientation, but I’ve been unable to confirm or fix this.
Here is my code:
CubeScene:
import SwiftUI
import SceneKit
class CuboScene: SCNScene {
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
// let light = SCNLight()
// light.type = .omni
// light.intensity = 2000
// let lightNode = SCNNode()
// lightNode.light = light
// lightNode.position = SCNVector3(x: 5, y: 5, z: 5)
// rootNode.addChildNode(lightNode)
configureLights()
createRubikCube()
}
private func createRubikCube() {
let size: CGFloat = 0.8
let spacing: CGFloat = 1.05
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.0) // No rounded edges
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) // Ensure no rotation
print("Cubelet at position: (\(Float(x) * Float(spacing)), \(Float(y) * Float(spacing)), \(Float(z) * Float(spacing)) with materials: \(getFaceMaterial(x: x, y: y, z: z).map { $0.diffuse.contents as? UIColor ?? .gray }) and eulerAngles: \(cubeletNode.eulerAngles), rotation: \(cubeletNode.rotation)")
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] = [
// Right face (+X): red if x = 1, gray for x = 0 or -1
(x == 1) ? .red : .gray,
// Left face (-X): orange if x = -1, gray for x = 0 or 1
(x == -1) ? .orange : .gray,
// Top face (+Y): white if y = 1, gray for y = 0 or -1
(y == 1) ? .white : .gray,
// Bottom face (-Y): yellow if y = -1, gray for y = 0 or 1
(y == -1) ? .yellow : .gray,
// Front face (+Z): green if z = 1, gray for z = 0 or -1
(z == 1) ? .green : .gray,
// Back face (-Z): blue if z = -1, gray for z = 0 or 1
(z == -1) ? .blue : .gray
]
// print("Position (\(x), \(y), \(z)): Colors = \(colors)") // Debugging
return colors.map { createMaterial(color: $0) }
}
private func createMaterial(color: UIColor) -> SCNMaterial {
let material = SCNMaterial()
print("Applying material with color: \(color)")
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
) // Orient toward the center
rootNode.addChildNode(lightNode)
}
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
SceneKitView:
import SwiftUI
import SceneKit
struct SceneKitView: UIViewRepresentable {
func makeUIView(context: Context) -> SCNView {
let view = SCNView()
view.scene = CuboScene() // Use the created scene
view.allowsCameraControl = true // Allow camera movement with touch
view.autoenablesDefaultLighting = false // Disable default lighting
view.backgroundColor = .clear
// 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 cubes center
view.pointOfView = cameraNode
return view
}
func updateUIView(_ uiView: SCNView, context: Context) {}
}
#Preview {
SceneKitView()
}
Here is how the Rubik's cube colors are generating:
I've tried a lot of different things, but I cannot make it right.
Share Improve this question edited Feb 25 at 2:46 HangarRash 15.1k5 gold badges19 silver badges55 bronze badges asked Feb 25 at 2:25 mafa-mafa- 152 bronze badges1 Answer
Reset to default 0You've got the materials in the wrong order. It goes Front, Right, Back, Left, Top, Bottom. Update your materials array like this
let colors: [UIColor] = [
// Front face (+Z): green if z = 1, gray for z = 0 or -1
(z == 1) ? .green : .gray,
// Right face (+X): red if x = 1, gray for x = 0 or -1
(x == 1) ? .red : .gray,
// Back face (-Z): blue if z = -1, gray for z = 0 or 1
(z == -1) ? .blue : .gray,
// Left face (-X): orange if x = -1, gray for x = 0 or 1
(x == -1) ? .orange : .gray,
// Top face (+Y): white if y = 1, gray for y = 0 or -1
(y == 1) ? .white : .gray,
// Bottom face (-Y): yellow if y = -1, gray for y = 0 or 1
(y == -1) ? .yellow : .gray
]
本文标签: iosI need help putting the colors correctly in my Rubik39s cube testStack Overflow
版权声明:本文标题:ios - I need help putting the colors correctly in my Rubik's cube test - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741231628a2362213.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论