ios - 为 SKShapeNode 添加着色器
问题描述
我想为SKShapeNode
. 我在这里Emboss
找到了一个着色器。
这是我的代码:
let node = SKShapeNode(rectOf: CGSize(width: w, height: h),cornerRadius: w / 4.0)
node.position = CGPoint(x: x, y: frame.size.height + h / 2)
node.fillColor = color
node.strokeColor = .clear
node.fillShader = createColorEmboss()
let v = simd_make_float2(Float(w),Float(h))
node.setValue(SKAttributeValue(vectorFloat2: v), forAttribute: "a_size")
func createColorEmboss() -> SKShader {
let source = "void main() {" +
"vec4 current_color = SKDefaultShading();" +
"if (current_color.a > 0.0) {" +
"vec2 pixel_size = 1.0 / a_size;" +
"vec4 new_color = current_color;" +
"new_color += texture2D(u_texture, v_tex_coord + pixel_size) * u_strength;" +
"new_color -= texture2D(u_texture, v_tex_coord - pixel_size) * u_strength;" +
"gl_FragColor = vec4(new_color.rgb, 1) * current_color.a * v_color_mix.a;" +
"} else {" +
"gl_FragColor = current_color;" +
"}" +
"}"
let shader = SKShader(source: source, uniforms: [SKUniform(name: "u_strength", float: 1)])
shader.attributes = [SKAttribute(name: "a_size", type: .vectorFloat2)]
return shader
}
但是什么也没发生。任何想法?
解决方案
带纹理的(*) SKShapeNode
和这里有一些很大的区别SKSpriteNode
:
- 如果
SKSpriteNode
有纹理和自定义着色器(shader
属性),那么着色器将可以通过制服访问原始纹理u_texture
,并且可以使用它来渲染节点,即通过对其应用各种效果,如浮雕、模糊, ETC。 SKShapeNode
可能有 afillTexture
和 afillShader
,但它们的工作方式不同:fillTexture
是一个矩形纹理,它被转换为灰度,用于设置fillColor
形状节点填充区域的亮度。fillShader
只能fillTexture
在用于最终渲染之前看到这个矩形图像,无法修改甚至查看矩形的哪些区域将是可见的(填充的一部分),以及最终渲染的外观。- 如果没有明确
fillTexture
的集合,u_texture
制服似乎假装它是一望无际的白色:无论你问什么坐标,它都会返回白色,即使你超出了它的界限。
(*)您也可以SKSpriteNode
只用一种颜色创建一个;它的行为将是一个奇怪的混合SKShapeNode
和一个纹理SKSpriteNode
,它对我们的讨论没有帮助,所以我会忽略这种。
您可以做的是将您的光栅SKShapeNode
化为纹理,并SKSpriteNode
从中创建一个。其实很简单:
let node = SKShapeNode(rectOf: CGSize(width: w, height: h),cornerRadius: w / 4.0)
node.fillColor = color
node.strokeColor = .clear
let theTexture = view.texture(from:node)
let spriteNode = SKSpriteNode(texture:theTexture)
spriteNode.position = CGPoint(x: x, y: frame.size.height + h / 2)
spriteNode.shader = createColorEmboss()
let v = simd_make_float2(Float(w),Float(h))
spriteNode.setValue(SKAttributeValue(vectorFloat2: v), forAttribute: "a_size")
如您所见,您甚至不必将节点添加到场景中;视图会将其渲染为具有清晰背景的纹理。您还可以使用view.texture(from:crop:)
指定更大的裁剪,如果它超出原始形状,则可以容纳投影。
但是,我必须警告您,您尝试使用的这个特定着色器可能不是您所需要的阴影……</p>
推荐阅读
- python - scipy.optimize 最小化的结果关闭
- angular - Angular 8 Material Table 分页和排序,使用自定义组件和来自 API 错误的动态数据 - 问题
- python - 使用pyqt5中的另一个按钮激活按钮,我应该使用if语句吗?
- javascript - 在异步操作的新窗口中打开签名的 S3 URL 时出错
- python - 使用 python 排序函数对 Pandas DataFrame 中的值进行排序
- batch-file - 我需要脚本来处理所有 dav 文件
- javascript - 仅当文本框具有使用 JavaScript 从数据库中显示的某些值时,它才会可见
- html - 模板驱动形式将所有内容标记为已触摸 - Angular 7
- mysql - SQL - 过程函数
- c - 如何制作在 C 中重复的菜单