xcode 了解SKShader中着色器的坐标?

zwghvu4y  于 2023-05-01  发布在  其他
关注(0)|答案(1)|浏览(95)

我一直在尝试理解着色器的坐标如何与SpriteKit一起工作。下面是我的测试程序。我创造了一个精灵,然后加载并运行一个着色器(作为一个字符串)在这个精灵上。着色器应在白色背景上创建蓝色矩形。我需要的矩形接近精灵的大小(等于0。9或其大小的90%),并且无论精灵在屏幕上的位置如何,都保持在精灵的中心。然而,我观察到:

  • 蓝色矩形明显小于精灵
  • 蓝色矩形似乎是粘在屏幕上,而不是来与精灵。这意味着它可能会“跑”出来的精灵时,我把精灵到其他位置。我猜这是由于使用gl_FragCoord造成的,但是当我用v_tex_coor替换它时,它仍然不起作用

有人能给我解释一下在使用SpriteKit时着色器的协调以及如何解决这些问题吗?谢谢。

import SpriteKit

class ViewController: UIViewController {
    // Shader as a string
    let shaderSource =
"""
// the center point of the rectangle, not really center vec2(0.0) but just for testing
constant vec2 center = vec2(0.5, 0.5); 
constant vec2 rectSz = vec2(0.9, 0.9); // size of the rectangle

void main()
{
    /// uv from -1 to 1 in Y height
    vec2 uv = (gl_FragCoord.xy - u_sprite_size.xy * 0.5) / u_sprite_size.y;

    vec2 sz = rectSz / 2.0; // half size to the center point

    vec2 d = abs(uv - center);
    bool inside = d.x <= sz.x && d.y <= sz.y;

    // draw blue rectangle, white background
    gl_FragColor = inside ? vec4(0.0, 0.0, 1.0, 1.) : vec4(1.0);
}
"""
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let sceneView = SKView(frame: view.bounds)
        print("view.bounds = \(view.bounds)")
        self.view.addSubview(sceneView)

        let scene = SKScene(size: view.bounds.size)
        sceneView.presentScene(scene)
        
        // sprite in yellow if shader is not working
        let sprite = SKSpriteNode(color: UIColor.yellow, size: CGSize(width: 300, height: 300))
        sprite.position = CGPoint(x: 150, y: view.bounds.height - 150)
        scene.addChild(sprite)
        
        let spriteSize = vector_float2(Float(sprite.frame.size.width),
                                       Float(sprite.frame.size.height))

        let shader = SKShader(source: shaderSource,
                              uniforms: [
                                SKUniform(name: "u_sprite_size", vectorFloat2: spriteSize)
                              ])
        sprite.shader = shader
    }
}

hrysbysz

hrysbysz1#

在某些情况下,将子画面大小作为均匀值传递是有用的。但你想多了如果你想让着色器坐标在0-1的数字空间中与精灵的大小齐平,那么你只要把坐标取为vec2 st = v_tex_coord.xy;就足够了,然后简单地使用它们而不需要缩放它们。下面是一个例子,在两个不同大小的精灵中绘制一个圆。

let shaderSource = """
constant vec2 center = vec2(0.5, 0.5);

void main() {
    vec2 st = v_tex_coord.xy;
    float d = distance(st,vec2(0.5)); //distance to center
    vec3 color = (d > center.x/2) ? vec3(1.0) : vec3(0.0); //interpret distance as color value
    gl_FragColor = vec4( color, 1.0 );
}
"""

class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        let shader = SKShader(source: shaderSource)
                                 
        let sprite1 = SKSpriteNode(color: UIColor.yellow, size: CGSize(width: 300, height: 300))
        sprite1.position.y = 150
        sprite1.shader = shader
        addChild(sprite1)

        let sprite2 = SKSpriteNode(color: UIColor.red, size: CGSize(width: 100, height: 100))
        sprite2.position.y = -150
        sprite2.shader = shader
        addChild(sprite2)
    }

}

相关问题