SceneKit自定义几何体纹理拉伸 ARKit自定义多边形铺砖问题求助
你的代码核心问题有三处:
- 纹理坐标数量和顶点数量不匹配
你写死了textureCoordinates只有4组值,但顶点是用户任意选取的,数量不固定,SceneKit无法将UV坐标和顶点一一对应,只会自动插值复用,必然导致纹理拉伸。 - 纹理坐标是固定归一化值,和实际多边形的物理尺寸无关
你用了0到1范围的固定UV,不管你画的多边形是1平米还是100平米,都会把单张纹理强行拉伸铺满整个面,就算开了重复模式、加了transform缩放也无法按物理尺寸均匀铺砖。 - 自定义几何体初始化错误,以及变换矩阵参数无效
你用SCNPlane初始化自定义多边形几何体是错误的,SCNPlane是系统生成矩形平面的类,自定义任意形状几何体应该用SCNGeometry;另外你最初写的SCNMatrix4MakeScale第三个参数设为0,会直接抹除纹理的Z轴分量,也会导致采样异常。
修复方案
- 动态计算每个顶点的UV坐标:因为你是在水平面上生成多边形(ARKit水平面默认y轴为竖直方向),直接用顶点的x、z坐标计算UV即可,保证UV值和实际世界尺寸对应。
- 修正几何体初始化和变换矩阵的无效参数。
修改后完整可运行代码如下:
let vertices: [SCNVector3] = ... // 用户选取的水平面点位 var indices: [Int32] = [Int32(vertices.count)] var index: Int32 = 0 // 计算所有顶点的x、z最小值,作为UV坐标的原点,避免出现负的UV值 let minX = vertices.map { $0.x }.min() ?? 0 let minZ = vertices.map { $0.z }.min() ?? 0 // 动态生成和顶点数量一一对应的UV坐标 var textureCoordinates = vertices.map { vertex in let u = CGFloat(vertex.x - minX) let v = CGFloat(vertex.z - minZ) return CGPoint(x: u, y: v) } for _ in vertices { indices.append(index) index += 1 } let vertexSource = SCNGeometrySource(vertices: vertices) let uvSource = SCNGeometrySource(textureCoordinates: textureCoordinates) let indexData = Data(bytes: indices, count: indices.count * MemoryLayout<Int32>.size) let element = SCNGeometryElement(data: indexData, primitiveType: .polygon, primitiveCount: 1, bytesPerIndex: MemoryLayout<Int32>.size) // 自定义几何体用SCNGeometry初始化,不要用SCNPlane let geometry = SCNGeometry(sources: [vertexSource, uvSource], elements: [element]) // 材质配置 let material = SCNMaterial() material.isDoubleSided = true material.diffuse.wrapS = .repeat material.diffuse.wrapT = .repeat material.diffuse.contents = UIImage(named: "tile")! // 调整缩放值控制砖的大小:值越大,同尺寸范围内砖的数量越多、单块砖越小 material.diffuse.contentsTransform = SCNMatrix4MakeScale(5, 5, 1) geometry.firstMaterial = material let planeNode = SCNNode(geometry: geometry) sceneView.scene.rootNode.addChildNode(planeNode)
如果要进一步调整砖的排列偏移,可以修改contentsTransform的平移参数即可。
内容的提问来源于stack exchange,提问作者Hossein
相关产品推荐
相关产品推荐

