Lesson 10: 着色器

Lesson 14: SDK文档:Tutorial02 Rendering a Triangle分析 结构体声明:// Structures struct SimpleVertex { D3DXVECTOR3 Pos; };全局变量声明:// Global Variables HINSTANCE g_hInst = NULL; //实例句柄 HWND g_hWnd = NULL; //窗口句柄 D3D10_DRIVER_TY 阅读详情

原文地址:
http://blog.youkuaiyun.com/sinat_24229853/article/details/46941927

Direct3D要求使用着色器来渲染几何图形,为了解着色器的由来,我们首先要了解下图形流水线的历史。

图形流水线是什么?
图形流水线是GPU(图形处理器,显卡的心脏)工作的通用模型。它以某种形式表示的三维场景或物体为输入,输出二维的光栅化图像到显示器。

光栅化,就是把顶点数据转换为片元的过程。片元中的每一个元素对应于帧缓冲区中的一个像素。见下图
这里写图片描述

固定图形流水线有哪些流程?
1.图形流水线的起点是一个三维模型,三维模型中的顶点列表即是流水线的输入数据,从起点进入流水线。
2.顶点可以用来形成多边形,从而拟出近似的表面。由顶点形成多边形最常用的一种方法就是三角化,即每相邻的三个点组成一个三角形。接下来每个顶点要经过一系列的逐顶点操作,比如计算每个顶点的光照,每个顶点的坐标变换等。
3.由于显示输出的需要,用户会定义一个视口,即观察模型的位置和角度,然后模型被投影到与视口观察方向垂直的平面上。这个投影变换也是硬件加速的。根据视域的大小,投影的结果有可能被裁剪(clipping)。
4.接受模型投影的平面是一个帧缓存,它是一个由像素定义的光栅化平面。光栅化(rasterization)的过程,实际上就是决定帧缓存上的哪些像素该取怎样的值。通过采样和插值,光栅化器会决定一幅最接近原投影图像的位图。
5.这些像素或者由像素连成的片段还须经历一些逐片段操作,也就是说,它们的颜色也可以根据算法改变。另外,纹理映射在这一阶段也会覆盖某些像素的值。另外,对于投影和光栅化的结果,还要判断片段的可见性,也就是遮挡探测(occlusion detection)。
6.最后帧缓存里的结果被刷新到显示器上。该过程以较高的帧频率重复,用户就能在显示器上看到连续的图形变换。

这个过程可以简要地表示为图1-5所示的流水线。从顶点列表到最终显示,三维模型主要经历了逐顶点操作、投影变换、裁剪、光栅变换和逐片段操作,最后输出显示。随着日益复杂的图形处理要求和不断完善的硬件加速性能,有越来越多的功能被添加到图形流水线中,下图只概括了流水线的基本功能。
这里写图片描述

可编程图形流水线是什么?
下图表示一个可编程图形流水线,其中已经略去了与经典GPGPU方法无关的模块。流水线的功能模块用箭头串起来,表示工序流动的方向。灰色的模块为可编程模块。当然,除了图上所给出的模块之外,它还有其他的模块。这里,除了我们已经熟悉的这条流水线,图下图还添加了另一个重要的模块──纹理缓存(Texture Buffer)。
这里写图片描述
图中的两个着色器模块被涂成了灰色,这是为了引入一个重要的概念:可编程图形流水线。从结构上来说,上图的流水线模型从应用程序到帧缓存的部分同固定图形流水线中的功能一一对应,只是OpenGL使用了不同的术语来指代这些流水线组件和硬件之间的对应关系。支持可编程图形流水线的GPU就是可编程图形处理器。2001年之前,GPU都是功能固定的,或者是可设置的(configurable)。可编程GPU与它们最大的区别是,用户可以用自定义的算法来实现着色器的功能。在可编程图形流水线中,有两个模块是可以让用户加载自定义算法的,它们是顶点着色器和片段着色器。

着色器是什么?
着色器(shader),又叫着色单元,实际上就是GPU的处理器。一般情况下,一个GPU会有多个处理器(几十个甚至几百个),它们同时工作,体现了GPU大规模并行处理的能力。进行几何计算的处理器叫顶点着色器,它负责对顶点进行坐标变换、投影变换等;进行片段的颜色处理的叫做片段着色器(Direct3D中称其为像素着色器)。应用程序输入GPU的是三维的点云数据。从流水线输入端直到顶点着色器,流水线计算的对象都是三维几何模型;从光栅化器开始,所有的操作都是针对二维的像素了。

加载着色器需要以下步骤:
1.编译着色器:
我们首先需要编译两个着色器,顶点着色器以及像素着色器,这是渲染所需要用到的两个着色器。

我们通过调用D3DX11CompileFromFile()来完成编译,
函数的原型如下:

HRESULT D3DX11CompileFromFile(
    LPCTSTR pSrcFile,                // file containing the code
    D3D10_SHADER_MACRO *pDefines,    // advanced
    LPD3D10INCLUDE pInclude,         // advanced
    LPCSTR pFunctionName,            // name of the shader's starting function
    LPCSTR pProfile,                 // profile of the shader
    UINT Flags1,                     // advanced
    UINT Flags2,                     // advanced
    ID3DX11ThreadPump *pPump,        // advanced
    ID3D10Blob **ppShader,           // blob containing the compiled shader
    ID3D10Blob **ppErrorMsgs,        // advanced
    HRESULT *pHResult);              // advanced

第一个参数,HLSL着色器代码的载入和编译路径。
第二个参数,在着色器代码中的全局宏,该宏在HLSL 着色器中的工作方式与 C/C++中的宏一样。在应用程序内定义 HLSL 宏,使用类型D3D_SHADER_MACRO。
第三个参数,一个可选参数,用于用于处理 HLSL 着色器文件中的#include 语句。这个接口的主要作用就是在包含它的着色器源代码中打开和关闭文件。
第四个参数,你所编译的着色器入口函数名。一个文件可以包含多个着色器类型(例如,顶点,像素,几何着色器等)和用于多种目的的多个函数。
第五个参数,具体的着色器模型,对于我们的目的可以使用 vs_4_0或者vs_5_0来代表使用着色器 4.0 或者 5.0。为了支持着色器模型 5.0,必须需要支持 DirectX 11 的图形硬件单元。
第六个参数,着色编译标识。
第七个参数,特效文件标识,如果我们编译的着色器使用了特效文件就需要设置它。
第八个参数,指向一个线程 pump 的指针。若是设置为 NULL,则当编译完成时函数将返回。此参数处理多线程,在游戏开发中是一个很热门和高级的主题。使用线程允许我们异步加载着色器,调用此函数未返回时,可以继续后面的代码执行。
第九个参数,存放着色器编译完成后字节码的内存地址,它还包括所编译的着色器的任何调试和符号表信息。
第十个参数,存放编译过程中产生的错误和警告信息的内存地址。如果编译过程没有错误发生则该参数对象为 NULL,如果我们使用它来报告错误我们能够准备它。
第十一个参数,线程 pump 的返回值,如果线程 pump(第八个参数)不为 NULL,则该参数在异步执行完成前必须是一个有效地址。

使用例子:

ID3D10Blob *VS, *PS;
D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

ID3D10Blob:blob是任意长度的内存块,以字节计,常用于诸如vertex buffer、adjacency以及shader code等数据。

我们将这段代码放在一个新的函数中:

void InitPipeline()
{
    // load and compile the two shaders
    ID3D10Blob *VS, *PS;
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);
}

2.将两个着色器封装到shader objects中:
每个着色器都被储存在了各自的COM接口对象中,这系列COM接口为ID3D11_____Shader:

// global
ID3D11VertexShader *pVS;    // the vertex shader
ID3D11PixelShader *pPS;     // the pixel shader

当我们有了这些接口之后,我们就可以像这样创建对象了:

void InitPipeline()
{
    // load and compile the two shaders
    ID3D10Blob *VS, *PS;
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

    // encapsulate both shaders into shader objects
    dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
    dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
}

3.绑定着色器:
通过调用Direct3D设备环境的VSSetShader函数来设置顶点着色器,调用PSSetShader来设置像素着色器。这两个函数都采用着色器作为参数,一个类型实例数组指针,和该数组的大小。

就像这样:

void InitPipeline()
{
    // load and compile the two shaders
    ID3D10Blob *VS, *PS;
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

    // encapsulate both shaders into shader objects
    dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
    dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

    // set the shader objects
    devcon->VSSetShader(pVS, 0, 0);
    devcon->PSSetShader(pPS, 0, 0);
}

