2012-12-10 65 views
1

详细信息:HLSL修改镶嵌着色器以制作等边三角形?

我正在处理程序行星的一代进程;到目前为止,我已经完成了动态LOD工作,但是我目前的软件算法非常慢。我决定用DX11的新镶嵌功能来代替它。 目前我的球体是细分的二十面体。 (20对双方都等边三角形)

回来时,我用我的软件算法细分,一个三角形是 拆分成跨越父每次形成海拉尔符号的中点四个孩子......这样的:http://puu.sh/1xFIx

正如你所看到的,每个三角形细分创造了越来越多的等边三角形,即每一个完全相同的形状。

但现在,我使用的GPU曲面细分在HLSL,结果绝对不是 我所期待的:http://puu.sh/1xFx7

问题:

有什么我可以在做赫尔和域着色器来改变镶嵌 以便它细分为套等边三角形像第一形象?

我应该使用几何着色器这样的事情?如果是这样,那么它是否会比曲面细分器慢 ?

回答

0

我试过使用Tessellation Shader,但是我发现一个问题:域着色器只能通过uv坐标(SV_DomainLocation)和用于定位顶点的输入补丁,当顶点的域位置为0.3,0.3,0.3(中心顶点)是不可能知道正确的位置,因为您需要了解这不是由域着色阶段提供迭代的其他顶点或指数(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]; 
     } 
    } 
}