You need to enable JavaScript to run this app. SceneKit自定义几何体纹理拉伸 ARKit自定义多边形铺砖问题求助
优惠活动
大模型
产品
解决方案
定价
更多

SceneKit自定义几何体纹理拉伸 ARKit自定义多边形铺砖问题求助

你的代码核心问题有三处:

  1. 纹理坐标数量和顶点数量不匹配
    你写死了textureCoordinates只有4组值,但顶点是用户任意选取的,数量不固定,SceneKit无法将UV坐标和顶点一一对应,只会自动插值复用,必然导致纹理拉伸。
  2. 纹理坐标是固定归一化值,和实际多边形的物理尺寸无关
    你用了0到1范围的固定UV,不管你画的多边形是1平米还是100平米,都会把单张纹理强行拉伸铺满整个面,就算开了重复模式、加了transform缩放也无法按物理尺寸均匀铺砖。
  3. 自定义几何体初始化错误,以及变换矩阵参数无效
    你用SCNPlane初始化自定义多边形几何体是错误的,SCNPlane是系统生成矩形平面的类,自定义任意形状几何体应该用SCNGeometry;另外你最初写的SCNMatrix4MakeScale第三个参数设为0,会直接抹除纹理的Z轴分量,也会导致采样异常。

修复方案

  1. 动态计算每个顶点的UV坐标:因为你是在水平面上生成多边形(ARKit水平面默认y轴为竖直方向),直接用顶点的x、z坐标计算UV即可,保证UV值和实际世界尺寸对应。
  2. 修正几何体初始化和变换矩阵的无效参数。

修改后完整可运行代码如下:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 08:54:04