DirectX大平面镶嵌

use*_*037 3 c++ directx shader tessellation

只是关于DirectX11 Tessellation的问题.

在Hull Shader中,可以设置的最大曲面细分因子是64(不确定原因).现在虽然这对于小型飞机来说足够了,但对于大型飞机来说,它还不够,所以我想知道如何渲染大型飞机?

以下代码生成我的四边形,其中R是半径:

vertices[0] = D3DXVECTOR3(-R, 0.0f,  R); //Top left
vertices[1] = D3DXVECTOR3( R, 0.0f,  R); //Top right
vertices[2] = D3DXVECTOR3( R, 0.0f, -R); //Bottom right
vertices[3] = D3DXVECTOR3(-R, 0.0f, -R); //Bottom left
vertices[4] = D3DXVECTOR3(-R, 0.0f,  R); //Top left
vertices[5] = D3DXVECTOR3( R, 0.0f, -R); //Bottom right

indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 3;
indices[4] = 4;
indices[5] = 5;
Run Code Online (Sandbox Code Playgroud)

我确实通过将它放在循环中来修改它,以便在3x3网格中生成多个四边形.然而,当我将它传递给曲面细分着色器时,它适用于第一个四边形,但其他人搞砸了.

vector<D3DXVECTOR3> verts;
vector<D3DXVECTOR2> tex;

float R = 1000;

for(int z = 0; z < 4; z++)
{
    for(int x = 0; x < 4; x++)
    {
        float xOffset = x * (2*R);
        float zOffset = z * (2*R);

        // Load the vertex array with data.
        verts.push_back( D3DXVECTOR3(-R+ xOffset, 0.0f,  R+ zOffset) ); //Top left
        verts.push_back( D3DXVECTOR3( R+ xOffset, 0.0f,  R+ zOffset) ); //Top right
        verts.push_back( D3DXVECTOR3( R+ xOffset, 0.0f, -R+ zOffset) ); //Bottom right
        verts.push_back( D3DXVECTOR3(-R+ xOffset, 0.0f, -R+ zOffset) ); //Bottom left
        verts.push_back( D3DXVECTOR3(-R+ xOffset, 0.0f,  R+ zOffset) ); //Top left
        verts.push_back( D3DXVECTOR3( R+ xOffset, 0.0f, -R+ zOffset) ); //Bottom right

        tex.push_back( D3DXVECTOR2(0.0f, 0.0f) );
        tex.push_back( D3DXVECTOR2(1.0f, 0.0f) );
        tex.push_back( D3DXVECTOR2(0.0f, 1.0f) );
        tex.push_back( D3DXVECTOR2(0.0f, 1.0f) );
        tex.push_back( D3DXVECTOR2(1.0f, 0.0f) );
        tex.push_back( D3DXVECTOR2(1.0f, 1.0f) );
    }
}

// Set the number of vertices in the vertex array.
m_vertexCount = verts.size();

// Set the number of indices in the index array.
m_indexCount = verts.size();

// Create the vertex array.
vertices = new VertexType[m_vertexCount];
if(!vertices)
{
    return false;
}

// Create the index array.
indices = new unsigned long[m_indexCount];
if(!indices)
{
    return false;
}

for(int i = 0; i < m_vertexCount; i++)
{
    vertices[i].position = verts[i];
    vertices[i].texture =  tex[i];
    indices[i] = i;
}
Run Code Online (Sandbox Code Playgroud)

这是我渲染循环平面时的样子:

为什么在使用多个四边形时它没有正确镶嵌?我应该通过在我的图形类中创建一个循环来解决这个问题,然后我翻译并一遍又一遍地渲染相同的四边形以创建网格吗?

希望这是有道理的.

Pro*_*oxy 15

你真的想要整个平面的细分是非常值得怀疑的 - 你只是在浪费时间细分整个事物,当观众甚至无法分辨出遥远的点时.考虑实现某种实时细节层次(LOD)算法.LOD的概念是为更近的对象提供更多细节,而使远处的对象更简单以节省渲染时间.如果您没有"获得"LOD,这里有一张图片可以帮助您:

说明LOD的图像

High tessellation <-------------------------------> Low tessellation

虽然这些特定模型是在Maya等建模软件中手动创建的,但与在GPU上实时镶嵌细分相反,您仍然希望得到这个想法.当相机远离模型时,在右边渲染兔子,当它靠近时,渲染出更加细致的兔子,直到相机紧挨着物体,当你渲染完整的美丽时.

