gpt4 book ai didi

ios - 如何以较低的分辨率渲染 SceneKit 着色器?

转载 作者:行者123 更新时间:2023-12-01 15:42:46 25 4
gpt4 key购买 nike

我正在使用 SceneKit shader modifiers 向我的应用添加一些视觉元素|像这样:

// A SceneKit scene with orthographic projection

let shaderBundle = Bundle(for: Self.self)
let shaderUrl = shaderBundle.url(forResource: "MyShader.frag", withExtension: nil)!
let shaderString = try! String(contentsOf: shaderUrl)

let plane = SCNPlane(width: 512, height: 512) // 1024x1024 pixels on devices with x2 screen resolution
plane.firstMaterial!.shaderModifiers = [SCNShaderModifierEntryPoint.fragment: shaderString]

let planeNode = SCNNode(geometry: plane)
rootNode.addChildNode(planeNode)

问题是性能低下,因为 SceneKit 正在煞费苦心地渲染筛选着色器的平面的每个像素。如何降低着色器的分辨率以保持平面大小不变?

我已经尝试让 plane 变小,并在 planeNode 上使用放大比例变换但没有结果,着色器的再现仍然像以前一样非常详细。

使用 plane.firstMaterial!.diffuse.contentsTransform 也没有帮助(或者我做错了)。

我知道我可以使全局 SCNView 变小,然后应用仿射缩放变换,如果该着色器是场景中唯一的节点,但它不是,还有其他节点(不是着色器) ) 在同一场景中,我宁愿避免以任何方式改变它们的外观。

最佳答案

似乎我通过将 SceneKit 场景嵌套在顶层 SceneKit 场景显示的 SpriteKit 场景中,使用一种“渲染到纹理”的方法设法解决了这个问题。

更详细地说,SCNNode 的以下子类在 SpriteKit 的 SK3DNode 中放置一个缩小的着色器平面,然后采用该 SK3DNode 和将其作为 SceneKit 的 SKScene 放入 SpriteKit 场景中,然后使用该 SKScene 作为放入顶级 SceneKit 场景中的放大平面的漫反射内容。

奇怪的是,为了保持原始分辨率,我需要使用 scaleFactor*2,所以为了将渲染分辨率减半(通常是比例因子 0.5),我实际上需要使用 scaleFactor = 1.

如果有人碰巧知道这种奇怪行为的原因或解决方法,请在评论中告诉我。

import Foundation
import SceneKit
import SpriteKit

class ScaledResolutionFragmentShaderModifierPlaneNode: SCNNode {

private static let nestedSCNSceneFrustumLength: CGFloat = 8

// For shader parameter input
let shaderPlaneMaterial: SCNMaterial

// shaderModifier: the shader
// planeSize: the size of the shader on the screen
// scaleFactor: the scale to be used for the shader's rendering resolution; the lower, the faster
init(shaderModifier: String, planeSize: CGSize, scaleFactor: CGFloat) {
let scaledSize = CGSize(width: planeSize.width*scaleFactor, height: planeSize.height*scaleFactor)

// Nested SceneKit scene with orthographic projection
let nestedSCNScene = SCNScene()
let camera = SCNCamera()
camera.zFar = Double(Self.nestedSCNSceneFrustumLength)
camera.usesOrthographicProjection = true
camera.orthographicScale = Double(scaledSize.height/2)
let cameraNode = SCNNode()
cameraNode.camera = camera
cameraNode.simdPosition = simd_float3(x: 0, y: 0, z: Float(Self.nestedSCNSceneFrustumLength/2))
nestedSCNScene.rootNode.addChildNode(cameraNode)
let shaderPlane = SCNPlane(width: scaledSize.width, height: scaledSize.height)
shaderPlaneMaterial = shaderPlane.firstMaterial!
shaderPlaneMaterial.shaderModifiers = [SCNShaderModifierEntryPoint.fragment: shaderModifier]
let shaderPlaneNode = SCNNode(geometry: shaderPlane)
nestedSCNScene.rootNode.addChildNode(shaderPlaneNode)

// Intermediary SpriteKit scene
let nestedSCNSceneSKNode = SK3DNode(viewportSize: scaledSize)
nestedSCNSceneSKNode.scnScene = nestedSCNScene
nestedSCNSceneSKNode.position = CGPoint(x: scaledSize.width/2, y: scaledSize.height/2)
nestedSCNSceneSKNode.isPlaying = true
let intermediarySKScene = SKScene(size: scaledSize)
intermediarySKScene.backgroundColor = .clear
intermediarySKScene.addChild(nestedSCNSceneSKNode)
let intermediarySKScenePlane = SCNPlane(width: scaledSize.width, height: scaledSize.height)
intermediarySKScenePlane.firstMaterial!.diffuse.contents = intermediarySKScene
let intermediarySKScenePlaneNode = SCNNode(geometry: intermediarySKScenePlane)
let invScaleFactor = 1/Float(scaleFactor)
intermediarySKScenePlaneNode.simdScale = simd_float3(x: invScaleFactor, y: invScaleFactor, z: 1)

super.init()

addChildNode(intermediarySKScenePlaneNode)
}

required init?(coder: NSCoder) {
fatalError()
}

}

关于ios - 如何以较低的分辨率渲染 SceneKit 着色器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62539114/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com