记住pVS和pPS都是对象,所以我们最后必须对其进行释放:

void CleanD3D(void)
{
    swapchain->SetFullscreenState(FALSE, NULL);    // switch to windowed mode

    // close and release all existing COM objects
    pVS->Release();
    pPS->Release();
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}
Unity6自定义渲染管线实战:从零构建LiteRP与RenderGraph应用 渲染管线是实时图形应用的核心架构,它定义了从三维场景数据到最终屏幕像素的完整绘制流程。其基本原理在于通过CPU组织渲染命令,由GPU执行顶点处理、光栅化、像素着色等阶段。掌握自定义渲染管线技术,对于实现独特的视觉风格、深度优化渲染性能以及适配特定硬件平台具有极高的工程价值,广泛应用于高性能游戏、XR应用及专业可视化领域。本文聚焦于Unity6的可编程渲染管线(SRP)框架,通过构建轻量级渲染管线LiteRP,深入解析了现代声明式渲染架构RenderGraph与智能资源管理组件RTHandleSystem的核 阅读详情

相关推荐

OpenGL入门视频教程合集(Lesson1-Lesson5)

本章详细讲解了OpenGL中最基础的图形绘制操作,包括点、线、多边形的绘制方式,以及如何设置它们的样式属性。通过代码示例展示了如何绘制单个图形元素,并进一步将它们组合起来构建更复杂的图形结构。最后,我们通过一个简单的旋转动画示例,引入了动画的基本实现机制,为后续章节的图形变换打下基础。默认情况下,旋转是围绕原点进行的。如果我们希望绕物体自身的中心旋转,需要先将物体平移到原点,旋转后再平移回去。示例:绕自身中心旋转// 先平移到原点// 旋转// 再平移回原位置。

weixin_28729843的博客 1037

DirectX11笔记(十二)--Direct3D渲染8--EFFECTS

效果框架

冠位仓鼠--慕白 1230

EMC测试案例分析——晶振对辐射发射的影响

本文分析了某产品350MHz辐射发射超标问题,发现源头是50MHz晶振的7次谐波通过连接器泄漏。主要原因是:1)防水非导电垫圈形成屏蔽缝隙;2)晶振下方地平面不完整且信号线穿过;3)晶振离接口过近。改进措施包括:完善晶振下方地平面、增大晶振与接口距离、使用导电密封圈等。最终辐射降低10dB以上达标。文章总结了晶振EMC设计要点:保持地平面完整、远离接口、外壳接地、合理布局滤波电路等,并强调防水与屏蔽的协调统一。

u012526819的博客 668

《黑神话悟空》的着色器编译怎么这么久?到底什么是着色器编译?

在早期的GPU中,图形渲染被分为几个预定义的阶段,每个阶段执行特定的操作,而这些操作是不可编程的,即开发者不能修改或替换这些阶段的具体实现。当然这些滤镜都是可以重复使用的,但各种不同的硬件甚至不同的版本的硬件能执行的代码是有差异的,于是开发者用通用语言来定义滤镜,由最终执行的设备使用翻译器先自行翻译成对应的代码再执行。我本人并不是计算机图形学方面的从业者,因此在介绍这方面的知识的时候,肯定从专业度和深度来讲是不如从业者的,如果在我的文章中出现了错误,还请直接指出,欢迎大家一起讨论。到底什么是着色器编译呢?

IT界那些事儿 1万+

手把手教你用Xilinx Ultrascale+ FPGA解串12-bit ADC的LVDS信号(附Verilog代码)

本文详细介绍了如何使用Xilinx Ultrascale+ FPGA解串12-bit ADC的LVDS信号,涵盖硬件设计、时钟域处理和数据对齐等关键技术。通过Verilog代码实例和调试技巧,帮助工程师解决高速数据采集中的核心挑战,提升系统稳定性和性能。

weixin_42522964的博客 373

Java对接快递鸟,查询快递物流信息

根据用户输入的订单号,我们的后台识别订单号并根据快递鸟查询快递API接口,实现自动查询的功能。下面是java版本的根据单号查询物流跟踪信息的详细示例代码。只需要下载就可以运行,(自己需要简单的修改)注:登录快递鸟用户管理后台后获得。登录快递鸟用户管理后台。

Roc的博客 958

初识OpenGL (2)编译着色器