在我的时代,我发现了两种我认为优于其他方法的实时LOD方法.第一个是为水渲染而开发的,它的链接就在这里 - 我真的无法解释它比它们更好.我惊奇地看着(或者如果我失败就点点笑),因为我现在试图解释另一个!


GPU地形细分和细分

  • 资料来源:Wolfgang Engel 撰写的GPU Pro 4一书中的第一篇文章
  • 如果您稍稍眯一下,您发布的图像可能会像严重倾斜的地形.由于这是为地形开发的,因此这可能比设计用于水渲染的其他方法更容易实现.

任何知情的GPU程序员都知道,CPU速度快,GPU速度更快.复杂图形的主要瓶颈是CPU和GPU之间的数据传输.这需要永远.

该方法专为地形渲染而开发,是一种几乎完全基于GPU的算法,旨在创建具有基于距离的LOD的细分网格.虽然性能在很大程度上取决于已安装的硬件支持它的能力,但此方法针对速度进行了高度优化.

实际上,该方法重复细分直到达到所需的LOD - 由程序员传递的一些参数表示.此外,还在算法的每次迭代中执行剔除,避免对视锥体之外的区域进行大量不必要的处理或细分.

由于此方法使用的所有数据都在GPU上保留和优化,因此CPU大部分可用于执行其他任务.此外,我们还利用平滑的LOD过渡方案来展示细分算法的实际应用.最终输出(带有部分叠加线框的图像)非常酷:

最终输出

现在,我不会撒谎.该算法难以吞咽.所以,我会尽力为你剥掉它.这是术语:

Viewable region由变量R表示的可视区域被定义为轴对齐(通常是向上)的四边形,其表示要被细分和/或渲染的区域.该区域由中心位置和宽度限定,沿着每个轴在正方向和负方向上延伸(参见下图).中心位置用RC表示.施加的偏移由Rλ表示.该区域的边界点由P1,P2,P3和P4表示.想象一下像这样的可视区域:

可视区域跨度

Viewable region span 由θ表示的可视区域跨度可以通过以下函数量化,给定点P和应用的偏移λ:

θ(P,λ)= | P ScreenR - P ScreenL |

P ScreenL =(P VProjLxy)/ P ProjLw

P ScreenR =(P ProjRxy)/ P ProjRw

P ProjL = P WL ×matProjection

P ProjR = P WR ×matProjection

P WL =(P Wx - λ,P Wy)

P WR =(P Wx +λ,P Wy)

P W = P×matWorldView

可视区域跨度是其可视区域在屏幕上的宽度.

Maximum viewable region span最大可视区域跨度(由θmax表示)是允许的最大可视区域跨度.该值由用户设置,是LOD算法中的主要因素之一,并且它也是细分算法中的关键部分.在LOD算法中,如果任何给定的可视区域具有大于θmax的可视区域跨度,则将其细分为4个新的可视区域.

Relative quadrant code此代码标识拆分可视区域相对于其父可视区域的相对位置.该代码在细分算法中计算,并由LOD转换算法使用.通常编码为2位掩码,此代码成为可视区域定义的一部分.


该算法有三个主要步骤.

概观

步骤1(准备):"初始化"+"中间区域缓冲区"

  • 只是设置; 我不会用手解释它.

步骤2(细分算法):循环,包括"Dispose Region"和"Final Region Buffer"

步骤3(LOD算法):"最终区域缓冲区"+"LOD"+"输出"


第2阶段 - 细分算法

对于循环的每次迭代,将可视区域的输入流馈送到渲染管道的几何着色器阶段.第一次迭代的输入流是在阶段1中创建的初始输入流.所有后续迭代都使用前一次迭代的中间输出流作为输入.

在几何着色器中使用两个输出流.中间输出流用于保持用于进一步处理的可视区域.最终输出流用于保存在下一次​​迭代中不需要进一步处理的可视区域,并且将被渲染为算法的阶段3的一部分.在几何着色器中,处理每个可视区域并执行以下三个操作之一:

  1. 如果确定可视区域不与视锥体相交,则将其丢弃.剔除的可视区域不会添加到中间输出流或最终输出流中.在确定可视区域是否与视锥体相交时,确保考虑算法的阶段3中的位移.

  2. 如果可视区域跨度θ(写为θ(RC,Rλ))大于最大可视区域跨度θmax,则可视区域R被分成四个象限(R1,R2,R3,R4).然后将象限本身成为可视区域的象限添加到中间输出流中,以在循环的下一次迭代中重新处理.它们的相对象限代码(每个象限是唯一的)也被添加到输出流中,以识别分割可视区域与其父可视区域的相对位置.当渲染每个可视区域时,LOD过渡算法稍后使用该代码.为了分割可视区域R,创建四个新的可视区域(R1,R2,R3,R4)及其各自的中心位置(R1 C,R2 C,R3 C,R4 C)和施加的偏移(R1λ,R2λ,R3 λ,R4λ)定义如下:

