You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SceneKit细分网格位移分辨率提升与顶点平滑方案求助

如何在SceneKit中平滑深度图生成的位移网格?

我正尝试用SceneKit从深度图生成3D网格,使用的深度图如下:
depth map

我创建了带分段的平面,通过细分和位移材质实现了基础的3D效果,代码如下:

import Cocoa
import SceneKit
import PlaygroundSupport

// MARK: - View setup

let scene = SCNScene()

let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.camera?.zFar = 1000
scene.rootNode.addChildNode(cameraNode)

cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)

let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = NSColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)

let scnView = SCNView(frame: NSRect(x: 0, y: 0, width: 400, height: 400))
scnView.autoenablesDefaultLighting = true
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.showsStatistics = true
scnView.backgroundColor = NSColor.black


PlaygroundPage.current.liveView = scnView

// MARK: - Plane

let plane = SCNPlane(width: 200, height: 200)
plane.widthSegmentCount = 10
plane.heightSegmentCount = 10

let planeNode = SCNNode(geometry: plane)
planeNode.name = "Plane"
planeNode.geometry?.firstMaterial?.diffuse.contents = NSColor.white

let tessellator = SCNGeometryTessellator()
tessellator.tessellationFactorScale = 25
tessellator.tessellationPartitionMode = .pow2
tessellator.insideTessellationFactor = 4
tessellator.edgeTessellationFactor = 4
tessellator.smoothingMode = .phong

planeNode.geometry?.tessellator = tessellator

planeNode.geometry?.firstMaterial?.displacement.contents = "rabbit"
planeNode.geometry?.firstMaterial?.displacement.textureComponents = .red
planeNode.geometry?.firstMaterial?.displacement.intensity = 200
planeNode.geometry?.firstMaterial?.displacement.maxAnisotropy = 1
planeNode.geometry?.firstMaterial?.displacement.magnificationFilter = .none

planeNode.geometry?.firstMaterial?.lightingModel = .phong

scene.rootNode.addChildNode(planeNode)

目前已经生成了目标中的3D网格:
tessellation + displacement

但网格存在明显的“块状感”,光照效果受影响,线框视图中问题更突出:
wireframe

我尝试过调整细分、自适应细分以及拉满细分参数,只能缩小阴影/高光斑块,但块状问题依然存在。请问有没有方法可以平滑生成的网格、平均顶点位置或实现类似效果?


解决方案

1. 优化位移纹理的滤波方式

当前设置的displacement.magnificationFilter = .none会导致纹理放大时出现硬边缘,换成线性滤波能让深度过渡更平滑:

planeNode.geometry?.firstMaterial?.displacement.magnificationFilter = .linear
planeNode.geometry?.firstMaterial?.displacement.minificationFilter = .linear

2. 优化细分曲面参数

调整细分分区模式和因子,让自适应细分更贴合深度变化,同时重新计算平滑法线:

// 改用更细腻的分区模式
tessellator.tessellationPartitionMode = .fractionalOdd
// 提高细分因子,增加顶点数量
tessellator.insideTessellationFactor = 8
tessellator.edgeTessellationFactor = 8
// 放大细分因子的影响,让深度变化大的区域生成更多顶点
tessellator.tessellationFactorScale = 50

// 重新计算平滑法线,优化光照表现
planeNode.geometry?.computeNormals()

3. 预平滑深度图

从根源解决区块问题,可以用图像处理工具(如Photoshop)给深度图添加轻微高斯模糊,让深度值的过渡更自然,再导入SceneKit使用。

4. 离线生成平滑网格(替代方案)

如果实时位移细分达不到预期,可先用Blender等工具将深度图转换为平滑网格,再导出为SceneKit支持的格式导入使用,离线处理能获得更细腻的平滑效果。


内容的提问来源于stack exchange,提问作者max

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:55:21