将一个自定义SKShader应用到SKScene中,使用Swift将iOS 8 SpriteKit中的整个渲染场景进行像素化
我正在尝试在SKScene上创build一个全屏的像素化效果。 我了解到,应该有两个select来做到这一点:
- 使用使用GLES 2.0的自定义
SKShader
。 - 使用核心图像filter。
我试图添加一个自定义的SKShader应该修改整个屏幕像素化。 我不确定如果可能,但SKScene
( SKScene
的子类)的SKEffectNode
表明:
SKEffectNode对象将其子级渲染为缓冲区,并可select将Core Image滤镜应用于此渲染输出。
像GameScene : SKScene
一样,可以将SKShader分配给SKScene GameScene : SKScene
:
override func didMoveToView(view: SKView) { let shader = SKShader(fileNamed: "pixelation.fsh") self.shader = shader self.shouldEnableEffects = true }
…但似乎呈现的缓冲区不作为u_texture传递给GLES:
void main() { vec2 coord = v_tex_coord; coord.x = floor(coord.x * 10.0) / 10.0; coord.y = floor(coord.y * 10.0) / 10.0; vec4 texture = texture2D(u_texture, coord); gl_FragColor = texture; }
…所以以前的着色器不起作用。
如果我将该着色器分配给基于纹理的SKSpriteNode
,它将起作用。
那么在所有的节点被渲染之后,是否有可能修改整个帧缓冲区(例如像素化)作为后期处理措施?
编辑 :我find了一种在OS X中使用Core Imagefilter进行像素化的方法( 如何将CIPixellate Core Image Filter添加到Sprite Kit场景? ),但是复制该实现不会在iOS上产生任何结果。 根据文件, CIPixellate
应该Available in OS X v10.4 and later and in iOS 6.0 and later.
。
为了让你的.shader
在.shader
运行,你需要在场景中设置shouldEnableEffects
为true(对于SKEffectNode
)。
虽然在技术上,这是“有效的”(着色器被应用),但是在渲染场景之后存在稍微resize的错误。
所以到目前为止,使用CoreImage
filter是最好的方法。
我设法使用核心图像filterCIPixellate
。 我使用的是SKEffectNode
产生像素化效果的filter。 几件事要注意:
-
SKScene
是SKScene
的子类,但是将filter应用于SKScene
不起作用。 它会弄乱背景,不做任何像素化。 - 您需要创build一个
SKEffectNode
并添加要在其下面进行像素化的节点。
这里的解决scheme是基于你使用Swift
selectGame
types项目时生成的代码:
import SpriteKit class GameScene: SKScene { var effectNode : SKEffectNode = SKEffectNode.node() override func didMoveToView(view: SKView) { let filter = CIFilter(name: "CIPixellate") filter.setDefaults() filter.setValue(5.0, forKey: "inputScale") self.effectNode.filter = filter self.effectNode.shouldEnableEffects = true self.addChild(effectNode) } override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { for touch: AnyObject in touches { let location = touch.locationInNode(self) let sprite = SKSpriteNode(imageNamed:"Spaceship") sprite.xScale = 0.5 sprite.yScale = 0.5 sprite.position = location let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1) sprite.runAction(SKAction.repeatActionForever(action)) self.effectNode.addChild(sprite) } } override func update(currentTime: CFTimeInterval) { /* Called before each frame is rendered */ } }
实际上,我不得不为最近的项目做同样的事情,以此作为在不同层次之间转换的方式,最后为此做了一些工作。 基本上,我在代码中截取了屏幕截图,然后当我加载下一个关卡时,我调用了以前保存的屏幕截图,看它在加载时的样子。 我将之前的关卡截图添加为SKSpriteNode,然后多次运行着色器,直到它非常像素化。 然后我对截图进行了相同的处理,并replace了这两个截图,然后我对第二个截图进行了非像素化处理,所以看起来像一旦水平被击败,所有的像素都会自动像素化,从而显示出一个新的水平。
UIGraphicsBeginImageContextWithOptions(UIScreen.mainScreen().bounds.size, false, 0); self.view!.drawViewHierarchyInRect(view!.bounds, afterScreenUpdates: true) let image:UIImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //UIGraphicsEndImageContext() protoImage = SKSpriteNode(texture: SKTexture(CGImage: image.CGImage!)) protoImage.size = CGSizeMake(self.frame.size.width, self.frame.size.height) node.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2) protoImage.zPosition = 9000
第二场景
let shader: SKShader = SKShader(fileNamed: "RWTGradient2.fsh") let ratioX: Float = divisor/Float(protoImage.frame.size.width) let ratioY: Float = divisor/Float(protoImage.frame.size.height) shader.uniforms = [ SKUniform(name: "ratioX", float: ratioX), SKUniform(name: "ratioY", float: ratioY), ] protoImage.shader = shader;
- iOS:如何正确获取电池电量
- 在同一UITableView的不同部分中显示多个NSFetchedResultsControllers
- 如何从头开始创建iTunes Samples Player? (第3部分)
- AVCaptureSession真的很慢
- UITapGestureRecognizer – 让它在接触下工作,而不是接触?
- 错误:索引expression式是无效的,因为下标types'NSUInteger'不是一个整数或者客观的c指针types
- 使用XCode 5支持iOS 5.0图标
- 如何在消息扩展中发送MSMessage?
- iOS应用程序审查 – videostreamMPEG-DASH超过10分钟