繁体   English   中英

如何在片段着色器(SpriteKit)中绘制纹理的特定部分

[英]How to draw specific part of texture in fragment shader (SpriteKit)

我的节点大小为 64x32,纹理大小为 192x192,我试图在第一个节点处绘制该纹理的第一部分,在第二个节点处绘制第二部分......

片段着色器(附加到 SKSpriteNode,纹理大小为 64x32)

void main() {
    float bX = 64.0 / 192.0 * (offset.x + 1);
    float aX = 64.0 / 192.0 * (offset.x );
    float bY = 32.0 / 192.0 * (offset.y + 1);
    float aY = 32.0 / 192.0 * (offset.y);
    float normalizedX = (bX - aX) * v_tex_coord.x + aX;
    float normalizedY = (bY - aY) * v_tex_coord.y + aY;
    gl_FragColor = texture2D(u_temp, vec2(normalizedX, normalizedY));
}

但结果似乎是错误的:

带有附加纹理的 SKSpriteNode

带有附加纹理的 SKSpriteNode

SKSpriteNode 没有纹理(我想用纹理实现)

SKSpriteNode 没有纹理

当纹理位于 altas 中时,不再通过(0,0)(1,1)的坐标来处理它。 地图集真的是一个在幕后组装的大纹理。 当您在普通精灵中使用来自图集的特定命名图像时,SpriteKit 会在有关图集如何组装的信息中查找该图像名称,然后告诉 GPU 类似“使用bigAtlasTexture绘制此精灵,坐标(0.1632,0.8814)通过(0.1778, 0.9143) “。 如果您要使用相同的纹理编写自定义着色器,则需要有关它在图集中的位置的信息,您可以从textureRect获得这些信息:

https://developer.apple.com/documentation/spritekit/sktexture/1519707-texturerect

因此,您的纹理实际上不是一个图像,而是由许多纹理的大打包图像中的位置textureRect()定义的。 我发现从(0,0)(1,1)的角度来思考最容易,所以在编写着色器时,我通常会做textureRect => 减法和缩放以达到(0,0)-(1,1) = > 计算所需的修改坐标 => 缩放并再次添加到textureRect => texture2D查找。

由于您的着色器需要了解textureRect但您不能从着色器代码中调用它,因此您有两种选择:

  1. 制作一个属性或统一来保存该信息,从外部填充它,然后让着色器引用它。
  2. 如果着色器仅用于特定纹理或少数纹理,那么您可以生成专用于所需textureRect的着色器代码,即它只是在纹理代码中包含一些常量。

这是使用方法 #2 的示例的一部分:

func myShader(forTexture texture: SKTexture) -> SKShader {
  // Be careful not to assume that the texture has v_tex_coord ranging in (0, 0) to
  // (1, 1)!  If the texture is part of a texture atlas, this is not true.  I could
  // make another attribute or uniform to pass in the textureRect info, but since I
  // only use this with a particular texture, I just pass in the texture and compile
  // in the required v_tex_coord transformations for that texture.
  let rect = texture.textureRect()
  let shaderSource = """
  void main() {
    // Normalize coordinates to (0,0)-(1,1)
    v_tex_coord -= vec2(\(rect.origin.x), \(rect.origin.y));
    v_tex_coord *= vec2(\(1 / rect.size.width), \(1 / rect.size.height));
    // Update the coordinates in whatever way here...
    // v_tex_coord = desired_transform(v_tex_coord)
    // And then go back to the actual coordinates for the real texture
    v_tex_coord *= vec2(\(rect.size.width), \(rect.size.height));
    v_tex_coord += vec2(\(rect.origin.x), \(rect.origin.y));
    gl_FragColor = texture2D(u_texture, v_tex_coord);
  }
  """
  let shader = SKShader(source: shaderSource)
  return shader
}

这是此处某些特定示例的简化版本: https://github.com/bg2b/RockRats/blob/master/Asteroids/Hyperspace.swift

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM