GPU渲染管线之旅|07 深度处理、模板处理

2023-05-16

在这一篇中,我们来讨论Z-pipline的前端部分(简称它为early-Z), 以及它是在光栅化中怎么起作用的。和上一篇一样,本篇也不会按实际的管道顺序进行讨论;我将首先描述基础算法,然后再补充管线中的各个阶段(以相反的顺序可以更简单的解释这些内容)。

1.插值

Z通过三角形进行插值,因为三角形顶点的属性是由vertex shader输出的。 让我先花点时间解释一下它是如何工作的。 在这一点上,我最初有一节介绍如何推导插值背后的数学运算,以及为何透视插值以这种方式起作用。 我花了几个小时苦苦挣扎,因为我试图将它限制为一到两段。现在我可以说的是,如果我想正确地解释它,我需要的空间比那还要多,至少一两张图片; 一幅图片可能表示上千多个单词,但是准备一张图表花掉的时间远远超出我写下上千个单词时间,所以从我的角度来看,这并不是很划算。好了,不多说这些离题的东西了:)。所以我将这些添加到我的"与图形相关的东西中",以便在后面的某个时候写出来。现在,我只描述它的相关摘要内容:

只有在屏幕空间三角形上线性插值属性(颜色,纹理坐标等)不会产生正确的结果(除非插值模式是“无视角”的一种,在这种情况下,请忽略我刚才写的内容)。假设我们要对2D纹理坐标 ( s , t ) (s, t) (s,t)进行插值,事实证明,如果在屏幕空间中线性插值 1 w \frac{1}{w} w1 s w \frac{s}{w} ws t w \frac{t}{w} wt(这里的w是齐次裁剪空间w距离顶点位置),的确可以得到正确的结果,然后每个像素取 1 w \frac{1}{w} w1的倒数以获得w,最后将其他两个插值公式乘以w得到st。实际的线性插值可归结为建立平面方程式,然后插入屏幕空间坐标。如果你要编写软件透视纹理映射器,到这里就已经完成了。但是,如果要插值两个以上的值,更好的方法则是为原始裁剪空间三角形中的当前像素计算(使用透视插值)重心坐标(我们将其称为 λ 0 \lambda_0 λ0 λ 1 \lambda_1 λ1)。这样使用常规线性插值对实际顶点属性进行插值,后面就不必将所有内容都乘以w

那么,这对三角形设置增加了多少工作?为三角形设置 λ 0 w \frac{\lambda_0}{w} wλ0 λ 1 w \frac{\lambda_1}{w} wλ1需要4个倒数,三角形面积(我们已经为背面剔除计算过!)和一些减法,乘法和加法。使用重心方法设置用于插值的顶点属性确实很划算——每个属性需要两个加减法(如果你不使用重心,则会在此处需要更多的乘加操作)。 可能跟不上这个节奏? 没关系,除非你之前实现过这些,否则很可能跟不上。没事,如果你不了解,可以忽略所有这些,因为他们只是性能上的考虑,你可以后面再返回来这部分。

让我们回到这里的目的:我们现在要插值的是Z,并且因为我们在顶点级别将Z计算为 z w \frac{z}{w} wz作为投影的一部分(请参见上一部分),因此它已经除以了w,我们可以在屏幕空间中对其进行线性插值。真好, 我们最终得到的是 Z = a X + b Y + c Z = aX + bY + c Z=aX+bY+c的平面方程,我们只需将XY代入即可得到一个值。所以,这是我在最后几段中强调的重点:在任意给定的插值Z可以归结为两个乘法加法。(建议可以开始了解为什么GPU具有快速的乘法累加单元?这些东在GPU设计中绝对无处不在!)。

2.Early-Z/Stencil

