C++Directx11开发笔记四:着色器之顶点着色器和像素着色器

简介:

前面我们学习了Directx 11如何在屏幕上绘制一个图形(三角形),其中涉及到着色器,我们只是使用了其中的方法,而没有讲解着色器是如何工作的,到底什么是着色器等等,今天将来了解一下着色器到底是什么!!!由于在Directx 11中包含了多种着色器,而有些着色器在一些高级的应用中才会用到,因此作为一个初学者,先了解顶点着色器和像素着色器就OK了,其它的在碰到的时候再进行深入了解。

 

着色器:

在以前的显卡中,图像的呈现就像流水线一样,不能够进行编程。不过后来GPU出现了,那样就可以计算很多东东,也就可以进行编程了,着色器就是一个可编程的例子,他通过代码传给GPU进行计算,然后通过屏幕显示出来。就像在前面的例子中,我们创建了一个缓存数据(Vertex Buffer)将三角形的坐标传给GPU。在Directx 11 SDK中,支持三种基础着色器:顶点着色器(Vertex Shader),像素着色器(Pixel Shader)【注:有些地方也就叫Fragment Shader】,以及几何着色器(Geometry Shader)。顶点着色器通过顶点作为输入数据,只要将每个顶点缓存数据传入GPU就会执行;像素着色器使用一个像素作为输入数据;而几何着色器使用基元(primitive)作为输入,基元可以是一个点,一条线或一个三角形。这三个基础着色器在呈现时都会遇到,在Direct3D 11中,GPU必须包含一个正确的顶点和像素着色器,而几何着色器是可选的,因此这也是为什么我们先了解顶点着色器和像素着色器的原因。当然在DirectX中,还包含了其他着色器,如Hull Shader,Domain Shader(域着色器)用于曲面细分(有些地方叫做镶嵌tessellation),Compute Shader用于计算。

 

顶点着色器:

顶点着色器支持编程,可以把顶点着色器看出是C语言中的一个函数,通过顶点作为参数输入这个函数,并且返回编程后的顶点信息。当程序通过顶点着色器传入顶点缓冲数据时,GPU就会迭代顶点缓冲数据,并为每一个顶点执行一次着色器函数。

顶点着色器可以用了做非常多的事情,最主要的是用了进行坐标变换等等,在Direct3D编程中会涉及到很多坐标的变换,如:将世界坐标转换为屏幕坐标等等。比如一个3D的三角形具有(0, 0, 0) (1, 0, 0) (0, 1, 0)坐标,当被绘制到2D纹理缓冲时GPU就需要知道在2D坐标系里的坐标,那样才知道需要画在什么地方。关于坐标的转换,我们后续还会遇到,这里就不进行讨论,对于前面的例子我们只需要知道传入一个顶点信息,返回一个顶点信息就OK了,具体代码如下:

1      float4 VS( float4 Pos : POSITION ) : SV_POSITION
2      {
3           return  Pos;
4      }

上面的代码就是HLSL,在前面我们也介绍了一下,他的语言像C一样,传入一个float4数据,POSITION是一个声明性字符串,而SV_POSITION具有特殊的声明意义,在HLSL中可以查询到,即是告诉绘图管线这是定义了一个坐标数据。而这个坐标就是GPU需要的知道的,也就是说在哪里绘制。

 

像素着色器:

在现代的显示器中,屏幕是有很多个正方形格子组成的,这些格式很小,我们把它叫做像素,每一个像素都包含着自己的颜色,他们之间不用相互依赖。其实当我们需要在屏幕上绘制一个三角形时,在屏幕上呈现的不切切是一个三角形,如下图所示,我们将会更好的理解。

 

 一个三角形,包含了三个顶点,通过这三个顶点连在一起,即叫做光栅化。GPU首先需要知道哪些像素需要被呈现,然后将这些需要呈现(三角形内部)像素激活并赋予颜色值,像素着色器就是为了计算哪些像素需要的颜色。像素着色器通过输入的像素颜色值,然后计算颜色并且将其返回给绘图管线。像素管线参数一般由几何着色器返回,假如没有几何着色器,比如我们上一节说说的例子,那么就通过顶点着色器返回。

顶点着色器中通过SV_POSITION声明描述创建了一个float4的值用于返回像素的坐标位置,这将作为像素着色器的输入参数,这样就告之了GPU当前坐标,而像素着色器返回的一个颜色值,即也为float4数值,并且使用SV_TARGET声明描述,以表示将用于目标的呈现格式。其代码如下所示:

1      float4 PS( float4 Pos : SV_POSITION ) : SV_Target
2      {
3           return  float4(  1.0f 1.0f 0.0f 1.0f  );     //  Yellow, with Alpha = 1
4      }

 

编译着色器:

着色器编写的代码即HLSL保存在一个文本文件中,可以通过Direct3D 11中的D3DX11CompileFromFile()进行编译,其代码如下所示:

