SceneKit 问题将纹理应用于自定义几何体
SceneKit issues applying texture to custom geometry
我在将纹理应用于自定义几何体时遇到问题,这就是现在的结果
但我希望每张脸都有不同的纹理,而我的纹理是
This is the code that I've used to generate the cube,我尝试了很多方法,但对我没有任何作用,我知道我正在做的事情有问题,但我不明白。
此致
单个顶点不能有多个纹理坐标。由于立方体中的每个顶点都出现在一个角上并且是三个不同面的一部分,因此您需要重复顶点数据三次并将其与纹理坐标匹配,然后将它们与索引一起引用。
另一种看待它的方式是,您用来引用顶点的同一索引也用于引用纹理坐标,因此由于您只有 8 个顶点,因此您只能引用前 8 个纹理坐标。
在我关于 SceneKit 的书中的一章中 I create a custom cube geometry。它的纹理坐标显示每个面上的完整纹理——因此您必须更改该部分——但它的索引也应该适用于您的立方体:
// Indices that turn the source data into triangles
// ------------------------------------------------
int indices[] = {
// bottom
0, 2, 1,
1, 2, 3,
// back
10, 14, 11, // 2, 6, 3, + 8
11, 14, 15, // 3, 6, 7, + 8
// left
16, 20, 18, // 0, 4, 2, + 16
18, 20, 22, // 2, 4, 6, + 16
// right
17, 19, 21, // 1, 3, 5, + 16
19, 23, 21, // 3, 7, 5, + 16
// front
8, 9, 12, // 0, 1, 4, + 8
9, 13, 12, // 1, 5, 4, + 8
// top
4, 5, 6,
5, 7, 6
};
// Custom geometry data for a cube
// -------------------------------
SCNVector3 vertices[] = {
SCNVector3Make(-halfSide, -halfSide, halfSide),
SCNVector3Make( halfSide, -halfSide, halfSide),
SCNVector3Make(-halfSide, -halfSide, -halfSide),
SCNVector3Make( halfSide, -halfSide, -halfSide),
SCNVector3Make(-halfSide, halfSide, halfSide),
SCNVector3Make( halfSide, halfSide, halfSide),
SCNVector3Make(-halfSide, halfSide, -halfSide),
SCNVector3Make( halfSide, halfSide, -halfSide),
// repeat exactly the same
SCNVector3Make(-halfSide, -halfSide, halfSide),
SCNVector3Make( halfSide, -halfSide, halfSide),
SCNVector3Make(-halfSide, -halfSide, -halfSide),
SCNVector3Make( halfSide, -halfSide, -halfSide),
SCNVector3Make(-halfSide, halfSide, halfSide),
SCNVector3Make( halfSide, halfSide, halfSide),
SCNVector3Make(-halfSide, halfSide, -halfSide),
SCNVector3Make( halfSide, halfSide, -halfSide),
// repeat exactly the same
SCNVector3Make(-halfSide, -halfSide, halfSide),
SCNVector3Make( halfSide, -halfSide, halfSide),
SCNVector3Make(-halfSide, -halfSide, -halfSide),
SCNVector3Make( halfSide, -halfSide, -halfSide),
SCNVector3Make(-halfSide, halfSide, halfSide),
SCNVector3Make( halfSide, halfSide, halfSide),
SCNVector3Make(-halfSide, halfSide, -halfSide),
SCNVector3Make( halfSide, halfSide, -halfSide)
};
SCNVector3 normals[] = {
// up and down
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, 1, 0),
SCNVector3Make( 0, 1, 0),
SCNVector3Make( 0, 1, 0),
SCNVector3Make( 0, 1, 0),
// back and front
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, -1),
SCNVector3Make( 0, 0, -1),
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, -1),
SCNVector3Make( 0, 0, -1),
// left and right
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
};
CGPoint UVs[] = {
CGPointMake(0, 0), // bottom
CGPointMake(1, 0), // bottom
CGPointMake(0, 1), // bottom
CGPointMake(1, 1), // bottom
CGPointMake(0, 1), // top
CGPointMake(1, 1), // top
CGPointMake(0, 0), // top
CGPointMake(1, 0), // top
CGPointMake(0, 1), // front
CGPointMake(1, 1), // front
CGPointMake(1, 1), // back
CGPointMake(0, 1), // back
CGPointMake(0, 0), // front
CGPointMake(1, 0), // front
CGPointMake(1, 0), // back
CGPointMake(0, 0), // back
CGPointMake(1, 1), // left
CGPointMake(0, 1), // right
CGPointMake(0, 1), // left
CGPointMake(1, 1), // right
CGPointMake(1, 0), // left
CGPointMake(0, 0), // right
CGPointMake(0, 0), // left
CGPointMake(1, 0), // right
};
虽然这是一种不同的方法,但我制作了一个 Box Class 可以正确渲染每一面:
class Box: SCNNode {
private var faceArray = [SCNMaterial]()
/// Creates An SCNBox With Either A Colour Or UIImage For Each Of It's Faces
/// (Either An Array [Colour] Or [UIImage] Must Be Input)
/// - Parameters:
/// - width: Optional CGFloat (Defaults To 20cm)
/// - height: Optional CGFloat (Defaults To 20cm)
/// - length: Optional CGFloat (Defaults To 20cm)
/// - colours: Optional [UIColor] - [Front, Right, Back, Left, Top, Bottom]
/// - images: Optional [UIImage] - [Front, Right, Back, Left, Top, Bottom]
init(width: CGFloat = 0.2, height: CGFloat = 0.2, length: CGFloat = 0.2, colours: [UIColor]?, images: [UIImage]?) {
super.init()
self.geometry = SCNBox(width: width, height: height, length: length, chamferRadius: 0)
var sideArray = [Any]()
if colours == nil{
guard let imageArray = images else { return }
sideArray = imageArray
}else{
guard let coloursArray = colours else { return }
sideArray = coloursArray
}
for index in 0 ..< 6{
let face = SCNMaterial()
face.diffuse.contents = sideArray[index]
faceArray.append(face)
}
self.geometry?.materials = faceArray
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
你可以像这样初始化它,通过旋转可以看到每个面都正确渲染:
let cube = Box(colours: [.red, .green, .cyan, .yellow, .blue, .black], images: nil)
scene.rootNode.addChildNode(cube)
let rotateAction = SCNAction.rotate(by: .pi * 2, around: SCNVector3(1, 0, 0), duration: 10)
cube.runAction(rotateAction)
我在将纹理应用于自定义几何体时遇到问题,这就是现在的结果
但我希望每张脸都有不同的纹理,而我的纹理是
This is the code that I've used to generate the cube,我尝试了很多方法,但对我没有任何作用,我知道我正在做的事情有问题,但我不明白。
此致
单个顶点不能有多个纹理坐标。由于立方体中的每个顶点都出现在一个角上并且是三个不同面的一部分,因此您需要重复顶点数据三次并将其与纹理坐标匹配,然后将它们与索引一起引用。
另一种看待它的方式是,您用来引用顶点的同一索引也用于引用纹理坐标,因此由于您只有 8 个顶点,因此您只能引用前 8 个纹理坐标。
在我关于 SceneKit 的书中的一章中 I create a custom cube geometry。它的纹理坐标显示每个面上的完整纹理——因此您必须更改该部分——但它的索引也应该适用于您的立方体:
// Indices that turn the source data into triangles
// ------------------------------------------------
int indices[] = {
// bottom
0, 2, 1,
1, 2, 3,
// back
10, 14, 11, // 2, 6, 3, + 8
11, 14, 15, // 3, 6, 7, + 8
// left
16, 20, 18, // 0, 4, 2, + 16
18, 20, 22, // 2, 4, 6, + 16
// right
17, 19, 21, // 1, 3, 5, + 16
19, 23, 21, // 3, 7, 5, + 16
// front
8, 9, 12, // 0, 1, 4, + 8
9, 13, 12, // 1, 5, 4, + 8
// top
4, 5, 6,
5, 7, 6
};
// Custom geometry data for a cube
// -------------------------------
SCNVector3 vertices[] = {
SCNVector3Make(-halfSide, -halfSide, halfSide),
SCNVector3Make( halfSide, -halfSide, halfSide),
SCNVector3Make(-halfSide, -halfSide, -halfSide),
SCNVector3Make( halfSide, -halfSide, -halfSide),
SCNVector3Make(-halfSide, halfSide, halfSide),
SCNVector3Make( halfSide, halfSide, halfSide),
SCNVector3Make(-halfSide, halfSide, -halfSide),
SCNVector3Make( halfSide, halfSide, -halfSide),
// repeat exactly the same
SCNVector3Make(-halfSide, -halfSide, halfSide),
SCNVector3Make( halfSide, -halfSide, halfSide),
SCNVector3Make(-halfSide, -halfSide, -halfSide),
SCNVector3Make( halfSide, -halfSide, -halfSide),
SCNVector3Make(-halfSide, halfSide, halfSide),
SCNVector3Make( halfSide, halfSide, halfSide),
SCNVector3Make(-halfSide, halfSide, -halfSide),
SCNVector3Make( halfSide, halfSide, -halfSide),
// repeat exactly the same
SCNVector3Make(-halfSide, -halfSide, halfSide),
SCNVector3Make( halfSide, -halfSide, halfSide),
SCNVector3Make(-halfSide, -halfSide, -halfSide),
SCNVector3Make( halfSide, -halfSide, -halfSide),
SCNVector3Make(-halfSide, halfSide, halfSide),
SCNVector3Make( halfSide, halfSide, halfSide),
SCNVector3Make(-halfSide, halfSide, -halfSide),
SCNVector3Make( halfSide, halfSide, -halfSide)
};
SCNVector3 normals[] = {
// up and down
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, -1, 0),
SCNVector3Make( 0, 1, 0),
SCNVector3Make( 0, 1, 0),
SCNVector3Make( 0, 1, 0),
SCNVector3Make( 0, 1, 0),
// back and front
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, -1),
SCNVector3Make( 0, 0, -1),
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, 1),
SCNVector3Make( 0, 0, -1),
SCNVector3Make( 0, 0, -1),
// left and right
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
SCNVector3Make(-1, 0, 0),
SCNVector3Make( 1, 0, 0),
};
CGPoint UVs[] = {
CGPointMake(0, 0), // bottom
CGPointMake(1, 0), // bottom
CGPointMake(0, 1), // bottom
CGPointMake(1, 1), // bottom
CGPointMake(0, 1), // top
CGPointMake(1, 1), // top
CGPointMake(0, 0), // top
CGPointMake(1, 0), // top
CGPointMake(0, 1), // front
CGPointMake(1, 1), // front
CGPointMake(1, 1), // back
CGPointMake(0, 1), // back
CGPointMake(0, 0), // front
CGPointMake(1, 0), // front
CGPointMake(1, 0), // back
CGPointMake(0, 0), // back
CGPointMake(1, 1), // left
CGPointMake(0, 1), // right
CGPointMake(0, 1), // left
CGPointMake(1, 1), // right
CGPointMake(1, 0), // left
CGPointMake(0, 0), // right
CGPointMake(0, 0), // left
CGPointMake(1, 0), // right
};
虽然这是一种不同的方法,但我制作了一个 Box Class 可以正确渲染每一面:
class Box: SCNNode {
private var faceArray = [SCNMaterial]()
/// Creates An SCNBox With Either A Colour Or UIImage For Each Of It's Faces
/// (Either An Array [Colour] Or [UIImage] Must Be Input)
/// - Parameters:
/// - width: Optional CGFloat (Defaults To 20cm)
/// - height: Optional CGFloat (Defaults To 20cm)
/// - length: Optional CGFloat (Defaults To 20cm)
/// - colours: Optional [UIColor] - [Front, Right, Back, Left, Top, Bottom]
/// - images: Optional [UIImage] - [Front, Right, Back, Left, Top, Bottom]
init(width: CGFloat = 0.2, height: CGFloat = 0.2, length: CGFloat = 0.2, colours: [UIColor]?, images: [UIImage]?) {
super.init()
self.geometry = SCNBox(width: width, height: height, length: length, chamferRadius: 0)
var sideArray = [Any]()
if colours == nil{
guard let imageArray = images else { return }
sideArray = imageArray
}else{
guard let coloursArray = colours else { return }
sideArray = coloursArray
}
for index in 0 ..< 6{
let face = SCNMaterial()
face.diffuse.contents = sideArray[index]
faceArray.append(face)
}
self.geometry?.materials = faceArray
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
你可以像这样初始化它,通过旋转可以看到每个面都正确渲染:
let cube = Box(colours: [.red, .green, .cyan, .yellow, .blue, .black], images: nil)
scene.rootNode.addChildNode(cube)
let rotateAction = SCNAction.rotate(by: .pi * 2, around: SCNVector3(1, 0, 0), duration: 10)
cube.runAction(rotateAction)