【问题标题】:HLSL Modify Tessellation shader to make equilateral triangles?HLSL 修改 Tessellation 着色器以制作等边三角形?
【发布时间】:2012-12-10 04:01:51
【问题描述】:

详情:

我正在生成程序行星;到目前为止,我已经完成了动态 LOD 工作,但是我目前的软件算法非常慢。我决定改用 DX11 的新曲面细分功能。 目前我的球体是一个细分的二十面体。 (20条边都是等边三角形)

当我使用我的软件算法进行细分时,一个三角形将是 每次都在父节点的中点分成四个子节点,形成 Hyrule 符号……就像这样:http://puu.sh/1xFIx

如您所见,每个细分的三角形都创建了越来越多的等边三角形,即每个三角形的形状完全相同。

但是现在我使用 GPU 在 HLSL 中进行曲面细分,结果肯定不是 我在找什么:http://puu.sh/1xFx7

问题:

我可以在 Hull 和 Domain 着色器中做些什么来更改曲面细分 让它像第一张图片一样细分成一组等边三角形?

我应该使用几何着色器来做这样的事情吗?如果是这样,会不会 比 tessellator 慢?

【问题讨论】:

    标签: directx hlsl tessellation


    【解决方案1】:

    我尝试使用 Tessellation Shader,但遇到了一个问题:当顶点的域位置为 0.3、0.3、0.3(中心顶点)时,域着色器仅传递 uv 坐标 (SV_DomainLocation) 和用于定位顶点的输入补丁) 不可能知道正确的位置,因为您需要有关其他顶点的信息或域着色器阶段未提供的迭代索引 (x, y)。

    因为这个问题我在几何着色器中编写代码,这个着色器对于镶嵌非常有限,因为输出流的大小不能大于 1024 字节(在着色器模型 5.0 中)。我使用 uv(如 SV_DomainLocation)实现了顶点位置的计算,但这仅对三角形进行细分,您必须使用部分代码来计算三角形中心的添加位置以创建精确的最终结果。

    这是等边三角形镶嵌的代码:

    // required for array
    #define MAX_ITERATIONS 5
    
    void DrawTriangle(float4 p0, float4 p1, float4 p2, inout TriangleStream<VS_OUT> stream)
    {
        VS_OUT v0;
        v0.pos = p0;
        stream.Append(v0);
    
        VS_OUT v1;
        v1.pos = p1;
        stream.Append(v1);
    
        VS_OUT v2;
        v2.pos = p2;
        stream.Append(v2);
    
        stream.RestartStrip();
    }
    
    [maxvertexcount(128)] // directx rule: maxvertexcount * sizeof(VS_OUT) <= 1024
    void gs(triangle VS_OUT input[3], inout TriangleStream<VS_OUT> stream)
    {
        int itc = min(tess, MAX_ITERATIONS);
        float fitc = itc;
        float4 past_pos[MAX_ITERATIONS];
        float4 array_pass[MAX_ITERATIONS];
        for (int pi = 0; pi < MAX_ITERATIONS; pi++)
        {
            past_pos[pi] = float4(0, 0, 0, 0);
            array_pass[pi] = float4(0, 0, 0, 0);
        }
        // -------------------------------------
        // Tessellation kernel for the control points
        for (int x = 0; x <= itc; x++)
        {
            float4 last;
            for (int y = 0; y <= x; y++)
            {
                float2 seg = float2(x / fitc, y / fitc);
                float3 uv;
                uv.x = 1 - seg.x;
                uv.z = seg.y;
                uv.y = 1 - (uv.x + uv.z);
    
                // ---------------------------------------
                // Domain Stage
                // uv           Domain Location
                // x,y          IterationIndex
    
                float4 fpos = input[0].pos * uv.x;
                fpos += input[1].pos * uv.y;
                fpos += input[2].pos * uv.z;
    
                if (x > 0 && y > 0)
                {
                    DrawTriangle(past_pos[y - 1], last, fpos, stream);
                    if (y < x)
                    {
                        // add adjacent triangle
                        DrawTriangle(past_pos[y - 1], fpos, past_pos[y], stream);
                    }
                }
                array_pass[y] = fpos;
                last = fpos;
            }
            for (int i = 0; i < MAX_ITERATIONS; i++)
            {
                past_pos[i] = array_pass[i];
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 2018-11-12
      • 2018-01-05
      • 2023-01-30
      • 1970-01-01
      • 2023-03-28
      相关资源
      最近更新 更多