六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 221|回复: 0

Directx11教程(59) tessellation学习(1)

[复制链接]

升级  91.33%

154

主题

154

主题

154

主题

举人

Rank: 3Rank: 3

积分
474
 楼主| 发表于 2012-10-25 01:16:32 | 显示全部楼层 |阅读模式
Directx11教程(59) tessellation学习(1)

      在D3D11管线中,新增加了3个stage, Hull shader, Tessellator, Domain shader,用来实现细分操作,就是在gpu中把低细节的表面细分成高细节的体元。在gpu中把低模通过tessellation转化为高模,在获得高细节模型的同时,可以有效降低把顶点数据从system memory传到 video memory的带宽消耗。
       下面我们看看这三个阶段到底做些什么,输入是什么,输出是什么?先画一张图。
  
  1、Hull shader阶段
        Hull shader阶段可以分成两个独立的阶段,它们是并行执行的。
        第一个阶段是per control points执行的, 在这个阶段对patch中的每个控制点,输出对应的控制点。所谓patch,简单理解就是带控制点的体元,比如一个三角形,它的三个顶点是控制点,那么这个三角形就是有3个控制点的patch。当然,在Hull shader中,我们还可以对输入的控制点进行转化操作,生成新的控制点,比如输入的3个控制点,输出6个控制点。注意:输入或者输出的控制点数量是1~32。
       第二个阶段就是patch常量阶段,这时HullShader会调用一个const data函数,这个函数主要产生tessellation factor,这些factor决定在TS阶段如何细分当前的patch。
      另外,在Hullshader阶段还会指定一些TS阶段使用的Tessellation模式,比如细分的patch是三角形(拓扑模式),partition mode(选择什么细分算法)是HS_PARTITION等。
  下面看一段Hull shader的代码:
  struct HullInputType
  {
  float3 position : POSITION;
  float4 color : COLOR;
  };
  struct ConstantOutputType
  {
  float edges[3] : SV_TessFactor;
  float inside : SV_InsideTessFactor;
  };
  struct HullOutputType
  {
  float3 position : POSITION;
  float4 color : COLOR;
  };
  // Patch 常量函数,决定tessellation因子,每个patch执行一次,所以是per patch的,不是per控制点的
  ConstantOutputType ColorPatchConstantFunction(InputPatch<HullInputType, 3> inputPatch, uint patchId : SV_PrimitiveID)
  {
  ConstantOutputType output;
  //设置三条边的细分因子
  output.edges[0] = tessellationAmount;
  output.edges[1] = tessellationAmount;
  output.edges[2] = tessellationAmount;
  //设置三角形内的细分因子
  output.inside = tessellationAmount;
  return output;
  }
  //注意输入控制点数量要和 IASetPrimitiveTopology()函数中一致
  //本例子中,都为3 INPUT_PATCH_SIZE
  // The hull shader is called once per output control point, which is specified with
  // outputcontrolpoints. For this sample, we take the control points from the vertex
  // shader and pass them directly off to the domain shader. In a more complex scene,
  // you might perform a basis conversion from the input control points into a Bezier
  // patch, such as the SubD11 Sample of DirectX SDK.
  // The input to the hull shader comes from the vertex shader
  // The output from the hull shader will go to the domain shader.
  // The tessellation factor, topology, and partition mode will go to the fixed function
  // tessellator stage to calculate the UVW and domain points
  
     
   [domain("tri")] //Triangle domain for our shader
  [partitioning("integer")] //Partitioning type according to the GUI
  [outputtopology("triangle_cw")] //Where the generated triangles should face
  [outputcontrolpoints(3)] //Number of times this part of the hull shader will be called for each patch
  [patchconstantfunc("ColorPatchConstantFunction")] //The constant hull shader function
  HullOutputType ColorHullShader(InputPatch<HullInputType, 3> patch, uint pointId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID)
  {
  HullOutputType output;
  //设置控制点
  output.position = patch[pointId].position;
  // 输出颜色为输入颜色
  output.color = patch[pointId].color;
  return output;
  }
  
  2. Tessellator阶段
  &#160;&#160;&#160;&#160;&#160;&#160; Tessellator是一个固定管线阶段,它的主要功能就是细分一个domain(三角形, 四边形或线),把它们细分成很多小的物体,比如三角形,四边形或者线。
  &#160;&#160;&#160;&#160;&#160;&#160; 在细分时,tessellator会在一个归一化的坐标系统中处理patch,比如输入是一个quad(四边形),但这个quad先要映射到一个单位为1的正方形上,然后tessellator会对这个正方形进行细分操作。
  &#160;&#160;&#160;&#160;&#160; Tessellator是per patch操作的,Hull shader阶段传入的Tess Factor决定细分多少次,而Hull shader阶段传入的partitioning则决定选用何种细分算法。Tessellator输出为u,v, {w}坐标以及细分后domain的拓扑信息。
  
  3. Domain Shader阶段
  &#160;&#160;&#160;&#160;&#160;&#160; Domain Shader 阶段会根据TS阶段生成的u,v , {w}坐标以及HS阶段传入的控制点在patch中生成细分后顶点的位置。
  &#160;&#160;&#160;&#160;&#160;&#160; Domain shader是per vertex的,对于TS中每个细分产生的顶点,它都要调用一次。它的输入参数除了u,v,{w}坐标及控制点以外,还有const data,比如Tess factor等。
  
  下面是一段Domain shader的代码:
  struct ConstantOutputType
  {
  float edges[3] : SV_TessFactor;
  float inside : SV_InsideTessFactor;
  };
  struct HullOutputType
  {
  float3 position : POSITION;
  float4 color : COLOR;
  };
  struct PixelInputType
  {
  float4 position : SV_POSITION;
  float4 color : COLOR;
  };
     
   //每个细分后的顶点调用一次
  [domain("tri")]
  PixelInputType ColorDomainShader(ConstantOutputType input, float3 uvwCoord : SV_DomainLocation, const OutputPatch<HullOutputType, 3> patch)
  {
  float3 vertexPosition;
  PixelInputType output;
     
   //基于重心坐标的顶点生成
  vertexPosition = uvwCoord.x * patch[0].position + uvwCoord.y * patch[1].position + uvwCoord.z * patch[2].position;
  // 计算新的顶点在世界坐标系中的位置
  output.position = mul(float4(vertexPosition, 1.0f), worldMatrix);
  output.position = mul(output.position, viewMatrix);
  output.position = mul(output.position, projectionMatrix);
  //新生成顶点颜色也为各个控制点颜色组合
  output.color = uvwCoord.x * patch[0].color + uvwCoord.y * patch[1].color + uvwCoord.z * patch[2].color;
  return output;
  }
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表