SceneKit - 将立方体纹理映射到盒子
SceneKit - Map cube texture to box
我有一个看起来像
的立方体纹理
我想在 SceneKit 视图中的立方体上使用它。为此,我正在使用 SceneKit 几何体 SCNBox
。不幸的是,结果是纹理完全投射到每个面上,而不是只使用相应的部分:
let videoGeometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
videoGeometry.firstMaterial?.isDoubleSided = true
videoGeometry.firstMaterial?.diffuse.contents = UIImage(named: "test")!
我知道我可以在几何体上使用着色器修改器,但我不确定从哪里开始。由于纹理目前使用了六次,我的直觉是 SCNBox
几何体可能不适合我的目标,但我真的不知道如何更改它。
您可以让它与自定义几何体一起工作:创建一个立方体(http://ronnqvi.st/custom-scenekit-geometry/ 是一个很好的起点)并且您可以在顶部添加一些自定义纹理映射。获得正确的索引有点棘手(对我来说),但最后它工作得很好:
func getSimpleCubeGeo() -> SCNGeometry {
let halfSide = Float(0.5)
/* The cube vertex are like:
5---------4
/. /|
/ . / |
7---------6 |
| . | |
| . | |
| 1......|..0
| . | /
|. |/
3---------2
*/
let _positions = [
SCNVector3(x:-halfSide, y:-halfSide, z: halfSide),
SCNVector3(x: halfSide, y:-halfSide, z: halfSide),
SCNVector3(x:-halfSide, y:-halfSide, z: -halfSide),
SCNVector3(x: halfSide, y:-halfSide, z: -halfSide),
SCNVector3(x:-halfSide, y: halfSide, z: halfSide),
SCNVector3(x: halfSide, y: halfSide, z: halfSide),
SCNVector3(x:-halfSide, y: halfSide, z: -halfSide),
SCNVector3(x: halfSide, y: halfSide, z: -halfSide),
]
// points are tripled since they are each used on 3 faces
// and there's no continuity in the UV mapping
// so we need to duplicate the points
//
// we'll use the first third for the faces orthogonal to the X (left) axis,
// the second for the Y (top) axis and the third for the Z (front) axis
let positions = _positions + _positions + _positions
let X = 0
let Y = 8
let Z = 16
let indices = [
// bottom
0 + Y, 2 + Y, 1 + Y,
1 + Y, 2 + Y, 3 + Y,
// back
2 + Z, 6 + Z, 3 + Z,
3 + Z, 6 + Z, 7 + Z,
// left
0 + X, 4 + X, 2 + X,
2 + X, 4 + X, 6 + X,
// right
1 + X, 3 + X, 5 + X,
3 + X, 7 + X, 5 + X,
// front
0 + Z, 1 + Z, 4 + Z,
1 + Z, 5 + Z, 4 + Z,
// top
4 + Y, 5 + Y, 6 + Y,
5 + Y, 7 + Y, 6 + Y,
]
// get the points in the texture where the faces are split
var textureSplitPoints = [CGPoint]()
for i in 0...12 {
let x = Double(i % 4)
let y = Double(i / 4)
textureSplitPoints.append(CGPoint(x: x / 3.0, y: y / 2.0))
}
let textCoords = [
textureSplitPoints[4],
textureSplitPoints[6],
textureSplitPoints[5],
textureSplitPoints[5],
textureSplitPoints[8],
textureSplitPoints[10],
textureSplitPoints[9],
textureSplitPoints[9],
textureSplitPoints[5],
textureSplitPoints[4],
textureSplitPoints[1],
textureSplitPoints[0],
textureSplitPoints[7],
textureSplitPoints[6],
textureSplitPoints[11],
textureSplitPoints[10],
textureSplitPoints[2],
textureSplitPoints[1],
textureSplitPoints[2],
textureSplitPoints[3],
textureSplitPoints[6],
textureSplitPoints[5],
textureSplitPoints[6],
textureSplitPoints[7],
]
let vertexSource = SCNGeometrySource(vertices: positions)
let textSource = SCNGeometrySource(textureCoordinates: textCoords)
let indexData = NSData(bytes: indices, length: sizeof(Int) * indices.count)
let elements = SCNGeometryElement(
data: indexData as Data,
primitiveType: SCNGeometryPrimitiveType.triangles,
primitiveCount: indices.count / 3,
bytesPerIndex: sizeof(Int)
)
return SCNGeometry(sources: [vertexSource, textSource], elements: [elements])
}
我有一个看起来像
的立方体纹理我想在 SceneKit 视图中的立方体上使用它。为此,我正在使用 SceneKit 几何体 SCNBox
。不幸的是,结果是纹理完全投射到每个面上,而不是只使用相应的部分:
let videoGeometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
videoGeometry.firstMaterial?.isDoubleSided = true
videoGeometry.firstMaterial?.diffuse.contents = UIImage(named: "test")!
我知道我可以在几何体上使用着色器修改器,但我不确定从哪里开始。由于纹理目前使用了六次,我的直觉是 SCNBox
几何体可能不适合我的目标,但我真的不知道如何更改它。
您可以让它与自定义几何体一起工作:创建一个立方体(http://ronnqvi.st/custom-scenekit-geometry/ 是一个很好的起点)并且您可以在顶部添加一些自定义纹理映射。获得正确的索引有点棘手(对我来说),但最后它工作得很好:
func getSimpleCubeGeo() -> SCNGeometry {
let halfSide = Float(0.5)
/* The cube vertex are like:
5---------4
/. /|
/ . / |
7---------6 |
| . | |
| . | |
| 1......|..0
| . | /
|. |/
3---------2
*/
let _positions = [
SCNVector3(x:-halfSide, y:-halfSide, z: halfSide),
SCNVector3(x: halfSide, y:-halfSide, z: halfSide),
SCNVector3(x:-halfSide, y:-halfSide, z: -halfSide),
SCNVector3(x: halfSide, y:-halfSide, z: -halfSide),
SCNVector3(x:-halfSide, y: halfSide, z: halfSide),
SCNVector3(x: halfSide, y: halfSide, z: halfSide),
SCNVector3(x:-halfSide, y: halfSide, z: -halfSide),
SCNVector3(x: halfSide, y: halfSide, z: -halfSide),
]
// points are tripled since they are each used on 3 faces
// and there's no continuity in the UV mapping
// so we need to duplicate the points
//
// we'll use the first third for the faces orthogonal to the X (left) axis,
// the second for the Y (top) axis and the third for the Z (front) axis
let positions = _positions + _positions + _positions
let X = 0
let Y = 8
let Z = 16
let indices = [
// bottom
0 + Y, 2 + Y, 1 + Y,
1 + Y, 2 + Y, 3 + Y,
// back
2 + Z, 6 + Z, 3 + Z,
3 + Z, 6 + Z, 7 + Z,
// left
0 + X, 4 + X, 2 + X,
2 + X, 4 + X, 6 + X,
// right
1 + X, 3 + X, 5 + X,
3 + X, 7 + X, 5 + X,
// front
0 + Z, 1 + Z, 4 + Z,
1 + Z, 5 + Z, 4 + Z,
// top
4 + Y, 5 + Y, 6 + Y,
5 + Y, 7 + Y, 6 + Y,
]
// get the points in the texture where the faces are split
var textureSplitPoints = [CGPoint]()
for i in 0...12 {
let x = Double(i % 4)
let y = Double(i / 4)
textureSplitPoints.append(CGPoint(x: x / 3.0, y: y / 2.0))
}
let textCoords = [
textureSplitPoints[4],
textureSplitPoints[6],
textureSplitPoints[5],
textureSplitPoints[5],
textureSplitPoints[8],
textureSplitPoints[10],
textureSplitPoints[9],
textureSplitPoints[9],
textureSplitPoints[5],
textureSplitPoints[4],
textureSplitPoints[1],
textureSplitPoints[0],
textureSplitPoints[7],
textureSplitPoints[6],
textureSplitPoints[11],
textureSplitPoints[10],
textureSplitPoints[2],
textureSplitPoints[1],
textureSplitPoints[2],
textureSplitPoints[3],
textureSplitPoints[6],
textureSplitPoints[5],
textureSplitPoints[6],
textureSplitPoints[7],
]
let vertexSource = SCNGeometrySource(vertices: positions)
let textSource = SCNGeometrySource(textureCoordinates: textCoords)
let indexData = NSData(bytes: indices, length: sizeof(Int) * indices.count)
let elements = SCNGeometryElement(
data: indexData as Data,
primitiveType: SCNGeometryPrimitiveType.triangles,
primitiveCount: indices.count / 3,
bytesPerIndex: sizeof(Int)
)
return SCNGeometry(sources: [vertexSource, textSource], elements: [elements])
}