如何在金属片段着色器中动态获取渲染目标尺寸?
how to get render target dimensions dynamically in a Metal fragment shader?
此 Metal 着色器基于此处的教程
http://metalkit.org/2016/10/01/using-metalkit-part-2-3-2.html
它绘制了页面上第 3 个图像中看到的黄色和蓝色渐变。
我使用此着色器的目标是使用 fragment/vertex 对而不是计算着色器来绘制它。
此着色器的结果在 MacOS Swift Playground 中由 MTKView 的子类显示。
着色器代码:
#include <metal_stdlib>
using namespace metal;
struct Vertex {
float4 position [[position]];
float4 color;
};
vertex Vertex vertex_func(constant Vertex *vertices [[buffer(0)]],
uint vid [[vertex_id]]) {
Vertex in = vertices[vid];
Vertex out;
out.position = float4(in.position);
out.color = in.color;
return out;
}
fragment float4 fragment_func(Vertex vert [[stage_in]],
constant float &timer [[buffer(0)]]) {
float4 fragColor;
int width = 400;
int height = 400;
float2 resolution = float2(width,height);
float2 uv = vert.position.xy * 0.5 / resolution;
float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1 - uv.y));
fragColor = float4(color,1);
return(fragColor);
}
swift顶点和索引代码:
let vertexData = [
Vertex(pos: [-1.0, -1.0, 0.0, 1.0], col: [1, 0, 0, 1]),
Vertex(pos: [ 1.0, -1.0, 0.0, 1.0], col: [0, 1, 0, 1]),
Vertex(pos: [ 1.0, 1.0, 0.0, 1.0], col: [0, 0, 1, 1]),
Vertex(pos: [-1.0, 1.0, 0.0, 1.0], col: [1, 1, 1, 1])
]
let indexData: [UInt16] = [
0, 1, 2, 2, 3, 0
]
最终图像的尺寸是硬编码的,400x400。有没有办法动态获取渲染目标尺寸?
我不知道有什么方法可以直接从片段函数查询渲染目标的尺寸。
一种技术是通过缓冲区传递维度。然后,应用程序代码将使用渲染目标纹理的属性填充该缓冲区。您已经有效地为 timer
参数执行了该操作。你会扩大它。例如:
struct params
{
float timer;
uint2 size;
};
然后,将函数参数列表中的 float &timer
替换为 params ¶ms
。将函数体中 timer
的使用替换为 params.timer
。使用 params.size
而不是 resolution
.
当然,您的应用程序代码必须更改其设置缓冲区 0 的方式,使其成为具有适当大小和布局的结构,并在其中存储计时器和渲染目标尺寸。
我认为将渲染目标纹理作为参数传递给函数也可以(通过渲染命令编码器的片段纹理 table)。您的片段函数将声明另一个参数,例如 texture2d<float, access::read> rt [[texture(0)]]
,以接收该纹理参数。然后,您可以调用 rt.get_width()
和 rt.get_height()
来获取其尺寸。
此 Metal 着色器基于此处的教程
http://metalkit.org/2016/10/01/using-metalkit-part-2-3-2.html
它绘制了页面上第 3 个图像中看到的黄色和蓝色渐变。
我使用此着色器的目标是使用 fragment/vertex 对而不是计算着色器来绘制它。
此着色器的结果在 MacOS Swift Playground 中由 MTKView 的子类显示。
着色器代码:
#include <metal_stdlib>
using namespace metal;
struct Vertex {
float4 position [[position]];
float4 color;
};
vertex Vertex vertex_func(constant Vertex *vertices [[buffer(0)]],
uint vid [[vertex_id]]) {
Vertex in = vertices[vid];
Vertex out;
out.position = float4(in.position);
out.color = in.color;
return out;
}
fragment float4 fragment_func(Vertex vert [[stage_in]],
constant float &timer [[buffer(0)]]) {
float4 fragColor;
int width = 400;
int height = 400;
float2 resolution = float2(width,height);
float2 uv = vert.position.xy * 0.5 / resolution;
float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1 - uv.y));
fragColor = float4(color,1);
return(fragColor);
}
swift顶点和索引代码:
let vertexData = [
Vertex(pos: [-1.0, -1.0, 0.0, 1.0], col: [1, 0, 0, 1]),
Vertex(pos: [ 1.0, -1.0, 0.0, 1.0], col: [0, 1, 0, 1]),
Vertex(pos: [ 1.0, 1.0, 0.0, 1.0], col: [0, 0, 1, 1]),
Vertex(pos: [-1.0, 1.0, 0.0, 1.0], col: [1, 1, 1, 1])
]
let indexData: [UInt16] = [
0, 1, 2, 2, 3, 0
]
最终图像的尺寸是硬编码的,400x400。有没有办法动态获取渲染目标尺寸?
我不知道有什么方法可以直接从片段函数查询渲染目标的尺寸。
一种技术是通过缓冲区传递维度。然后,应用程序代码将使用渲染目标纹理的属性填充该缓冲区。您已经有效地为 timer
参数执行了该操作。你会扩大它。例如:
struct params
{
float timer;
uint2 size;
};
然后,将函数参数列表中的 float &timer
替换为 params ¶ms
。将函数体中 timer
的使用替换为 params.timer
。使用 params.size
而不是 resolution
.
当然,您的应用程序代码必须更改其设置缓冲区 0 的方式,使其成为具有适当大小和布局的结构,并在其中存储计时器和渲染目标尺寸。
我认为将渲染目标纹理作为参数传递给函数也可以(通过渲染命令编码器的片段纹理 table)。您的片段函数将声明另一个参数,例如 texture2d<float, access::read> rt [[texture(0)]]
,以接收该纹理参数。然后,您可以调用 rt.get_width()
和 rt.get_height()
来获取其尺寸。