现在,如果你认为图形API传统上将Z/Stencil处理放入的位置恰好在alpha blend之前,位于的Pixel处理的最后,你可能会感到非常的困惑。为什么我甚至在管道现在的位置上就开始讨论Z? 我们甚至还没有开始渲染出来任何像素点!答案很简单:**Z和模板测试就开始kill潜在地大多数像素。**你肯定不想渲染一整个被大部分遮盖的复杂材料组成的网格,然后放弃你刚完成的工作的95%,因为该网格恰好隐藏在墙后。那样真的是愚蠢的带宽,处理能力和资源的浪费。在大多数情况下,这是完全是没有必要的:大多数着色器不会执行任何操作修改Z测试结果或将值写回到Z/Stencil缓冲区。

因此,GPU在可能的情况下实际执行的操作被称为“Early-Z”(与Late-Z相反,后者实际上处于传统API模型通常显示在管线中的后期)。 虽然,这些听起来像在对三角形进行光栅化之后以及开始向着色器发送像素之前。执行Z/Stencil测试并尽早写入,这样,我们可以尽早注意到所有被拒绝的像素,而不会浪费大量的计算时间。 但是,我们不能总是这样做:Pixel Shader可能会忽略插值的深度值,提供自己的要写入Z缓冲区的深度(例如,depth sprites);或者它可能使用丢弃,alpha testalpha-to-coverage,所有这些都会在Pixel Shader执行期间Kill像素/采样,这意味着我们无法及早更新Z缓冲区或模板缓冲区,因为我们可能正在更新后来被着色器丢弃的采样的深度值!
因此,GPU实际上具有Z/Stencil逻辑的两个副本。一个在光栅器之后,在Pixel Shader的前面(执行Early-Z),另一个在着色器之后(执行Late-Z)。 请注意,即使着色器使用某些采样杀死机制,原则上我们仍然可以在Early-Z阶段进行深度测试。 这只是我们必须要小心的地方。 真正使我们根本无法进行任何Early-Z测试的唯一情况是,当我们在Pixel Shader中写入输出深度时, 在这种情况下,Early-Z单元根本无法使用。

传统上,API只是假装不存在任何这种早期逻辑。 Z/Stencil在原始API模型中处于后期阶段,必须以与该模型在功能上100%一致的方式进行任何优化(例如Early-Z)。 也就是说,驱动必须检测Early-Z的适用时间,并且只有在没有明显差异的情况下才能将其打开。 到现在为止,API已经缩小了差距。 从DX11开始,着色器可以声明为“强制Early-Z”,这意味着即使着色器使用对于Early-Z不一定“安全”的图元,着色器也可以进行完整的Early-Z处理。 可以声明插值的Z值是保守的(即仍会发生早期的Z拒绝)。

3.Z/stencil writes: the full truth

好的,等一下。正如我已经描述的那样,我们现在有两个部分,即Early-ZLate-Z,它们都可以写入Z/模板缓冲区。对于我们看到的任何给定的着色器/渲染状态组合,这都将在稳态下起作用。但这不是实际的运作方式。实际上发生的是,我们每帧渲染几百到几千个批次,定期切换着色器并渲染状态。这些着色器中的大多数将允许Early-Z,但有些则不允许。从执行Early-Z的着色器切换到执行Late-Z的着色器是没有问题的。但是,如果Early-Z做任何写操作,则从Late-Z回到Early-Z:重点是Early-Z在管道中比Late-Z早很多!因此,我们可能会开始对一个着色器进行Early-Z处理,愉快地写入深度缓冲区,同时仍旧存在运行Late-Z的旧着色器的管线中的内容,并且可能试图同时写入相同的位置——经典的竞态条件。那么我们该如何解决呢?有很多选择:

  • 一旦在一个帧内(或至少对同一渲染目标执行一系列操作)从Early-Z处理到Late-Z,你将停留在Late-Z直到下一个flush pipline的点。这可以工作,但可能会浪费大量的着色器周期,而Early-Z不必要地处于关闭状态。
  • Late-Z着色器到Early-Z着色器时触发一个(像素)pipline flush, 这样也可以,但也不太精确。这次,我们不浪费着色器周期(或内存带宽),而是停顿了——这没有太大的改进。
  • 但是实际上,在两个地方进行Z写入不是个好现象。另一种选择是永远不要在Early-Z阶段写入Z。总是在Late-Z进行Z写入。请注意,如果要这样做,则在Early-Z要谨慎做出保守的Z测试决定!这样可以避免出现竞争情况,但意味着早期的Z测试结果可能会过时,因为直到不久之后才会对当前分配的像素进行Z写入。
  • 使用一个单独的单元为我们跟踪Z写入并强制执行正确的排序; Early-Z和Late-Z都必须经过此单元。