首先我们定义一个整型变量来表示是否成功编译,还定义了一个储存错误消息(如果有的话)的容器。如果编译失败,我们会用glGetShaderInfoLog获取错误消息,然后打印它。检测调用glCompileShader后编译是否成功了,如果没成功的话,你还会希望知道错误是什么,这样你才能修复它们。eg.顶点着色器,传递的参数是GL_VERTEX_SHADER。如果编译的时候没有检测到任何错误,顶点着色器就被编译成功了。第二参数指定了传递的源码字符串数量,这里只有一个。第一个参数要编译的着色器对象。......

thefist的专栏 1203

WSL 相关命令时遇到了 “无法从raw.githubusercontent.com提取分发列表、操作超时

核心问题:国内网络屏蔽raw.githubusercontent.com,导致WSL无法获取发行版列表;最优方案:优先用方案1(手动指定发行版安装),无需改配置,1分钟搞定;永久修复:用方案2(修改hosts),适合需要管理多个WSL发行版的场景;兜底方案:用方案3(手动下载安装包),适配所有网络环境。按以上步骤操作后,你不仅能正常安装WSL,等命令也能正常执行,后续可正常使用WSL搭配Docker Desktop(如切换WSL 2后端),无需再担心网络超时问题。

weixin_39766667的博客 2140

第3章-图形处理单元-3.3-可编程着色器阶段

《实时渲染》第四版中翻,第3.3节。

Charlee44的技术驿站 1431

【寄存器模型】二、前门访问与后门访问

1.后门访问可以更好的完成前门访问能够完成的事情:后门访问不消耗仿真时间,且消耗的运行时间也远小于前门访问的运行时间。 2.后门访问可以完成前门访问不能完成的事:对于某些特定的场景,如网络通信系统中的一些只读计数器,当要验证计数器进位归零的场景时,前门访问无法完成写寄存器操作,只能通过消耗仿真时间来使计数器到达特定的计数值。而后门访问可以直接对只读寄存器赋一个初值......

carrotbanana的博客 9657

避坑指南:将大华官方Java SDK无缝迁移到SpringBoot 2.x项目的完整流程

本文详细介绍了如何将大华官方Java SDK无缝迁移到SpringBoot 2.x项目,重点解决内存管理、连接池设计和异步处理等核心问题。通过设备连接池化、异步非阻塞接口改造和内存管理优化,实现刷卡、刷脸等认证功能的高效整合,提升Web服务的稳定性和性能。

weixin_42557830的博客 417

DX11渲染管道 :着色器的编译和创建

