几何着色器是从DirectX 10才引入的着色器,是一个可选阶段,位于顶点着色器和像素着色器阶段之间。顶点着色器以顶点作为输入数据,而几何着色器以完整的图元作为输入数据,像点、直线、三角形等。之所以引进几何着色器是为了充分利用GPU的计算能力来生成几何结构和模型细节,减轻CPU的负担,让CPU更专注于逻辑控制。几何着色器的编程和其它着色器类似,在VS2012中默认生成的几何着色器代码如下:

struct GSOutput
{float4 pos : SV_POSITION;
};[maxvertexcount(3)]
void main(triangle float4 input[3] :SV_POSITION,inout TriangleStream<GSOutput > output
)
{for (uint i = 0; i < 3;i++){GSOutputelement;element.pos =input[i];output.Append(element);}
}

这部分代码没有对顶点进行任何处理,主要注意下几何着色器与其它着色器不同的地方:maxvertexcount用来说明几何着色器所能输出顶点的最大数量,因为几何着色器每次输出的顶点数目可以不同。而triangle则说明输入是一个三角形图元,input[3]表明每次读入三角形的三个顶点。TriangleStream说明输出是一个流类型的对象,它是一个描述三角形的顶点列表,在main方法中构造好一个顶点后,使用Append方法将其加入列表。关于几何着色器更详细的介绍当然还得参考书籍和MSDN,接下来就实现一个用几何着色器对三角形进行细分的效果。

可以看出,把一个三角形细分成四个三角形,总的顶点数增加一倍。(写到这里突然想到游戏中常用的材质细节选项,不知道是不是通过设置不同的细分参数来区别。)知道基本方法后就可以进行代码的编写。这次是对第十二篇实现的模型进行细分。

首先向项目中添加几何着色器,并重命名为SimpleGeometryShader。注意这里需要更改编译选项,之前的着色器模型是 4 级别 9_3 (/4_0_level_9_3),而几何着色器是在DirectX 10中才引入的,所以要更改着色器模型为4 (/4_0)。

然后要修改几何着色器中的结构体定义,与顶点着色器对应:

struct VertexShaderOutput
{float4 posH : SV_POSITION;float3 posW   : POSITION;float3 normal : NORMAL;float2 tex : TEXCOOD;float2 texa :TEXCOOD_ALPHA;
};struct GSOutput
{float4 posH : SV_POSITION;float3 posW : POSITION;float3 normal : NORMAL;float2 tex : TEXCOOD;float2 texa :TEXCOOD_ALPHA;uint   PrimID : SV_PrimitiveID;
};

几何着色器的输入是顶点着色器的输出,所以几何着色器的main方法定义如下:

// 将输入三角形分割为四个小三角形
[maxvertexcount(8)]
void main(triangle VertexShaderOutputinput[3],inout TriangleStream<GSOutput > output)

在main方法中进行计算时与其它着色器没什么区别。首先生成5个数组,对应结构体的5个属性,而每个数组均包含6个元素,对应之前图中的6个顶点。

  // v1,v2,v3是原始顶点,m0,m1,m2是各边中点////     示意图          新数组中的序号//       v1              5//       *               *//      / \             / \//     /  \            / a \//  m0*-----*m1      1*-----*3//   / \  / \        / \ c / \ //  /   \/   \      / b \ / d \// *-----*-----*   *-----*-----*//v0    m2    v2   0     2     4float4 ph[6];ph[0] =input[0].posH;ph[1] =0.5f*(input[0].posH + input[1].posH);ph[2] =0.5f*(input[2].posH + input[0].posH);ph[3] =0.5f*(input[1].posH + input[2].posH);ph[4] =input[2].posH;ph[5] =input[1].posH;float3 pw[6];pw[0] =input[0].posW;pw[1] =0.5f*(input[0].posW + input[1].posW);pw[2] =0.5f*(input[2].posW + input[0].posW);pw[3] =0.5f*(input[1].posW + input[2].posW);pw[4] =input[2].posW;pw[5] =input[1].posW;float3 n[6];n[0] =input[0].normal;n[1] =normalize(input[0].normal + input[1].normal);n[2] =normalize(input[2].normal + input[0].normal);n[3] =normalize(input[1].normal + input[2].normal);n[4] =input[2].normal;n[5] =input[1].normal;float2 t[6];t[0] =input[0].tex;t[1] =0.5f*(input[0].tex + input[1].tex);t[2] =0.5f*(input[2].tex + input[0].tex);t[3] =0.5f*(input[1].tex + input[2].tex);t[4] =input[2].tex;t[5] =input[1].tex;float2 ta[6];ta[0] =input[0].texa;ta[1] =0.5f*(input[0].texa + input[1].texa);ta[2] =0.5f*(input[2].texa + input[0].texa);ta[3] =0.5f*(input[1].texa + input[2].texa);ta[4] =input[2].texa;ta[5] =input[1].texa;