所有这些方法均有效,并且各有优点和缺点。 同样,我不确定在这些情况下当前的硬件会做什么,但是我有充分的理由相信它是最后两种选择之一。 特别是,我们稍后会在路上(和管道中)遇到一个功能单元,这将是实现最后一个选择的好地方。

但是我们仍在对每个像素进行所有这些测试。 我们不能做得更好吗?

4.Hierarchical Z/Stencil

这里的想法是,我们可以再次使用栅格化中的图块(tile)技巧,并尝试一次Z-reject整个图块,甚至可以下降到像素级!我们在这里所做的是严格的保守测试;它可能会告诉我们“在此图块中可能没有通过Z/Stencil的像素”,却没有声称所有像素都被拒绝。

假设在这里,我们使用“小于”,“小于等于”或“等于”作为Z的比较模式。然后,我们需要为每个图块存储编写的最大Z值。在对三角形进行栅格化时,我们计算活动三角形要写入当前图块的最小Z值(一个简单的保守近似值是在当前图块的四个角取内插Z值的最小值)。如果三角形的最小Z值大于当前图块存储的最大Z值,则保证三角形完全被遮挡。这意味着我们现在需要跟踪最大Z值,并在写入新像素时保持该值是最新的。不过,如果该信息不是最新的,这很好。由于我们的Z检验种类较少,因此Z缓冲区中的值只会随着时间的推移而变小。如果我们使用的过零最大值Z有点过时,那就意味着我们的早期拒绝率会比我们可能会稍差一些;它不会引起任何其他问题。