R1 C =(R Cx - .5× ,R Cy + .5× )

R2 C =(R Cx + .5× Rλ/,R Cy + .5× )

R3 C =(R Cx + .5× ,R Cy - .5× )

R4 C =(R Cx - .5× ,R Cy - .5× )

R1 λ = 0.5×R λ

R2 λ = 0.5×R λ

R3 λ = 0.5×R λ

R4 λ = 0.5×R λ

  1. 如果可视区域跨度θ(R C,)小于或等于最大可视区域跨度θmax,则可视区域R被添加到可视区域的最终输出流.

另请注意,在循环的最后一次迭代中,必须将所有可查看区域添加到阶段2中的输出流.


第3阶段 - LOD过渡算法

在算法的阶段3中,渲染可视区域流.需要一个阶段3:一个给定的可视区域R与R的应用的偏移λ可以邻近另一可视区域与所施加的偏移量为半双工或双R的尺寸λ.如果不在两个不同大小的可视区域之间执行平滑过渡,则在渲染时会出现可见的不连续或其他视觉异常.

为了避免曲面细分出现裂缝,通过将可视区域分成四个四边形(由Q1,Q2,Q3和Q4表示)来渲染每个可视区域.每个四边形的边界点,包括静态边界点(P 1,P 2,P 3,P 4)的集合和变形边界点(P L,P T,P R,P B,P C),定义如下:

边界点

总的来说,这些非重叠的四边形将覆盖与它们的可视区域相同的表面区域.计算每个四边形的边界点以与相邻可视区域四边形的边界点对齐.变形四边形边界点(P L,P T,P R,P B,P C)计算如下:

变形边界点

给定点P处的可视区域跨度θ和应用的偏移λ,写为θ(P,λ),使用以下公式计算变形因子 - 写为T(P,λ):

变形因子

我们计算每个一般变形因素(T的大号,T Ť,T [R,T ,T Ç),用于与一个中心位置R的可视区域R Ç和应用偏移r λ为这样:

一般变形因素


问题是,当相邻的可视区域具有相同的应用为R偏移值这些一般变形因素只工作λ.见下图:计算一般变形因子时使用的各种位置图.

在计算变形因子时,我们需要处理两个特殊的边界情况.当一个可视区域与较大或较小的施加偏移λ的另一个可视区域相邻时,出现这些特殊情况.案例定义如下:

特殊边界案件

特殊边界案例1

施加偏移r可视区域R λ是邻近与,5R的应用的偏移较小的可视区域λ.我们将有条件地设置以下变形因子如下:

特殊边界案例1

上述条件集测试相邻可视区域已被分成较小可视区域的情况.因此,我们需要将受影响的变形因子锁定为1.这是为了确保所有重叠的四边形顶点与较小的相邻可视区域的顶点完全匹配.下图提供了计算边界情况1的变形因子时使用的各种位置的图表.

边界案例1的立场

边界案例2

施加偏移r可视区域λ是相邻的较大可视区域用2R的应用的偏移λ.为了能够测试这种情况,我们需要确保我们有一些关于我们正在渲染的当前可视区域的其他信息.在我们算法的第2阶段,我们需要为每个可视区域存储相对象限代码.现在用它来正确计算较大的相邻可视区域的中心位置.这也允许我们计算与较大的相邻可视区域相邻的可视区域的边缘.我们将根据可视区域的相对象限代码有条件地设置以下变形因子:

基于相对象限码的变形因子 基于相对象限码的变形因子

对于其中一个相邻可视区域没有分裂为相同大小作为当前可视区域和代替例上述组测试条件句的已施加的偏移2R的λ.因此,我们需要将受影响的变形因子锁定为0,以确保所有重叠的四边形顶点与较大的相邻可视区域的顶点完全匹配.下图提供了在根据可视区域的相对象限代码计算边界情况2的变形因子时,每个可视区域使用的各种位置的图表:

边界情况2相对象限代码


好极了!你做到了最后!就像我开始喜欢把头撞在桌子上一样!等等,你问的是什么?代码示例?好吧,当然! 在这里 - 包括VC++ 2008和VC++ 2010版本.请享用!