生成所有需要的信息后就可以输出小三角形了。

// 画分割后的小三角形bcd
for(int i = 0; i < 5;++i)
{ gOut.posH =ph[i];gOut.posW =pw[i];gOut.normal =n[i];gOut.tex =t[i];gOut.texa =ta[i];output.Append(gOut);
}

细分后下面的一排三角形b、c、d是连续的,构成三角形带,可以只循环5次。而上面的三角形a需要单独输出。


output.RestartStrip();// 画分割后的小三角形a
gOut.posH =ph[1];
gOut.posW =pw[1];
gOut.normal =n[1];
gOut.tex = t[1];
gOut.texa = ta[1];
output.Append(gOut);gOut.posH =ph[5];
gOut.posW =pw[5];
gOut.normal =n[5];
gOut.tex = t[5];
gOut.texa =ta[5];
output.Append(gOut);gOut.posH =ph[3];
gOut.posW =pw[3];
gOut.normal =n[3];
gOut.tex = t[3];
gOut.texa =ta[3];
output.Append(gOut);

开始调用RestartStrip方法用来结束三角形带,重新开始输出顶点序列,让后面添加的三个顶点构成三角形。

至此,几何着色器的代码编写完成,而顶点着色器和像素着色器均无需更改,接下来就修改C++代码。首先为Renderer类添加新成员:

Microsoft::WRL::ComPtr<ID3D11GeometryShader> m_geometryShader;

然后在CreateDeviceResources方法中添加以下代码以载入几何着色器

auto loadGSTask = DX::ReadDataAsync("SimpleGeometryShader.cso");
auto createGSTask = loadGSTask.then([this](Platform::Array<byte>^ fileData) {DX::ThrowIfFailed(m_d3dDevice->CreateGeometryShader(fileData->Data,fileData->Length,nullptr,&m_geometryShader));});

现在开始就能够在程序中使用几何着色器了。在Render方法中设置顶点着色器后面添加下面的代码,用来设置几何着色器:

// 设置几何着色器m_d3dContext->GSSetShader(m_geometryShader.Get(),nullptr,0);

另外,为了看清细分与不细分的区别,将水面设置为线框渲染模式,并改变了下观察角度。对比图如下:

上面是细分后的效果,下面是未细分的效果。

本篇文章源代码:Direct3DApp_HillWaveGS

原文地址:http://blog.csdn.net/raymondcode/article/details/8503985