在不使用效果框架的时候,整个渲染管道其实挺简单的,创建资源,输入资源。编译着色器输入着色器,其实着色器本身也是一种数据,只不过这个数据描述的是逻辑。最后调用一下draw方法画一下就OK 了。这里说说着色器的编译和创建,很简单。   D3DX11CompileFromFile : HRESULT D3DX11CompileFromFile( _In_ LPCTSTR pSrcFile...

l1987021的专栏 543

Autosar PWM模块的配置和使用

在上面的代码中,我们首先配置了PWM的初始化参数,包括频率和分辨率。GPIO Driver:由于PWM信号需要输出到特定的引脚上,因此我们还需要使用GPIO驱动程序来控制引脚的状态。通过合理配置和应用PWM模块,我们可以实现对汽车电子系统中各种功能的精确控制,从而提高汽车性能和用户体验。在实际应用中,我们可以根据需要进行更多的配置和调整,以实现灵活的PWM控制。PWM Driver:这是主要的PWM驱动程序,负责产生PWM信号并输出到相应的引脚上。接下来,我们需要配置PWM模块的参数。

TcData的博客 682

【DirecX 教程】Lesson 10:绘制一个三角形

Lesson 10:绘制一个三角形 课程一览

Purplenigma的专栏 1192

7.3 空间矢量调制(SVM)整数算法

本文提出了一种基于整数运算的空间矢量调制(SVM)优化实现方案,适用于计算资源有限的Cortex-M0平台。针对传统SVM算法中复杂的三角函数和浮点运算问题,重点优化了扇区判断和占空比计算两个关键环节。在扇区判断方面,采用基于电压分量符号和相对大小的三变量法,避免了角度计算;在占空比计算方面,通过几何关系将作用时间表示为电压分量的线性组合,并采用定点数实现。方案还详细讨论了系数定点化、死区补偿等实现细节,在保证精度的同时显著降低了计算复杂度。实验结果表明,优化后的整数算法在M0平台上仅需50-80个周期即可

技术工作者 944

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

图形渲染: tinyrenderer 实现笔记(Lesson 5 - 7)

各种纹理贴图使用及shadowmapping的实现

lzh804121985的博客 1040

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Lesson 15: SDK文档:Tutorial 4 3D Spaces分析

Constant BufferConstant buffer(cb)是DX10中引入的概念,它取代了DX9时代GPU常量寄存器的概念,允许通过一块大小可变的buffer向shader提供常量数据,而不是之前数量非常受限的n个寄存器,这也是我们遇到的第一种可在shader着色阶段由HLSL访问的资源。 管线的每个可编程阶段都能同时访问一个或者几个cb,对于shader代码来说,cb中的数据都是全局常量

Nim的辙迹 532

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

your browser doesn't support html5,Html5Lesson10QQ.html

Html5 Lesson 10 (Canvas 3D)header {background: #FFCC99;color: white;-moz-box-shadow: 0 2px 8px -3px rgba(0, 0, 0, .5), 0 1.4em 2em -0.7em rgba(255, 255, 255, .2) inset;-webkit-box-shadow: 0 2px 8px -3...

weixin_31766003的博客 835

EasyGame Lesson10 – MDL Animation

MDL Amati on is the very famous skeleton animation. All joints matrix will be saved for each frame. Each joint will give some impact to some vertex, different vertex will give different weight. A...

abc2912333的博客 143

Lesson5 Shader加载二维贴纸

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34242658的博客 127

Ruffle:用Rust重生的Flash Player终极指南

在2020年Adobe正式停止Flash Player支持后,互联网上数以百万计的Flash内容面临着永久消失的危机。从经典的小游戏到教育课件,从交互式广告到企业培训材料,这些数字遗产急需一个可靠的解决方案。Ruffle应运而生——这是一个用Rust语言编写的开源Flash Player模拟器,它不仅保留了Flash内容的原汁原味体验,更通过现代技术架构提供了前所未有的安全性和性能。 ## 问题

gitblog_00556的博客 759

如何在项目中高效实现无限画布渲染与编辑系统

在当今前端开发领域,构建高性能的无限画布系统已成为设计工具、白板应用和创意平台的核心需求。本文将深入解析如何基于现代Web技术栈构建一个功能完整的无限画布渲染与编辑系统,涵盖从基础架构到高级功能的完整实现路径。 ## 为什么无限画布是现代Web应用的关键组件? 无限画布不仅仅是"无限大的绘图区域",它代表了一种全新的内容组织范式。与传统的有限画布相比,无限画布具备三大核心优势: - **非线

gitblog_00731的博客 421

“着色器”是什么意思? 如何使用HTML5和WebGL创建它们

这篇文章是从微软Web开发技术系列的一部分。 感谢您支持谁使SitePoint可能的合作伙伴。 您可能已经注意到,我们首先谈到了很多关于babylon.js去年和最近我们已经发布babylon.js 2.0与3D音效定位(与WebAudio)和体积光散射。 如果你错过了V1.0宣布,第一你可以追赶基调休息两天在这里 ,直接进入2:24-2:28。 在这里面,微软的传道者史蒂芬Guggenhe...

2863

OpenGL学习笔记三(编译着色器)

运行着色器程序 ps:大部分出自(LearnOpenGL)       上一篇(OpenGL学习笔记二(着色器))说到什么是着色器,如何写着色器,这次我们要开始运行我们写好的着色器代码了       着色器程序的创建与C/C++程序的创建相似。首先你需要编写着色器程序文本并...

Love柒的博客 2652

Ada计算机图形DirectX之d3d10misc

---------------------------------------- -- File : d3d10misc.ads -- -- Translator:Dongfeng.Gu,2018/10/21 -- -- Mail: 515639@qq.com -- -- Progress:100% ...

adacore的博客 266

opengl学习4 编译着色器

顶点着色器编译 1.创建一个着色器对象,注意还是用ID来引用的 GLuint vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); 2.下一步我们把这个着色器源码附加到着色器对象上,然后编译它: glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); g...

Furrain的博客 1188
上一篇: Lesson 9: 全屏
下一篇: Lesson 11: 绘制三角形
Nim的辙迹
博客等级 码龄10年 17粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值