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

Swift中SceneKit视频纹理对象的布局坐标设置及节点实现问询

解决SceneKit中SCNPlane视频纹理的布局坐标问题

嘿,我来帮你搞定这个视频纹理的布局调整!你已经完成了基础的节点和播放器创建,接下来咱们把视频的布局和显示搞定,主要有两种常用的方式,我给你详细讲清楚:

方法一:用SpriteKit的SKScene控制布局(推荐,更灵活)

这种方式借助SpriteKit的布局系统来调整视频的位置、缩放和适配模式,操作起来更直观,还能顺便加一些2D元素(比如字幕、动画)到视频上。

先补全你的代码,然后加上布局设置:

// 你的基础代码
let plane = SCNPlane(width: 5, height: 5)
let node = SCNNode(geometry: plane)
GlobalScene.shared.rootNode.addChildNode(node)

guard let urlStr = Bundle.main.path(forResource: "test", ofType: "mov"),
      let videoURL = NSURL(fileURLWithPath: urlStr) as? URL else {
    fatalError("找不到视频文件")
}

// 创建AVPlayer和SKVideoNode
let player = AVPlayer(url: videoURL)
let videoNode = SKVideoNode(avPlayer: player)

// 1. 创建适配SCNPlane尺寸的SKScene
let skSceneSize = CGSize(width: plane.width, height: plane.height)
let skScene = SKScene(size: skSceneSize)

// 2. 设置SKScene的缩放模式,控制整体适配逻辑
skScene.scaleMode = .resizeAspectFill // 可选:.resizeAspect(保持比例,留黑边)、.resizeAspectFill(铺满,裁剪超出部分)

// 3. 调整videoNode在SKScene中的布局,让它居中铺满
videoNode.position = CGPoint(x: skScene.size.width/2, y: skScene.size.height/2)
videoNode.size = skScene.size
videoNode.videoGravity = .resizeAspectFill // 和scene的scaleMode配合,保证视频适配

// 4. 将SKScene设置为SCNPlane的材质内容
plane.firstMaterial?.contents = skScene

// 开始播放视频
player.play()

如果遇到视频倒过来的情况(因为SceneKit的Y轴和SpriteKit的Y轴方向相反),给videoNode加个翻转就行:

videoNode.yScale = -1

方法二:直接用SCNMaterial的contentsTransform调整

如果不需要SpriteKit的额外功能,也可以直接通过SceneKit材质的contentsTransform属性,用CATransform3D来控制视频纹理的缩放、平移,实现布局调整。

示例代码:

// 基础代码和上面一致,到创建player为止
let player = AVPlayer(url: videoURL)
let material = plane.firstMaterial!

// 1. 将AVPlayer直接设为材质内容
material.contents = player

// 2. 计算视频和平面的宽高比,调整缩放比例
let videoAspectRatio = 16.0/9.0 // 替换成你的视频实际宽高比
let planeAspectRatio = plane.width / plane.height

var scaleX: CGFloat = 1.0
var scaleY: CGFloat = 1.0

if videoAspectRatio > planeAspectRatio {
    // 视频比平面宽,缩放Y轴让高度适配平面
    scaleY = CGFloat(planeAspectRatio / videoAspectRatio)
} else {
    // 视频比平面高,缩放X轴让宽度适配平面
    scaleX = CGFloat(videoAspectRatio / planeAspectRatio)
}

// 3. 创建变换:先缩放,再平移让视频居中
let scaleTransform = CATransform3DMakeScale(scaleX, scaleY, 1)
let translateTransform = CATransform3DMakeTranslation((1 - scaleX)/2, (1 - scaleY)/2, 0)
material.contentsTransform = CATransform3DConcat(scaleTransform, translateTransform)

// 可选:如果视频倒过来,加上Y轴翻转
// material.contentsTransform = CATransform3DConcat(material.contentsTransform, CATransform3DMakeScale(1, -1, 1))

// 开始播放
player.play()

额外注意点

  • 如果只需要视频显示在平面的一面,可以设置material.isDoubleSided = false,节省渲染性能
  • 记得处理视频播放的生命周期:比如进入后台时暂停player.pause(),回到前台时继续player.play()
  • 如果需要视频循环播放,可以设置player.actionAtItemEnd = .none,然后监听AVPlayerItemDidPlayToEndTimeNotification来实现循环逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:50:02