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,如需转载请自行联系原作者

相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
相关文章
|
16天前
|
开发框架 Linux C语言
C、C++、boost、Qt在嵌入式系统开发中的使用
C、C++、boost、Qt在嵌入式系统开发中的使用
29 1
|
21天前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
30 0
|
1月前
|
网络协议 C++
C++ Qt开发:QTcpSocket网络通信组件
`QTcpSocket`和`QTcpServer`是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QTcpSocket`组件实现基于TCP的网络通信功能。
37 8
C++ Qt开发:QTcpSocket网络通信组件
|
27天前
|
监控 C++
C++ Qt开发:QProcess进程管理模块
Qt是一个跨平台的C++图形库,简化了窗体应用开发,支持通过拖放组件提升效率。本章节关注`QProcess`组件,它用于控制和管理进程,例如执行命令、运行可执行文件及与外部进程通信。`QProcess`提供多种方法如`start`、`waitForStarted`和`waitForFinished`等,实现启动、监控和交互。示例展示了如何使用`QProcess`获取系统进程和信息,通过`tasklist`和`systeminfo`命令,并将结果展示在`QTreeWidget`中。
28 0
C++ Qt开发:QProcess进程管理模块
|
29天前
|
编译器 测试技术 API
C++库开发之道:实践和原则(三)
C++库开发之道:实践和原则
71 0
|
29天前
|
存储 缓存 安全
C++库开发之道:实践和原则(二)
C++库开发之道:实践和原则
45 0
|
29天前
|
安全 API C++
C++库开发之道:实践和原则(一)
C++库开发之道:实践和原则
45 0
|
30天前
|
存储 C++ 网络架构
C++ Qt开发:QUdpSocket实现组播通信
Qt教程:使用`QUdpSocket`实现UDP组播通信。通过设置套接字选项、绑定端口、加入和离开组播组,以及发送和接收数据报,简化跨平台窗体应用开发。关键函数包括`setSocketOption`设置多播TTL,`bind`绑定地址和端口,`joinMulticastGroup`加入组播,`leaveMulticastGroup`退出,`writeDatagram`发送,和`readDatagram`接收数据报。
16 1
C++ Qt开发:QUdpSocket实现组播通信
|
30天前
|
存储 网络安全 C++
C++ Qt开发:QUdpSocket网络通信组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QUdpSocket`组件实现基于UDP的网络通信功能。与`QTcpSocket`组件功能类似,`QUdpSocket`组件是 Qt 中用于实现用户数据报协议(UDP,User Datagram Protocol)通信的类。UDP 是一种无连接的、不可靠的数据传输协议,它不保证数据包的顺序和可靠性,但具有低延迟和简单的特点。
19 0
C++ Qt开发:QUdpSocket网络通信组件
|
1月前
|
缓存 网络安全 调度
C++ Qt开发:QNetworkAccessManager网络接口组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QNetworkAccessManager`组件实现Web网页访问。QNetworkAccessManager是Qt网络模块中的关键类,用于管理网络访问和请求。作为一个网络请求的调度中心,它为Qt应用程序提供了发送和接收各种类型的网络请求的能力,包括常见的GET、POST、PUT、DELETE等。这个模块的核心功能在于通过处理`QNetworkReply`和`QNetworkRequest`来实现
21 0
C++ Qt开发:QNetworkAccessManager网络接口组件