复制代码
1       //  Create the vertex shader
2       if ( FAILED( D3DX11CompileFromFile(  " Tutorial03.fx " , NULL, NULL,  " VS " " vs_4_0 " , D3DCOMPILE_ENABLE_STRICTNESS, NULL, NULL,  & pVSBlob,  & pErrorBlob, NULL ) ) )
3           return  FALSE;
4 
5       //  Create the pixel shader
6       if ( FAILED( D3DX11CompileFromFile(  " Tutorial03.fx " , NULL, NULL,  " PS " " ps_4_0 " , D3DCOMPILE_ENABLE_STRICTNESS, NULL, NULL,  & pPSBlob,  & pErrorBlob, NULL ) ) )
7           return  FALSE;
复制代码

 

绑定着色器:

这样我们就可以在C++代码中通过VSSetShader() 和 PSSetShader()两个方法将顶点着色器和像素着色器绑定到管线上,当我们使用Draw方法时,将顶点缓存信息Vertex Buffer传入到绘图管线中进行绘制,这样关于顶点着色器和像素着色器就了解完毕了。

 

通过这篇文章其实就是了解到两个东东,顶点着色器是告诉管线坐标,而像素着色器是告诉管线颜色,有了这两项东西就可以绘制图形了。当然在实际需求中不可能这么便宜,书写的代码还是挺多的,最主要希望微软也能够将HLSL的言语智能提示继承到VS中,那样我想像我这种写代码的人将会带来很爽的感觉。

 

附:

Directx11管道流水线

 

曲面细分(Tessellator):

从上面这张技术解析图,我们可以很了解到Hull Shader、Tessellator、Domain Shader这3个新单元的具体作用:Hull Shader主要负责定义细分等级(LOD)和相关控制点在细分中的“形变”趋势,需要说明的是这种形变仅仅是类似于曲率改变等小幅度的变化,而非大幅度的多边形位移;Tessellator则负责根据Hull Shader传输下来的信息,通过“暴力”增加多边形去实现Hull Shader的要求;Domain Shader负责的最重要的功能就是通过贴图控制的方式,实现模型的形变,也就是我们大家在DX11的细分曲面中看到的高细节画面。

本文转自网魂小兵博客园博客,原文链接:http://www.cnblogs.com/xdotnet/archive/2011/07/31/directx_direct3d11_shaders.html,如需转载请自行联系原作者

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
2月前
|
机器学习/深度学习 算法 算法框架/工具
为什么使用C++进行机器学习开发
C++作为一种高性能语言,在某些性能要求极高或资源受限的场景下也具有非常重要的地位。C++的高效性和对底层硬件的控制能力,使其在大规模机器学习系统中发挥重要作用,尤其是当需要处理大数据或实时响应的系统时。
44 3
WK
|
14天前
|
机器学习/深度学习 人工智能 算法
那C++适合开发哪些项目
C++ 是一种功能强大、应用广泛的编程语言,适合开发多种类型的项目。它在游戏开发、操作系统、嵌入式系统、科学计算、金融、图形图像处理、数据库管理、网络通信、人工智能、虚拟现实、航空航天等领域都有广泛应用。C++ 以其高性能、内存管理和跨平台兼容性等优势,成为众多开发者的选择。
WK
37 1
|
1月前
|
Rust 资源调度 安全
为什么使用 Rust over C++ 进行 IoT 解决方案开发
为什么使用 Rust over C++ 进行 IoT 解决方案开发
64 7
WK
|
13天前
|
开发框架 移动开发 Java
C++和Java哪个更适合开发移动应用
本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
WK
27 0
WK
|
14天前
|
安全 Java 编译器
C++和Java哪个更适合开发web网站
在Web开发领域,C++和Java各具优势。C++以其高性能、低级控制和跨平台性著称,适用于需要高吞吐量和低延迟的场景,如实时交易系统和在线游戏服务器。Java则凭借其跨平台性、丰富的生态系统和强大的安全性,广泛应用于企业级Web开发,如企业管理系统和电子商务平台。选择时需根据项目需求和技术储备综合考虑。
WK
17 0
|
29天前
|
NoSQL API Redis
如何使用 C++ 开发 Redis 模块
如何使用 C++ 开发 Redis 模块
|
2月前
|
物联网 C# C语言
物联网开发中C、C++和C#哪个更好用
在物联网(IoT)开发中,C、C++和C#各有优缺点,适用场景不同。C语言性能高、资源占用低,适合内存和计算能力有限的嵌入式系统,但开发复杂度高,易出错。C++支持面向对象编程,性能优秀,适用于复杂应用,但学习曲线陡峭,编译时间长。C#易于学习,与.NET框架结合紧密,适合快速开发Windows应用,但性能略低,平台支持有限。选择语言需根据具体项目需求、复杂性和团队技术栈综合考虑。
|
2月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
122 1
|
3月前
|
C++
C++ Qt开发:QUdpSocket网络通信组件
QUdpSocket是Qt网络编程中一个非常有用的组件,它提供了在UDP协议下进行数据发送和接收的能力。通过简单的方法和信号,可以轻松实现基于UDP的网络通信。不过,需要注意的是,UDP协议本身不保证数据的可靠传输,因此在使用QUdpSocket时,可能需要在应用层实现一些机制来保证数据的完整性和顺序,或者选择在适用的场景下使用UDP协议。
139 2
|
2月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
197 0