gpt4 book ai didi

macos - 使用计算着色器的 Metal 模拟几何着色器

转载 作者:行者123 更新时间:2023-12-04 15:29:54 27 4
gpt4 key购买 nike

我正在尝试在 Metal 中实现体素锥体追踪。该算法的步骤之一是使用几何着色器对几何进行体素化。 Metal 没有几何着色器,所以我正在考虑使用计算着色器来模拟它们。我将顶点缓冲区传入计算着色器,执行几何着色器通常会执行的操作,并将结果写入输出缓冲区。我还将绘制命令添加到间接缓冲区。我使用输出缓冲区作为顶点着色器的顶点缓冲区。这工作正常,但我的顶点需要两倍的内存,一个用于顶点缓冲区,另一个用于输出缓冲区。有没有办法直接将计算着色器的输出传递给顶点着色器而不将其存储在中间缓冲区中?我不需要保存计算着色器的输出缓冲区的内容。我只需要将结果提供给顶点着色器。

这可能吗?谢谢

编辑

本质上,我试图从 glsl 模拟以下着色器:

#version 450

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

layout(location = 0) in vec3 in_position[];
layout(location = 1) in vec3 in_normal[];
layout(location = 2) in vec2 in_uv[];

layout(location = 0) out vec3 out_position;
layout(location = 1) out vec3 out_normal;
layout(location = 2) out vec2 out_uv;

void main()
{
vec3 p = abs(cross(in_position[1] - in_position[0], in_position[2] - in_position[0]));

for (uint i = 0; i < 3; ++i)
{
out_position = in_position[i];
out_normal = in_normal[i];
out_uv = in_uv[i];

if (p.z > p.x && p.z > p.y)
{
gl_Position = vec4(out_position.x, out_position.y, 0, 1);
}
else if (p.x > p.y && p.x > p.z)
{
gl_Position = vec4(out_position.y, out_position.z, 0, 1);
}
else
{
gl_Position = vec4(out_position.x, out_position.z, 0, 1);
}

EmitVertex();
}

EndPrimitive();
}

对于每个三角形,我需要输出一个顶点位于这些新位置的三角形。三角形顶点来自顶点缓冲区并使用索引缓冲区绘制。我还计划添加进行保守光栅化的代码(只是稍微增加三角形的大小),但这里没有显示。目前我在 Metal 计算着色器中所做的是使用索引缓冲区来获取顶点,在上面的几何着色器中执行相同的代码,然后在另一个缓冲区中输出新顶点,然后我用它来绘制。

最佳答案

这是一个非常推测性的可能性,具体取决于您的几何着色器需要做什么。

我认为你可以只用一个顶点着色器而不是单独的计算着色器来“向后”做它,代价是在 GPU 上进行冗余工作。您会进行绘制,就像您拥有几何着色器输出图元的所有输出顶点的缓冲区一样。但是,您实际上手头上没有那个。您将构建一个可以在飞行中计算它们的顶点着色器。

因此,在应用程序代码中,计算输出基元的数量,从而计算为给定输入基元计数生成的输出顶点数。绘制具有这么多顶点的输出原始类型。

你会不是 提供一个缓冲区,其中输出顶点数据作为此绘图的输入。

您将提供原始索引缓冲区和原始顶点缓冲区作为该绘制的顶点着色器的输入。着色器将根据顶点 ID 计算它所针对的输出图元,以及该图元的哪个顶点(例如,对于三角形,分别是 vid / 3vid % 3 )。根据输出图元 ID,它将计算哪个输入图元会在原始几何着色器中生成它。

着色器将从索引缓冲区中查找该输入图元的索引,然后从顶点缓冲区中查找顶点数据。 (例如,这对三角形列表与三角形带之间的区别很敏感。)它会将任何预几何着色器顶点着色应用于该数据。然后它将执行有助于识别输出图元的识别顶点的几何计算部分。一旦计算出输出顶点数据,您就可以应用任何您想要的后几何着色器顶点着色(?)。结果就是它会返回的内容。

如果几何着色器可以为每个输入图元生成可变数量的输出图元,那么至少您有一个最大数量。因此,您可以为输出图元的最大潜在计数绘制顶点的最大潜在计数。顶点着色器可以进行必要的计算,以确定几何着色器实际上是否会生成该图元。如果没有,顶点着色器可以安排将整个图元剪掉,方法是将其定位在视锥体外或使用 [[clip_distance]]输出顶点数据的属性。

这避免了将生成的基元存储在缓冲区中。但是,它会导致 GPU 重复执行一些预几何着色器顶点着色器和几何着色器计算。当然,它会被并行化,但可能仍然比你现在正在做的要慢。此外,它可能会破坏一些关于获取索引和顶点数据的优化,而这些优化可能是使用更普通的顶点着色器实现的。

这是几何着色器的转换示例:

#include <metal_stdlib>
using namespace metal;

struct VertexIn {
// maybe need packed types here depending on your vertex buffer layout
// can't use [[attribute(n)]] for these because Metal isn't doing the vertex lookup for us
float3 position;
float3 normal;
float2 uv;
};

struct VertexOut {
float3 position;
float3 normal;
float2 uv;
float4 new_position [[position]];
};


vertex VertexOut foo(uint vid [[vertex_id]],
device const uint *indexes [[buffer(0)]],
device const VertexIn *vertexes [[buffer(1)]])
{
VertexOut out;

const uint triangle_id = vid / 3;
const uint vertex_of_triangle = vid % 3;

// indexes is for a triangle strip even though this shader is invoked for a triangle list.
const uint index[3] = { indexes[triangle_id], index[triangle_id + 1], index[triangle_id + 2] };
const VertexIn v[3] = { vertexes[index[0]], vertexes[index[1]], vertexes[index[2]] };

float3 p = abs(cross(v[1].position - v[0].position, v[2].position - v[0].position));

out.position = v[vertex_of_triangle].position;
out.normal = v[vertex_of_triangle].normal;
out.uv = v[vertex_of_triangle].uv;

if (p.z > p.x && p.z > p.y)
{
out.new_position = float4(out.position.x, out.position.y, 0, 1);
}
else if (p.x > p.y && p.x > p.z)
{
out.new_position = float4(out.position.y, out.position.z, 0, 1);
}
else
{
out.new_position = float4(out.position.x, out.position.z, 0, 1);
}

return out;
}

关于macos - 使用计算着色器的 Metal 模拟几何着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50557224/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com