原文:Directx11教程(64) tessellation学习(6)-PN Triangles

      前面我们用tessellation细分三角形或者四边形,产生的细分点都是在三角形或四边形平面内。本教程我们学习一下PN triangles(point normal triangles)的方法,把一个三角形细分为一个曲面。PN triangles的详细介绍请参考:2001 paper by Vlachos et al ,下面我们简单介绍一下PN triangles:

     大家都知道,通常我们用贝塞尔函数表示光滑的曲面,贝塞尔函数是多项式函数,它表示的曲面通常也称作贝塞尔曲面,贝塞尔曲面的详细介绍,可以到wiki上看看Bezier Surface

     PN triangle是一个特殊的贝塞尔曲面,它的表示形式为:  

      u,v, w是重心坐标,bxyz就是控制点,其中u+v+w=1,控制点的位置如下,看以看出来,b003, b030,b300就是三角形的三个顶点控制点,根据这三个控制点位置和法向,我们就可以计算出其它控制点的位置。

  

     PN triangles的法向通过下面的方法计算得到:

     下面我们在myTutorialD3D_54的基础上,增加PN triangle支持,用三角形生成曲面。首先修改MeshClass类,为三角形patch顶点结构增加normal属性,因为计算控制点时候需要它。

struct VertexType
    {
    D3DXVECTOR3 position;
    D3DXVECTOR3 normal;
    D3DXVECTOR4 color;
    };

//创建顺时针方向的三角形,左手规则
// 设置顶点数据
vertices[0].position = D3DXVECTOR3(4.0f, 0.0f, -2.0f);  // 左下
vertices[0].normal = D3DXVECTOR3(-1.0f, 1.0f, 0.0f);
vertices[0].color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);

vertices[1].position = D3DXVECTOR3(6.0f, 0.0f, 4.0f);  // 中上.
vertices[1].normal = D3DXVECTOR3(0.0f, 1.0f, 1.0f);
vertices[1].color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);

vertices[2].position = D3DXVECTOR3(8.0f, 0.0f, -2.0f);  // 底右
vertices[2].normal = D3DXVECTOR3(1.0f, 1.0f, 0.0f);
vertices[2].color = D3DXVECTOR4(0.0f, 1.0f, 1.0f, 1.0f);

       接下来,修改TessShaderClass类,修改顶点布局,增加normal支持:

polygonLayout[1].SemanticName = "NORMAL";
polygonLayout[1].SemanticIndex = 0;
polygonLayout[1].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[1].InputSlot = 0;
polygonLayout[1].AlignedByteOffset = 12;
polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate = 0;

       接着就是shader 文件的修改,这也是最关键的部分,下面看看各个shader文件,vs中基本就是pass through,把顶点属性传到hs,和以前比没有太多的变化,hs中增加了生成新控制点的代码:

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;

   // PN triangle三个控制顶点的位置,和三角形patch的原始控制点是一样的
    float3 f3B003 = inputPatch[0].position;
    float3 f3B030 = inputPatch[1].position;
    float3 f3B300 = inputPatch[2].position;

   
    // 法向
    float3 f3N002 = inputPatch[0].normal;
    float3 f3N020 = inputPatch[1].normal;
    float3 f3N200 = inputPatch[2].normal;

       
    // 根据公式计算边控制点和中心控制点
    output.f3B210 = ( ( 2.0f * f3B003 ) + f3B030 - ( dot( ( f3B030 - f3B003 ), f3N002 ) * f3N002 ) ) / 3.0f;
    output.f3B120 = ( ( 2.0f * f3B030 ) + f3B003 - ( dot( ( f3B003 - f3B030 ), f3N020 ) * f3N020 ) ) / 3.0f;
    output.f3B021 = ( ( 2.0f * f3B030 ) + f3B300 - ( dot( ( f3B300 - f3B030 ), f3N020 ) * f3N020 ) ) / 3.0f;
    output.f3B012 = ( ( 2.0f * f3B300 ) + f3B030 - ( dot( ( f3B030 - f3B300 ), f3N200 ) * f3N200 ) ) / 3.0f;
    output.f3B102 = ( ( 2.0f * f3B300 ) + f3B003 - ( dot( ( f3B003 - f3B300 ), f3N200 ) * f3N200 ) ) / 3.0f;
    output.f3B201 = ( ( 2.0f * f3B003 ) + f3B300 - ( dot( ( f3B300 - f3B003 ), f3N002 ) * f3N002 ) ) / 3.0f;

    float3 f3E = ( output.f3B210 + output.f3B120 + output.f3B021 + output.f3B012 + output.f3B102 + output.f3B201 ) / 6.0f;
    float3 f3V = ( f3B003 + f3B030 + f3B300 ) / 3.0f;
    output.f3B111 = f3E + ( ( f3E - f3V ) / 2.0f );

   // 计算法向控制点
    float fV12 = 2.0f * dot( f3B030 - f3B003, f3N002 + f3N020 ) / dot( f3B030 - f3B003, f3B030 - f3B003 );
    output.f3N110 = normalize( f3N002 + f3N020 - fV12 * ( f3B030 - f3B003 ) );
    float fV23 = 2.0f * dot( f3B300 - f3B030, f3N020 + f3N200 ) / dot( f3B300 - f3B030, f3B300 - f3B030 );
    output.f3N011 = normalize( f3N020 + f3N200 - fV23 * ( f3B300 - f3B030 ) );
    float fV31 = 2.0f * dot( f3B003 - f3B300, f3N200 + f3N002 ) / dot( f3B003 - f3B300, f3B003 - f3B300 );
    output.f3N101 = normalize( f3N200 + f3N002 - fV31 * ( f3B003 - f3B300 ) );

    return output;
}

    在ds中,我们根据PN triangle公式生成新的控制点:

    //重心坐标
    float fU = uvwCoord.x;
    float fV = uvwCoord.y;
    float fW = uvwCoord.z;

   // 预计算一些需要的值
    float fUU = fU * fU;
    float fVV = fV * fV;
    float fWW = fW * fW;
    float fUU3 = fUU * 3.0f;
    float fVV3 = fVV * 3.0f;
    float fWW3 = fWW * 3.0f;
    //根据公式和重心坐标计算细分后顶点的位置
    float3 f3Position = patch[0].position * fWW * fW +
                        patch[1].position * fUU * fU +
                        patch[2].position * fVV * fV +
                        input.f3B210 * fWW3 * fU +
                        input.f3B120 * fW * fUU3 +
                        input.f3B201 * fWW3 * fV +
                        input.f3B021 * fUU3 * fV +
                        input.f3B102 * fW * fVV3 +
                        input.f3B012 * fU * fVV3 +
                        input.f3B111 * 6.0f * fW * fU * fV;

    
    //计算新的顶点在世界坐标系中的位置
    output.position = mul(float4(f3Position, 1.0f), worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);

    // 计算法向
    float3 f3Normal =   patch[0].normal * fWW +
                        patch[1].normal * fUU +
                        patch[2].normal * fVV +
                        input.f3N110 * fW * fU +
                        input.f3N011 * fU * fV +
                        input.f3N101 * fW * fV;

    // 归一化   
    f3Normal = normalize( f3Normal );

    output.normal = f3Normal;

    //新生成顶点颜色也为各个控制点颜色组合
    output.color = uvwCoord.x * patch[0].color + uvwCoord.y * patch[1].color + uvwCoord.z * patch[2].color;

     程序执行后界面如下,其中tess factor 从1到6,可以看出来,随着细分因子的增大,三角形越接近曲面。

完整的代码请参考:

工程文件myTutorialD3D11_59

代码下载:

稍后提供