Windows 8 Directx 开发学习笔记(十四)使用几何着色器实现三角形细分相关推荐

  1. Windows 8 Directx 开发学习笔记(四)示例程序小结

    VS2012的示例程序包括了最基本的DirectX流程,涉及许多知识,所以看完代码之后还是感觉没有头绪,打算对整个过程再整理一下,方便进一步的学习. 正方体在空间中可以用它的8个顶点定义,而每个顶点可 ...

  2. Polyworks脚本开发学习笔记(十四)-WORKSPACE信息读取及管理

    Polyworks脚本开发学习笔记(十四)-WORKSPACE信息读取及管理 Polyworks的工作任务存储分为工作区和项目两级,通过WORKSPACE命令获取工作任务信息,实现更好的任务管理. 下 ...

  3. Windows 8 DirectX 开发学习笔记(十五)使用Billboard实现树木贴图

    要使用DirectX来获得三维效果,一般首先要生成一个三维模型,然后计算它在可视空间中的投影.这样得到的二维图像十分真实,但是计算量也很大.在大规模场景渲染中,随着模型精度的提高,这样的处理方式十分消 ...

  4. Windows 8 Directx 开发学习笔记(十二)利用混合实现浮在水面的木箱

    在场景中绘制多个不透明物体时很简单,哪个物体离得近,看到的就是哪个物体.但如果加入一个透明的物体,像玻璃,如何渲染就有些麻烦.拿一块红色的玻璃挡住眼睛,看到的物体都偏红,换成蓝色的玻璃,物体都偏蓝.D ...

  5. Windows 8 Directx 开发学习笔记(十)纹理贴图实现旋转的木箱

    纹理贴图映射(texturemapping)是可以显著提高场景细节和真实感的一种技术,基本原理是将图像数据映射到3D三角形表面(之前的文章提到过,三维模型其实是由很多个三角形拼接而成).当使用纹理资源 ...

  6. Windows 8 Directx 开发学习笔记(十三)利用模板实现木箱镜像

    假设墙上有一面镜子,镜子前面有个木箱.如果观察角度合适,整个木箱镜像都会在镜子里,计算起来还比较简单:而变换个角度,木箱的镜像可能只有一部分在镜子里,这时单纯依靠计算来实现就很麻烦.DirectX提供 ...

  7. Windows 8 Directx 开发学习笔记(二)建立模型及初始化设备

    上一篇中介绍的DirectxApp类给整个应用搭建了一个框架,而这篇文章涉及的CubeRenderer类则是负责填充框架,呈现实际内容:一个旋转的彩色立方体.CubeRenderer类中的方法通过名称 ...

  8. Windows 8 Directx开发学习笔记(一)应用基本框架

    Windows 8系统10月25日就要正式发布,其应用可与Windows Phone 8应用兼容,所以打算转到Windows 8系列的开发.之前虽然开发过应用,但对游戏开发更感兴趣,随意开始学习Met ...

  9. Windows 8 Directx 开发学习笔记(十一)地形纹理贴图

    前一篇实现木箱贴图时,木箱的六个面都正好用一整张纹理图,即六个面的纹理坐标均在[0,1]内.然而在为比较大的模型贴图时,像山峰河谷模型,如果只用一张纹理图,那么每个三角形只得到几个纹理元素,无法为提供 ...

最新文章

  1. interface declaration, parcelable declaration, AidlTokenType.import or AidlTokenType.package ...
  2. unity 4种实现动态障碍方法
  3. 准确检测图像的轮廓 opencv_图像处理案例实战
  4. linux php环境搭建 图文教程,linux php环境搭建教程
  5. oracle外部结合,浅谈Oracle外部文件
  6. WPS Android版API
  7. 拜耳再投4亿元提升在华处方药产能;阿斯利康进博会公布新冠疫苗最新进展 | 美通企业日报...
  8. [iOS]寻找superView
  9. 全角字符空格(可复制使用)
  10. 1330: PIPI的乐高积木
  11. 【MySQL】MySQL 存储引擎、索引、锁、集群
  12. 计算机伦理的发展,人工智能技术发展的伦理困境研究
  13. 改了计算机名oracle,修改计算机名字导致oracle连接不上的解决方案
  14. 【干货】S7-PLCSIM Advanced V3.0 无法下载组态(搜索到设备地址为红色)问题解决方法
  15. ICSE (2022). Nessie的阅读记录
  16. 聊聊接口性能优化的11个小技巧
  17. OSI7层网络模型协议精析
  18. Java Development - String
  19. PJblog教程:无缝滚动友情连接菜单
  20. HDU 3234 Exclusive-OR

热门文章

  1. autojs长按坐标没反应_Auto.js 一个主要由无障碍服务实现的不需要Root权限的类似按键精灵的自动操作软件...
  2. mysql分组按天统计数据_MySql按周,按月,按日分组统计数据
  3. 【三次握手、四次挥手流程】及【长短链接区别】
  4. nosetest忽略执行指定文件方法
  5. C++类所占大小的问题
  6. sonarqube汉化
  7. 八年测开经验面试28K公司后,吐血整理出高频面试题和答案
  8. python开发内部管理系统_GitHub - JEmbrace/ZYPCManageSystem: 工作室的]内部管理平台
  9. 百度地图 绘制运动轨迹_百度地图创新破局:声音个性表达、出行精准预估与全球无碍...
  10. 现网问题排查实战:Jstat,Jstack,Jmap