如果我们使用的是“大于”,“大于等于”或“等于”Z比较模式,则同样的方法也是有效的(交换最小/最大和比较方向)。 我们不容易做到的是,在框架中间从基于“小于”的测试更改为基于“大于”的测试,因为这会使我们一直跟踪的信息无用( 基于基础的测试,我们需要每个tile最大Z,对于基于基础的测试,我们需要每个tile最小Z。 我们需要遍历整个深度缓冲区以重新计算所有图块的最小值/最大值,但是GPU实际要做的就是在执行此操作后关闭“Z轴分层”(直到下一个“清除”)。 所以:不要那样做。

与我描述的Z分层逻辑类似,当前的GPU也具有分层模板处理。但是,与Hierarchical Z不同,我在该主题的出版文献中所见不多(意思是,我还没有碰到它, 可能有论文,但我并不知道)。作为游戏机开发人员,你可以访问包含底层算法描述的底层GPU文档,但是坦率地说,我绝对不愿意在这里写一些东西,实际上我拥有的唯一好的资源就是带有大量保密协议(NDAs)的各种GPU文档。

5.Putting it all together

好的,我们现在有了所需的所有算法和理论, 让我们看看如何将其与已有的内容串联起来!

首先,我们现在需要对Z/属性插值进行一些额外的三角形设置。 要做的事情不多,三角设置需要做更多的工作; 就是这样。 在此之后,我已经在上一部分中讨论了粗光栅化。

然后是分层Z(我在这里假设样式比较少)。我们希望在粗光栅化和精细光栅化之间运行。首先,我们需要逻辑来计算每个图块的最小Z估计值。我们还需要存储每位的最大Z,这不必是精确的:只要我们总是四舍五入!与往常一样,在已用空间和早期拒绝效率之间要进行权衡。从理论上讲,你可以将Z-max信息放入常规内存中。在实践中,我认为没有人会这样做,因为你希望做出Z层决策,而不会带来大量额外延迟。另一个选择是将用于分层Z的专用内存放到芯片上,通常作为SRAM,你也可以将其用作缓存。对于24位Z,每个图块你可能需要大约10-14位,以便以紧凑的编码存储合理精度的Z​​-max。假设使用8×8的图块,则意味着不足1MBit(128k)的SRAM支持最高2048×2048的分辨率,对我来说,这听起来似乎是合理的数量级。注意,这些东西是固定大小的,并在整个芯片上共享。如果进行上下文切换,则会失败。如果你为该内存分配了错误的深度缓冲区,则无法在实际重要的深度缓冲区上使用分层Z,否则会丢失。就是这样。这就是硬件供应商定期告诉你首先创建最重要的渲染目标和深度缓冲区的原因。他们提供的这种类型的内存有限(你会看到的更像是这种内存),当它耗尽时,您就倒霉了。注意,他们并不一定要做这种孤注一掷的事情;例如,如果你有一个非常大的深度缓冲区,则可能只会在左上角2048×1536像素中获得分层的Z,因为这足以容纳Z-max内存。它并不理想,但仍然比完全禁用hierarchy z要好得多。

顺便说一句,“Real-Time Rendering” 在这一点上提到“gpu很可能正在使用超过两层的层次z缓冲”。我怀疑这是真的, 出于同样的原因, 我怀疑他们使用多级分层光栅化程序:添加更多的水平是最简单的情况下(大三角形)更快而增加延迟和无用的小三角形:如果你要画一个三角形,适合在一个8×8 tile,任何粗糙层次水平是纯粹的开销,因为即使在8×8级,你刚做的一个测试trivial-reject三角形(或没有)。再说一次,对于硬件来说,这不是一个大的性能问题; 只要你不消耗额外的带宽或其他稀缺资源,做比严格需要的更多的计算工作并不是大问题,只要它在合理的范围内,分层Stencil也在那里,也应该在精细光栅之前发生,最有可能与分层Z并行。

之后是精细的栅格化,然后依次是Early-Z。对于Early-Z,我需要指出两个重要的观点。

6.Revenge of the API order

在过去的几部分中,我一直在按图元的提交顺序进行快速而宽松的操作。不适用于顶点着色,原始装配,三角形设置或栅格化。但是Z是不同的。对于“小于”或“小于等于”的Z比较模式,像素到达的顺序非常重要;如果我们对此感到困惑,则有可能改变结果并引入不确定性行为。更重要的是,根据规范,只要应用不可见,我们就可以按任意顺序执行操作;好吧,正如我刚才说的,对于Z处理,顺序很重要,因此我们需要确保三角形以正确的顺序到达Z处理(Early-ZLate-Z都是这样)。

在这种情况下,我们要做的是回到管道中,并寻找一个合理的位置来再次将它们进行排序。在我们目前的道路上,最佳候选位置似乎是图元装配。因此,当我们从shader顶点块开始组装图元时,确保严格按照应用程序提交给API的原始顺序来组装它们。这意味着我们可能会停顿更多(如果PA缓冲区包含一个输出顶点块,但它不是正确的顶点块,则需要等待,并且无法开始设置图元),但这就是正确性的代价。

7.Memory bandwidth and Z compression

第二个要点是Z/Stencil非常占用带宽。这有几个原因。首先,这是我们真正为光栅化器生成的所有Samples运行的(当然,假设Z/Stencil没有关闭)。Shaders,Blending等都受益于我们做的早期reject;但即使是Z-rejected像素也要先进行Z缓冲区读取(除非它们被分层Z kill掉)。另一个主要原因是,当MSAA启用时,Z/Stencil缓冲区是每个样本;所以4x MSAA意味着4x Z的内存带宽成本?对于需要大量内存带宽的东西,即使在没有MSAA,这是严重的坏消息。

因此GPU要做的就是Z压缩。有各种各样的方法,但总的思路始终是相同的:假设三角形大小合理,我们期望很多图块仅包含一个或两个三角形。如果发生这种情况,那么我们不存储整个图块的Z值,而是存储填充该图块的三角形的平面方程。该平面方程(希望)小于实际的Z值。如果没有MSAA,则一个图块会覆盖8×8的实际像素,因此三角形需要相对较大才能覆盖整个图块。但是使用4倍MSAA,图块可以有效缩小到4×4像素,覆盖整个图块变得更加容易。还有一些扩展程序可以支持2个三角形等,但是对于合理大小的图块,你不能超过2-3个三角形,但实际上仍可以节省带宽:额外的平面方程式和coverage mask并非是没有开销的!

无论如何,关键是:这种压缩在起作用时是完全无损的,但并不适用于所有图块。因此,我们需要一些额外的空间来表示图块是否已压缩。我们可以将其存储在常规内存中,但这意味着我们现在需要等待两个全内存往返延迟才能进行Z读取。那很糟。同样,我们添加一些专用的SRAM,使我们可以在每个图块中存储几(1-3)位。简单来说,它只是一个“已压缩”或“未压缩”标志,但是你可以添加多种压缩模式等等。 Z压缩的一个不错的副作用是,它使我们可以进行快速的Z清除:当清除为Z = 1时,我们只是将所有图块设置为“压缩”,并存储Z = 1常数三角形的平面方程。

所有的Z压缩操作(类似于纹理采样中的纹理压缩)都可以折叠到内存访问/缓存逻辑中,并且对其他所有人完全透明。如果你不想将平面方程式发送给Z存储器访问模块(或添加插值器逻辑),则可以从Z数据中推断出它们,并使用一些整数增量编码方案。这种方法每个样本通常需要额外的位以实际进行无损重建,但是它可能导致更简单的数据路径和单元之间更好的接口,这是硬件专家所钟爱的。

下一步我们就可以看看pixel shader及相关的内容了。

8.后记

就像我之前说的,设置插值属性的主题实际上可以自己撰写一篇不错的文章。我现在暂时跳过这一点,可能以后决定填补这一空白。

Z处理已经存在于3D管道中已有很长时间了,并且在大多数情况下都存在严重的带宽问题。人们对此问题进行了漫长而艰辛的思考,为GPU(无论大小)提供“生产质量” Z缓冲的方法千千万万。再说一遍,我只是在这里抛砖引玉。我试图将自己局限于对图形程序员有用的知识。这就是为什么我不花很多时间在Z分层计算或Z压缩等细节上的原因;所有这些都是非常具体的,因为硬件细节在每一代中都会稍有变化,最终,几乎没有一种实用的方法可以有效地利用其中的任何一种方法:如果给定的Z压缩方案在你的场景中效果很好,那就是一些内存你可以花在其他事情上的带宽。如果没有,你会怎么做?更改几何形状和相机位置,以使Z压缩更有效?不太可能。对于硬件设计人员而言,这些都是每一代都需要改进的算法,但是对于程序员而言,它们只是生活中必须面对的事实。

这次,我不会在管道的此阶段详细介绍内存访问的工作方式。但这是在后期的阶段,一切都会在适当的时候显示出来:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GPU渲染管线之旅|07 深度处理、模板处理 的相关文章

  • GPU 的延迟是多少?

    我可以找到 CPU 核心与其缓存 主内存等之间的 CPU 周期延迟 但似乎很难找到有关现代 GPU 的类似信息 有谁知道 GPU 的延迟 特别是现代 nvidia GPU GF110 或更高版本 与其内存之间的延迟 谢谢 GPU 内存确实具
  • 为什么 nvidia-smi 在 Windows 10 21H2 下的 WSL2 中返回“GPU 访问被操作系统阻止”[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在 WSL2 上安装 CUDA 我已按照以下说明在台式机 配备 RTX3080 的 AMD 5950X 系统 和笔记本电脑 配备 i7 7
  • 如何检查 PyTorch 是否正在使用 GPU?

    如何检查 PyTorch 是否正在使用 GPU 这nvidia smi命令可以检测 GPU 活动 但我想直接从 Python 脚本内部检查它 这些功能应该有助于 gt gt gt import torch gt gt gt torch cu
  • 如何让Jupyter Notebook在GPU上运行?

    在 Google Collab 中 您可以选择笔记本在 CPU 或 GPU 环境上运行 现在我有一台配备 NVDIA Cuda 兼容 GPU 1050 和最新 anaconda 的笔记本电脑 如何拥有与协作功能类似的功能 让我可以简单地让我
  • GPU训练时Tensorflow 2.5退出代码-1073740791

    在 GPU 上训练 Tensorflow 模型时 调用 model fit 退出并带有代码 1073740791 0xC0000409 立即地 Epoch 1 500 2021 10 16 20 13 42 154951 I tensorf
  • 在 Tensorflow 中训练简单模型 GPU 比 CPU 慢

    我在 Tensorflow 中设置了一个简单的线性回归问题 并在 1 13 1 中使用 Tensorflow CPU 和 GPU 创建了简单的 conda 环境 在 NVIDIA Quadro P600 的后端使用 CUDA 10 0 然而
  • 带 GPU 的 Lightgbm 分类器

    model lgbm LGBMClassifier n estimators 1250 num leaves 128 learning rate 0 009 verbose 1 使用 LGBM 分类器 现在有没有办法通过 GPU 来使用它
  • 同时使用 2 个 GPU 调用 cudaMalloc 时性能较差

    我有一个应用程序 可以在用户系统上的 GPU 之间分配处理负载 基本上 每个 GPU 都有一个 CPU 线程来启动一个GPU处理间隔当由主应用程序线程定期触发时 考虑以下图像 使用 NVIDIA 的 CUDA 分析器工具生成 作为示例GPU
  • DirectX 世界视图矩阵乘法 - GPU 或 CPU 的地方

    我是 directx 的新手 但令我惊讶的是 我看到的大多数示例中 世界矩阵和视图矩阵都是作为顶点着色器的一部分相乘 而不是与 CPU 相乘并将结果传递给着色器 对于刚性对象 这意味着您为对象的每个顶点将相同的两个矩阵相乘一次 我知道 GP
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • 无法满足显式设备规范“/device:GPU:0”,因为没有匹配的设备

    我想在我的 Ubuntu 14 04 机器上使用 TensorFlow 0 12 作为 GPU 但是 当将设备分配给节点时 我收到以下错误 InvalidArgumentError see above for traceback Canno
  • CUDA - 将 CPU 变量传输到 GPU __constant__ 变量

    与 CUDA 的任何事情一样 最基本的事情有时也是最难的 所以 我只想将变量从 CPU 复制到 GPUconstant变量 我很难过 这就是我所拥有的 constant int contadorlinhasx d int main int
  • 如何读取 GPU 负载?

    我正在编写一个程序 用于监控计算机的各种资源 例如CPU使用率等 我还想监控 GPU 使用情况 GPU 负载 而不是温度 using System using System Collections Generic using System
  • 如何为 CUDA 内核选择网格和块尺寸?

    这是一个关于如何确定CUDA网格 块和线程大小的问题 这是对已发布问题的附加问题here https stackoverflow com a 5643838 1292251 通过此链接 talonmies 的答案包含一个代码片段 见下文 我
  • TensorFlow的./configure在哪里以及如何启用GPU支持?

    在我的 Ubuntu 上安装 TensorFlow 时 我想将 GPU 与 CUDA 结合使用 但我却停在了这一步官方教程 http www tensorflow org get started os setup md 这到底是哪里 con
  • Tensorflow 训练期间 GPU 使用率非常低

    我正在尝试为 10 类图像分类任务训练一个简单的多层感知器 这是 Udacity 深度学习课程作业的一部分 更准确地说 任务是对各种字体呈现的字母进行分类 数据集称为 notMNIST 我最终得到的代码看起来相当简单 但无论如何我在训练期间
  • 用于计算邻居列表的最佳 GPU 算法

    给定 3D 中数千个点的集合 我需要获取落在某个截止值 以欧几里得距离而言 内的每个粒子的邻居列表 并且如果可能的话 从最近到最远排序 在 CUDA 或 OpenCL 语言中 哪种 GPU 算法最快 我所知道的最快的 GPU MD 代码之一
  • 设备内存刷新cuda

    我正在运行一个 C 程序 其中调用了两次 cuda 主机函数 我想清理这两个调用之间的设备内存 有没有办法可以刷新 GPU 设备内存 我使用的是计算能力为2 0的Tesla M2050 如果你只想将内存归零 那么cudaMemset可能是最
  • 我们如何在每次运行时使用不同的种子在 CUDA C 中生成随机数?

    我正在研究一个随机过程 我想在每次运行程序时在 CUDA 内核中生成不同的系列随机数 这类似于我们在 C 中声明 种子 时间 空 接下来是 srand 种子 和兰特 我可以通过内核将种子从主机传递到设备 但是 这样做的问题是我必须将整个种子
  • nvidia GPU 上的内核真的有超时吗?

    寻找为什么我的内核产生奇怪的错误消息或仅 0 结果的答案我发现了这个answer https stackoverflow com questions 3988645 cl out of resources for 2 millions fl

随机推荐

  • c++的字节序与符号位的问题

    看这样一道题 xff1a include lt stdio h gt int main void int w h int i 61 0xa1b2c3d4 char p 61 char amp i for int j 61 0 j lt 4
  • docker镜像之带vnc的ubuntu

    docker镜像 之 带vnc图形界面ubuntu 前言 xff1a 为了在图形界面中使用firefox xff0c 需要找一个带rdp或者vnc的ubuntu xff0c 最好是gnome的界面 xff0c 折腾了3天 xff0c 终于找
  • STM32中,关于中断函数调用全局变量的问题

    xfeff xfeff https blog csdn net leo liu006 article details 79334905 首先是问题的描述 xff1a 硬件单片机型号 xff0c STM32F103VET6 xff0c IDE
  • python使用selenium以及selenium-wire做质量与性能检测

    python天生就是适合用来做爬虫 xff0c 结合selenium真是如虎添翼 xff1b 1 安装库 pip install selenium pip install selenium wire 2 xff09 添加驱动 xff0c 比
  • 编写http workshop脚本从网页缓存里解析音乐

    前一篇文章 编写http workshop脚本从网站下载音乐 示范了如何使用HttpClient访问API 以及Json数据的解析 今天我们通过解析一个网页展示如何使用内置的LibXml2的功能解析HTML 提取我们关心的内容 这里随便搜了
  • pytorch环境搭建若干

    备注 xff1a 不要使用python3 11不支持 xff0c pip会说找不到合适的版本 xff1b python官网不提供旧版的下载了 xff0c 说是win7以后无法使用 xff0c 都是扯淡 xff0c 有其他地方可以下载pyth
  • ffmpeg常用方法

    FFmpeg 是一款开源的音视频处理工具 xff0c 可以处理各种格式的音视频文件 xff0c 并且可以进行格式转换 剪切 合并 添加水印等多种操作 下面是 FFmpeg 的一些常用命令及其用法 xff1a 视频转码 将一个视频文件转换为另
  • RFC2152 UTF-7 中文

    RFC2152 UTF 7 中文 翻译 xff1a 李静南 时间 xff1a 2006 03 29 EMAIL xff1a robin fox 64 sohu com 版权 xff1a 可以用于非商业用途自由转载 xff0c 但请保留本文档
  • 第九章0.4的CMakeLists.txt结构

    最开始看这一章的时候 xff0c 将CMakeLists txt部分跳过了 xff0c 没有看 后来看高博RGBD SLAM时候 xff0c 第一讲降到了cmake的用法 xff0c 发现有新的东西 xff0c 又回头看 xff1a 最原始
  • ROS 中setup.bash

    好久没写了 xff0c 最近搞了辆小车 xff0c 瞅了瞅ROS的相关内容 xff0c 没有写ROS的内容 xff0c 刚开始看 xff0c 写的话基本就成了书本粘贴 不过最近由ROS引出来的一些Linux相关的东西 xff0c 然后又回头
  • ros_hostname与ros_ip

    在ROS的环境变量中 xff0c 需要在 bashrc中设置的并不多 xff08 此处是指在wiki的基本教程中出现的 xff0c 大牛请无视 xff09 xff0c 大概只有三个 xff1a ROS MASTER URI ROS HOST
  • git图形化代码冲突处理

    当代码量少的时候使用 xff0c 使用vimdiff或者手动处理冲突 xff0c 都很方便 xff0c 但是当代码量大还是图形化处理更方便 xff0c 这里推荐使用kdiff3 首先下载kdiff3 xff0c 网上不好找的话 xff0c
  • Apache httpd 目录列表禁用配置(options indexes)

    Apache httpd服务器在缺省的情况下 xff0c 开启了基于目录列表的访问 xff0c 这是一个存在安全隐患的问题 xff0c 因此可以关闭这个功能 在Apache 2 4的版本中 xff0c 不在支持使用 indexes来配置 x
  • cmake学习笔记6-catkin的CmakeList.txt讲解

    https www jianshu com p 551d6949b49d 引用 cmake学习笔记 cmakelist txt创建项目示例 cmake的介绍和使用 Cmake实践 推荐cmake手册详解 严重推荐CMake构建系统的骨架 c
  • ROS中使用Intel RealSense D455或L515深度相机

    目的 在ROS平台上 xff0c 使用深度相机作为传感器设计自主避障机器人 1 安装驱动 测试环境 软件 xff1a Ubuntu 16 04 ROS Kinetic 硬件 xff1a Intel RealSense D455 或 L515
  • ROS机器人操作系统底层原理及代码剖析

    0 目的 本文介绍ROS机器人操作系统 xff08 Robot Operating System xff09 的实现原理 xff0c 从最底层分析ROS代码是如何实现的 1 序列化 把通信的内容 xff08 也就是消息message xff
  • RS232,RS485波形分析

    通过观察波形可以确定以下情况 xff1a 是否有数据接收或发送 xff1b 数据是否正确 xff1b 波特率是否正确 xff1b 一 串行数据的格式 异步串行数据的一般格式是 xff1a 起始位 43 数据位 43 停止位 xff0c 其中
  • GPU渲染管线之旅|05 图元处理、Clip/Cull, 投影和视图变换

    上一篇中我们讨论了关于 纹理和采样 xff0c 这一篇我们回到3D管线的前端 在执行完顶点着色之后 xff0c 就可以实际的渲染东西了 xff0c 对吗 xff1f 暂时还不行 xff0c 因为在我们实际开始光栅化图元之前 xff0c 仍然
  • 谈谈OpenCV中的四边形

    首先抛出一个问题 xff0c 给定一系列二维平面上的的点 xff0c 这些点是可以组成一个封闭的二维图形 因为这些点是矩形区域拍摄图像后识别得到的图形的边界点 xff0c 所以我们要抽象出来这个矩形 xff0c 也就是我们要反映出这个矩形
  • GPU渲染管线之旅|07 深度处理、模板处理

    在这一篇中 xff0c 我们来讨论Z pipline的前端部分 简称它为early Z 以及它是在光栅化中怎么起作用的 和上一篇一样 xff0c 本篇也不会按实际的管道顺序进行讨论 xff1b 我将首先描述基础算法 xff0c 然后再补充管