Directx11教程(64) tessellation学习(6)-PN Triangles的更多相关文章

  1. Directx11教程(60) tessellation学习(2)

    原文:Directx11教程(60) tessellation学习(2)        本教程中,我们开始tessellation编程,共实现了2个程序,第一个tessellation程序,是对一个三 ...

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

    原文:Directx11教程(59) tessellation学习(1)       在D3D11管线中,新增加了3个stage, Hull shader, Tessellator, Domain s ...

  3. Directx11教程(63) tessellation学习(5)

    原文:Directx11教程(63) tessellation学习(5)        TS中生成细分后顶点的u,v,{w}坐标,我们根据控制点和u,w,{w}坐标生成新的顶点位置,在前面四边形的细分 ...

  4. Directx11教程(62) tessellation学习(4)

    原文:Directx11教程(62) tessellation学习(4)       现在看看四边形在不同tess factor时,四边形细分的细节,下图是tess factor1-8时候的细分.te ...

  5. Directx11教程(61) tessellation学习(3)

    原文:Directx11教程(61) tessellation学习(3)       现在我们看看在不同tess factor的情况下,三角形是如何细分的?(这儿三条边和内部tess factor值是 ...

  6. Directx11教程(15) D3D11管线(4)

    原文:Directx11教程(15) D3D11管线(4) 本章我们首先了解一下D3D11中的逻辑管线,认识一下管线中每个stage的含义. 参考资料:http://fgiesen.wordpress ...

  7. Directx11教程(16) D3D11管线(5)

    原文:Directx11教程(16) D3D11管线(5) 本章我们学习VS中具体做些什么事情? 首先再看看我们的VS shader代码: Clolor.vs - PixelInputType Col ...

  8. Directx11教程(66) D3D11屏幕文本输出(1)

    原文:Directx11教程(66) D3D11屏幕文本输出(1)      在D3D10中,通过ID3DX10Font接口对象,我们可以方便的在屏幕上输出文字信息,一个DrawText函数就能解决所 ...

  9. Directx11教程(56) 建立一个skydome

    原文:Directx11教程(56) 建立一个skydome       本章建立一个skydome(天空穹),主要学习如何使用cube mapping.      cube map就是把六张纹理当作 ...

随机推荐

  1. LUOGU 9月 月赛

    T1 签到题 传送门 解题思路 将原式化简一下,让n个1变成 (10^n-1)/9 ,然后再移项,变成了高次同余形式,用bsgs求解.交了好几次都是80,后来才被告知要快速乘. 代码 #include ...

  2. Java 容易疑惑的一些杂记录

    1 final.finally和finalize final 是一个关键字 ,final 修饰 对象不能被修改,final 修饰的方法不能被重写,final 修饰的 类 不能被继承. finally ...

  3. PHP中的符号 ->、=> 和 :: 的含义(用法)

    php新手经常碰到的问题,->.=> 和 :: 这三个家伙是什么分别都是做什么的啊!看着就很晕. 没关系,下面我们做一下详细的解释,如果你有C++,Perl基础,你会发现这些家伙和他们里面 ...

  4. Java正则表达式实例详解

    创建正则表达式 你可以从比较简单的东西入手学习正则表达式.要想全面地掌握怎样构建正则表达式,可以去看JDK 文档的java.util.regex 的Pattern 类的文档. 字符 B 字符B \xh ...

  5. 在云计算环境中使用Hadoop

  6. 初学linux时遇到的那些哭笑不得的问题

    1.终端中无法输入密码? 在终端输入密码,是不会在输入密码的时候看见星号或者圆点符号的.它不会有任何输入密码的视觉指示,也不会有任何光标移动,什么也不显示. 其实是输进去了,只是没有明文显示出来而已. ...

  7. javascript基础:语法与html结合方式

    一.基本语法: 1.与html结合方式 1.内部JS: *  定义<script>,标签体内容就是JS代码 2.外部JS: *  定义<script>,通过src属性引入外部的 ...

  8. TZOJ 4021 Ugly Problem(线段树区间子段最大)

    描述 给定一个序列A[0],A[1],…A[N-1],要求找到p0,p1,p2,p3使得A[p0]+A[p0+1]+…+A[p1] + A[p2]+A[p2+1]+…+A[p3]最大(0<=p0 ...

  9. 跟我一起做一个vue的小项目(APPvue2.5完结篇)

    先放一下这个完结项目的整体效果 下面跟我我一起进行下面项目的进行吧~~~ 接下来我们进行的是实现header的渐隐渐显效果,并且点击返回要回到首页 我们先看效果 在处理详情页向下移动过程中,heade ...

  10. 超干货!Cassandra Java堆外内存排查经历全记录

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...