当前位置: 首页 > news >正文

游戏引擎学习第89天

回顾

由于一直没有渲染器,终于决定开始动手做一个渲染器,虽然开始时并不确定该如何进行,但一旦开始做,发现这其实是正确的决定。因此,接下来可能会花一到两周的时间来编写渲染器,甚至可能更长时间,因为写完整个渲染器需要时间。即使不写整个渲染器,至少会写够多的部分来解决当前的问题。因为之前有很多冗余的代码在没有渲染器的情况下产生了不少麻烦,这时候不得不决定开始着手渲染器的开发。

另一个考虑因素是,地面渲染代码也已经开始有了雏形,想要支持多层地面,并希望实现这一目标。面临的一个问题是,目前没有缩放功能,无法测试地面物件的渲染效果,尤其是想实现低层次的物体看起来更远,需要一种能够模拟这种效果的方式。而为了测试这一点,即使渲染器不完美,至少需要一个简单的渲染器来验证它是否可行,确保渲染效果能够满足需求。因此,决定继续推进渲染器开发,直到遇到需要调整方向的情况。

黑板:渲染

为了让渲染器能够正常工作,游戏代码需要发出一系列指令,告诉渲染器应该做什么,但这些指令不会立刻执行。换句话说,游戏代码会发出指令,当需要渲染某些内容时,它会把这些指令放入一个缓冲区。这些指令可能包括渲染某个物体的头部,或者渲染一些粒子效果等。这个缓冲区被称为“推送缓冲区”,原因是因为可以不断向缓冲区中推送新的指令,缓冲区不会缩小,只会持续增加,直到渲染器最终将所有指令渲染并丢弃缓冲区中的内容。

使用这种方法有几个原因。通过将指令放入缓冲区,渲染器可以延迟执行这些指令,直到渲染时才统一处理,从而优化渲染流程。

黑板:使用 PushBuffer 的原因

推送缓冲区的第一个,也是最重要的原因,是希望能够进行排序。为了做到这一点,需要能够在渲染之前先看到所有需要渲染的内容,并决定它们的渲染顺序。虽然可以尝试设计游戏代码,让它按照渲染的顺序逐步处理每个任务,但这样会给游戏带来很多约束,导致游戏需要进行大量不必要的计算,而这并不是理想的设计。游戏的结构应该以提高灵活性和速度为目标,并且优化离屏计算的效率,而不是仅仅围绕如何渲染来构建整个游戏架构。

黑板:围绕渲染器构建的游戏架构历史

过去,游戏架构完全围绕渲染器来构建并不罕见,尤其是在资源极其有限的时代,比如 Atari 2600、ColecoVision 和 Commodore 64。当时,若试图将渲染命令排队后再执行,游戏根本无法运行,因为没有足够的系统资源来高效处理这些操作,游戏会非常缓慢,内存也可能不足。而今天的硬件资源充足,允许在不影响性能的情况下使用推送缓冲区来排队渲染命令,并在需要时执行。

黑板:现代的奢侈品和权衡

在现代硬件资源充足的情况下,可以做出不同的权衡,以优化游戏代码的整体结构。然而,强调避免使用大量低效的代码来浪费 CPU 资源,尤其是在如今机器性能强大的情况下,更应该避免这种做法。建议尽量找到合理的权衡点,使得游戏代码整体更加高效和灵活。在渲染命令的排序上,通过将排序逻辑与游戏代码的结构分离,能使游戏代码更加高效和灵活,同时在需要时可以根据具体情况调整排序方式。这种方式的优势在于,它能够根据不同的场景灵活地进行排序,从而提升整体的效率和性能。

黑板:输出目标

通过使用推送缓冲区,可以实现将渲染命令输出到不同的目标平台上,如 OpenGL、Direct3D、Mantle 等,甚至可以为不同的硬件平台和软件渲染器提供优化。例如,可以为 ARM 架构的处理器提供专门的 NEON 版本,或者为不同的硬件平台设计专用的渲染版本。通过这种方式,推送缓冲区不仅仅是排序,它还允许将渲染命令转化为最适合目标平台的形式,从而实现不同渲染器的优化,而不需要重写整个游戏代码。这为游戏提供了一层可移植性,使得可以在多种渲染目标之间进行优化,而不影响游戏的整体架构。

黑板:平衡优化方法

对于优化效率的追求,存在一个平衡点。极端的优化哲学,追求每个细节的完美,可能会导致项目无法完成,因为总有更多的优化可以做。同样,忽视性能,完全不关心它,也是不理智的,因为这会导致低效和不可靠的结果。理想的做法是在项目的时间范围内,找到一个合理的效率平衡,使得产品既能提供良好的性能,又能确保高质量,使得运行时感觉流畅、可靠且美观。

黑板:PushBuffer 的好处

Push缓冲区可以在渲染过程中提供良好的平衡。它使得游戏代码能够迅速、简洁地描述渲染需求,并且避免过度消耗资源。这个缓冲区充当了一种中间表示,类似于编译器中的中间步骤,使得游戏能够在不影响性能的前提下优化渲染操作。通过这种方式,渲染目标(如OpenGL、Direct3D或软件渲染器)能够高效地处理渲染命令,而不需要每帧都做过多处理。此外,Push缓冲区还支持在不同平台间的移植,使得代码在不同的渲染API上能够灵活转换并实现优化。

黑板:支持多个目标的考虑

在设计渲染系统时,虽然目前对一些渲染目标(如OpenGL、软件渲染器)已有经验,但仍保持一种谨慎的态度,假设对于某些输出目标并不完全了解。这是因为游戏可能会面临新的渲染目标(例如Vulkan或Mantle),而开发者无法预见所有的技术挑战。目标是确保系统可以灵活适应新平台,无需重写整个游戏代码,以此实现高效的渲染优化。这种方式能够帮助快速适应不同的渲染API,同时保持较好的性能,而不会陷入繁琐的重构工作。

黑板:我们的第一个目标:软件 “GPU 类渲染”

在开发软件渲染器时,目标是使其模拟GPU的工作方式,尽管它不会完全与GPU相同,但通过这种方式可以获得宝贵的对现代游戏渲染流程的洞察。此类渲染器将稍微慢一些,因为不会做出专门针对CPU优化的捷径,而是力求最大程度地还原GPU的工作机制,从而为开发者提供更深刻的理解,尤其是关于着色器的结构和性能特点。

这种方法有助于理解GPU如何处理图形,并通过该方式开发渲染器时,可以从中获得对现代游戏图形渲染的宝贵见解。虽然软件渲染器的效率不如GPU,但它的设计有助于开发者深入了解图形渲染的本质。

黑板:两种渲染工作方式的视角:1) 显式表面光栅化器

一种常见的渲染方法是通过扫描线来绘制图形。例如,绘制三角形时,首先会确定三角形所触及的扫描线,然后遍历每条扫描线,计算出三角形在每条扫描线上的跨度,最终确定哪些像素属于三角形。这种方法是传统的软件光栅化方式,在过去的Pentium时代较为常见。

然而,虽然这种方法在某些情况下可能是更高效的,当前的开发策略并不打算使用这种传统的扫描线渲染方式。即使这种方式能够提供较好的性能,也不会采用它,而是选择一种不同的渲染策略。

黑板:2) 隐式表面光栅化器

当前的渲染策略采用了一种隐式的表面光栅化方法,而不是传统的显式光栅化。传统的光栅化方法会逐像素遍历并填充需要的像素,而隐式光栅化则通过粗略估算哪些区域会被图形触及来进行处理。例如,可以使用一个4x4像素的方格(16个像素)来估算三角形与屏幕上的区域的交点,而不需要明确计算每个像素是否被三角形触及。

具体操作是,先估算哪些4x4的像素区块会被图形触及,然后对这些区块中的所有像素进行计算,而不管三角形是否真的经过这些像素。最后,会通过掩蔽操作去除不被触及的像素,仅填充真正被图形覆盖的区域。

黑板:使用隐式方法的理由

采用这种方式有很多原因,虽然现在不打算详细展开,但随着实现的推进,这些原因会变得更加清晰。现代GPU通常采用类似的方案进行渲染。

黑板:我们的渲染器大概会是什么样

渲染器的工作流程将包括以下几个阶段:首先是推送缓冲区(push buffer),接着进入一个定位阶段,确定屏幕上各个三角形的位置。然后,渲染器将选择需要填充的4x4区域,针对每个三角形或其他几何图形进行处理。之后,将有一个计算阶段,负责计算这些4x4区域的像素值。这个阶段会使用类似光栅化的算法来处理这些区域。

黑板:SIMD 指令集

渲染器将在不同的处理器架构上进行优化,具体根据不同的SIMD(单指令多数据)宽度进行调整。对于SSE2(最小目标),每次计算四个像素,AVX则是八个像素,AVX-512则是16个像素。渲染器将根据平台的不同,分别进行四倍、双倍或单倍的处理。最终,通过这种方式,渲染器可以在不同平台上有效运行,同时保证每个像素的渲染按预定的方式进行,处理过程会像流水线一样进行,确保高效执行。

黑板:我们正在构建的概述

目前的工作重点是处理矩形渲染,因为游戏引擎是基于精灵的,矩形是主要的处理对象。虽然有时可能会考虑三角形,但在实际情况中,处理矩形的成本和处理三角形相似,因此选择专门处理矩形可以节省许多计算工作。接下来,渲染器将扩展功能,包括支持缩放和旋转等操作,虽然目前游戏还没有请求这些功能的接口,但为了能够在后续阶段处理这些需求,需要在渲染管线中预留空间。当前的目标是清理和优化推送缓冲区,并确保渲染器能够表达这些新的功能。

开始提取绘制函数

开始整理和提取一些功能,包括绘制矩形、绘制矩形轮廓、绘制位图等操作。所有这些功能将集中在一个地方,方便查看和检查,确保没有出现错误。虽然在操作过程中遇到了一些小问题,但这些可以逐步解决。
在这里插入图片描述

在这里插入图片描述

看看我们目前的进展

检查了当前状态后,确认一切正常,缓存填充工作进行顺利,没有需要担心的地方,项目目前处于可工作状态,可以继续推进。

开始玩代码

在当前工作中,发现了 PieceCount 仍然存在,但不再使用,进行了对齐操作,确保一切显示正常。
在这里插入图片描述

Vaporise PieceCount

决定删除 PieceCount,因为它不再被使用,进行清理工作。

研究在这里添加多种命令类型,首先将 entity_visible_piece 重命名为 render_group_entry

为了便于扩展命令类型,决定将 entity_visible_piece 更名为 render_group_entry。这样可以更清晰地表示其实际功能,并且更好地适应未来可能的复杂命令操作。
在这里插入图片描述

把 RenderGroupToOutput 提取到 game_render_group.cpp 中

在这一过程中,计划将一些功能提取到game_render_group中,主要是为了更好的组织结构,便于集中管理相关内容。此举与代码本身无关,完全是为了个人方便。将这一部分称为“RenderGroupToOutput”,并将原本在推送缓冲区内进行的操作移到渲染组中。接下来,需要传递一些必要的参数,包括渲染组本身和输出缓冲区等。

对于ScreenCenter坐标(X和Y)等信息,可以从缓冲区中计算得出。像将米转换为像素这类操作,则可以通过RenderGroup直接进行,尽管这可能会在稍后的过程中稍作不同的处理。最终的目标是确保所有需要的值都可以通过RenderGroup或其输出目标来获得。

重点是,所需的“绘制缓冲区”实际上是一个加载的位图,它代表了绘制的目标。因此,将该位图作为输出目标传递,其他相关的计算(如屏幕中心)也可以通过这个目标来完成。

总的来说,这一过程并不涉及任何设计变动,仅仅是一个简单的编程步骤,确保代码结构更加清晰。
在这里插入图片描述

在这里插入图片描述

面向压缩编程

**压缩导向编程(Compression Oriented Programming,COP)**是一种编程范式,重点在于将压缩技术作为系统和算法设计的核心主题。其目标是通过在系统架构中广泛应用压缩技术来优化数据的存储、传输和处理。该方法不仅能够减少存储和传输成本,还可以通过减少内存使用和提高数据处理速度,特别是在处理大型数据集时,来改善性能。

压缩导向编程的主要原则包括:

  1. 数据表示:使用压缩格式作为数据存储和处理的主要表示方式,确保最小化空间使用。

  2. 算法设计:开发能够高效处理压缩数据的算法,使其在不完全解压的情况下也能快速访问和操作数据。这可能涉及专门的数据结构或编码方案,以便实现压缩感知计算。

  3. 权衡:管理压缩效率与压缩和解压操作开销之间的权衡。虽然压缩可以节省空间,但压缩和解压所花费的时间也需要平衡,以确保性能不受影响。

  4. 流处理与实时处理:实现允许高效处理数据流的压缩技术,确保在实时处理时不会显著影响性能,通常使用如流式压缩算法等技术。

  5. 可扩展性:设计能够随着数据规模的增大而扩展的系统,确保即使在大规模分布式系统或大数据环境中,压缩的优势仍然能够显现。

这种方法在数据传输(例如网络传输)、存储管理以及处理大型数据文件或数据库等领域尤为有用,因为数据的庞大规模可能会成为瓶颈。

在这段讨论中,强调了设计过程应当是自然、有机地进行的,而不是过度设计或过度思考。整个过程应该是逐步推进的,通过不断提取和简化现有的结构,按照已有的代码要求来决定各部分内容的组织和功能,而不是在早期就过度规划。提到在编程中,重要的是写出可行的代码,然后逐步整理、优化,而不是一开始就进行复杂的设计,例如绘制类图等,这些通常没有实际意义。

这种方法避免了“过度设计”的坏习惯,鼓励更关注实际代码的实现,并逐步将其分解为更简洁、清晰的模块。这是一种非常有效的方式,经过多次实践证明其有效性,强调了本能的编程方式比许多书籍所教的“标准方法”更为高效,尤其是在解决实际问题时。

考虑对一组实体进行操作

在这段内容中,主要讨论了如何优化渲染指令的处理方式。首先,讨论了推送缓冲区(push buffer)中的命令是如何被交错执行的,虽然这种做法可能效率较低,因为每个命令都需要检查其类型并执行相应操作,但目标是尽量精简命令,以避免频繁处理不必要的渲染指令。例如,如果绘制大量粒子效果时,每个粒子都是一个矩形且使用相同的纹理,不应该单独把每个粒子作为一个渲染命令推送到缓冲区。这是因为每个粒子的处理都会引入额外的判断和开销,极大影响性能。

为了优化这一过程,推荐将具有相同纹理或相似渲染需求的物体合并为一个命令。例如,对于具有相同纹理的多个位图图形,可以将它们合并成一个渲染指令,从而减少每个命令的切换和判断开销。虽然推送缓冲区中的命令数量可能很庞大,但为了避免因为粒子数量庞大(可能达到十万甚至更多)而导致性能瓶颈,必须谨慎选择在推送缓冲区中添加的命令。

最终的目标是减少切换和判断的开销,以保证渲染效率。虽然目前开始的实现较为基础,但在未来的优化中,必须考虑如何减少这些开销,确保推送缓冲区的效率不成为瓶颈。

设置处理不同类型条目的情况

在这段内容中,讨论了如何改进处理推送缓冲区条目的方式。首先,将Piece一词更改为Entry,以便更清晰地表示这些条目是什么。在处理这些条目时,首先需要判断条目的类型,然后根据类型执行不同的操作。例如,某个条目可能是一个“clear”操作,另一个可能是一个矩形渲染命令,后者通常用于精灵图像的渲染。
在这里插入图片描述

在这里插入图片描述

当前并没有明确所有条目的类型,但目标是确保能够处理所有可能的情况。为此,需要引入一个机制,能够根据不同类型的条目执行相应的渲染操作。通过这种方式,可以确保在推送缓冲区中的每个条目都能被正确处理,无论它是何种类型。
在这里插入图片描述

引入 InvalidDefaultCase

在这段内容中,讨论了使用一个宏“InvalidDefaultCase”来处理switch语句中的默认情况。这个宏的作用是确保在switch语句中,如果进入默认分支,程序会触发断言(assert),以确保不允许默认情况发生。原因在于,推送到缓冲区的条目应该是可以处理的,如果遇到无法处理的情况,就需要为其添加一个专门的case,但在处理这个case时什么也不做,意味着不处理这种情况。例如,某些特定于OpenGL的情况可能就不需要处理。总之,目标是确保所有被推送到缓冲区的条目都是可以处理的,而不允许进入默认情况。
在这里插入图片描述

根据 Entry->Type 增加 BaseAddress

在这段内容中,讨论了如何调整基地址的变化。在处理条目时,基地址的增量将根据当前条目的内容进行不同的调整,这意味着每个条目的偏移量将依据其具体类型而有所不同。虽然这种方法可能不是最优化的方式,但目的是确保系统能够支持这种方式。最终是否选择这种方式,还需要在后续根据实际效果做进一步评估。

此外,提到了一种可能的替代方案,即通过指针追踪的方式来调整基地址的增量,但目前不确定哪种方式更适合。计划保持灵活性,待到实际实现时根据具体情况决定最终的选择。
在这里插入图片描述

编写这些情况

在这段内容中,讨论了如何处理渲染条目的类型转换。首先,通过将渲染条目(如清除操作或矩形操作)进行类型转换,确保每个条目都被正确识别和处理。这种方式类似于使用带有区分的联合类型(discriminated union),其中根据条目的类型,执行相应的操作。比如,清除操作会被转换为对应的类型,矩形操作则会转换为矩形类型。

此外,还提到了一种可能的改进,即将条目统一命名为“entry”,并将其类型设为“TypelessEntry”或类似名称。这样一来,能够更方便地识别和处理不同类型的条目。处理完每个条目后,将根据条目的大小来推进基地址,确保内存布局和条目顺序正确。
在这里插入图片描述

创建对应的 render_entries

在这段内容中,讨论了如何组织渲染条目,特别是如何将渲染条目分为不同的类型,如“清除(clear)”和“矩形(rectangle)”。为了清晰区分这两种类型,决定为每个类型创建不同的结构体,例如render_entry_clearrender_entry_rectangle。每种类型将拥有不同的字段,例如“清除”条目可能包含一个RGBA值,用于指定清除颜色。

此外,还提到需要为每个条目添加一个头部(header),这个头部将包含条目的类型(如清除或矩形)。考虑是否需要在头部中添加其他字段,但最终决定目前只需要类型字段,因为其他信息暂时没有想到需要添加。

为了进一步简化,考虑将头部命名为“render_group_entry_header”,或者使用更通用的名称“typeless_render_group_entry”,但目前没有决定。最后,提到会用枚举(enum)来表示不同的渲染条目类型,具体包括“clear”和“rectangle”两种类型。
在这里插入图片描述

在这里插入图片描述

描述 “紧凑判别联合体”

在这段内容中,讨论了使用“判别联合体”(discriminated union)来组织不同类型的渲染条目。判别联合体的特点是通过一个类型字段来区分不同的可能类型,这使得每个条目在内存中可以根据其类型分配适当的空间。相比于传统的联合体(union),传统联合体会使用最大尺寸来确保所有类型都能容纳,而判别联合体则使用一个类型字段来判断每个条目的具体类型,从而根据实际类型调整内存的分配大小。

举个例子,假设系统中有两种渲染条目类型:一种是清除操作(clear),另一种是矩形(rectangle)。如果使用传统的联合体,内存分配将为这两种类型中占用空间最大的类型提供足够的空间。例如,clear可能只需要一个RGBA值,而rectangle可能需要更多的数据,如位置、尺寸等。传统联合体会为rectangle分配足够大的空间,以容纳所有可能的数据,但这会浪费内存,因为clear类型只需要小部分空间。

然而,使用判别联合体时,可以通过类型字段来区分这两种类型。当处理清除操作时,只分配必要的内存(如RGBA值的大小),而处理矩形时,则分配矩形需要的内存大小(例如包含位置和尺寸的结构体)。这样,每次处理时,只会根据实际类型的需求来分配内存,不会浪费空间。

为了进一步提高效率,系统决定避免使用固定的最大内存块,而是根据每个条目的类型动态调整内存地址的偏移。例如,在处理矩形时,如果矩形需要更大的内存块,可以根据其实际大小进行内存推进;如果是清除操作,则只推进小量的内存。这种方式可以有效减少内存的浪费,并使得推送缓冲区能够处理任意大小的条目。

至于头部字段的问题,原本计划为每个条目添加一个头部字段,可能包含类型和其他信息,但经过讨论后,认为仅保留类型字段就足够了,这样可以简化结构体的设计。

进一步地,为了提高内存效率,计划将这些类型压缩,而不是使用最大的内存块。这意味着,每次处理条目时,不再按照最大类型大小推进内存,而是根据实际类型的大小来调整内存位置。这种方法的目的是支持推送任意大小的条目到推送缓冲区,这在后续的实现中将证明非常有用。

此外,讨论了是否需要添加一个头部字段(header)。虽然目前仍然保留了头部字段,但认为可能仅需要类型字段。总体来说,目标是通过这种方式有效地管理内存,并确保系统能够灵活地处理不同大小的渲染条目。

回顾我们新的能力

在这段内容中,讨论了如何通过判别联合体处理不同类型的渲染操作,例如清除操作和矩形渲染操作。通过判别联合体的使用,可以根据不同类型的渲染条目采取不同的操作。例如,在遇到清除操作时,可以执行清除操作,而遇到矩形时则执行相应的矩形渲染操作。系统的设计允许在渲染过程中灵活处理不同类型的渲染条目,使得可以扩展支持更多类型的渲染操作。

接下来,计划将矩形操作进一步细化,添加不同类型的矩形,例如矩形轮廓(outline)。这一点体现了通过判别联合体的使用,能够更加灵活地扩展渲染系统,支持更多复杂的渲染类型。此时,可以通过不同的渲染操作类型组合,形成更加丰富的渲染系统。

关于推送缓冲区(push buffer)的操作,强调了在处理过程中所采取的架构决策。通过经验积累,能够较为迅速地做出正确的架构选择,而不需要经历每次都从零开始的尝试。这种经验优势能够帮助在设计系统时做出更加高效的决策。对于没有这种经验的人来说,可能需要更多的迭代和尝试,但最终编程的方式大体上是相似的。

总的来说,判别联合体的使用提高了渲染操作的灵活性,并且经验的积累在系统架构设计中起到了重要作用。
在这里插入图片描述

荒谬技巧:将类型名称与 RenderGroupEntryType 连接以构成标识符,并使用 #define PushRenderElement 宏以类型安全的方式在一步中正确设置类型字段

在这段内容中,讨论了如何在推送渲染元素时,不仅推送渲染元素的大小,还推送渲染元素的类型。为了实现这一点,提出了一个技巧,通过宏来动态生成类型标识符,并将其应用于推送操作。

具体来说,宏 PushRenderElement 被设计成接受渲染组和渲染元素类型作为参数。宏的作用是调用实际的推送函数,传递渲染组,并推送该类型的大小。同时,宏会将类型名称的前缀附加到类型上,从而创建一个带前缀的类型标识符。这个前缀是通过枚举类型中的结构类型名称生成的。

这种做法避免了复杂的模板或不必要的复杂性,同时保持类型安全。在调用 PushRenderElement 时,只需要指定希望推送的类型(例如矩形类型),其他的处理会自动完成。通过这种方式,系统能够正确地设置类型字段,确保类型的一致性,并简化了渲染元素推送的过程。

整体而言,这种方法使得渲染元素的推送更加高效、安全且简洁,避免了冗余的模板操作,并且确保了类型字段的正确性和一致性。
在这里插入图片描述

将类型传递给 PushRenderElement

在这段内容中,讨论了如何在推送渲染元素时处理内存分配和类型信息。当从推送缓冲区获取结果时,计划将结果作为一个“头部”来处理,这意味着不管分配的内存如何,它都会包含某种形式的头部信息。即使某些元素可能不需要该头部,系统也能进行处理,允许没有头部信息的元素插入。如果决定允许这种情况,还可以在更深一层添加推送大小的处理。

此外,提到如果内存空间不足,可以通过在头部进行检查来轻松支持空间不足的情况。当空间不足时,元素会被丢弃,简单地忘记它们即可,不需要更复杂的处理。

总结来说,目标是通过头部信息和类型字段来管理推送的渲染元素,并通过简单的检查确保空间充足,避免复杂的错误处理机制。
在这里插入图片描述

编译并清理

在这段内容中,讨论了如何正确获取并处理渲染元素的头部。首先,获取头部信息后,计划将其转换为相应的类型。这涉及到通过名称的修改来适应不同类型的转换。通过这些步骤,可以确保在内存中正确地管理头部信息,并根据需要将其转换为相应的渲染元素类型。

此外,还提到了一些细节,例如在进行类型转换时需要确保位置正确,以避免错误发生。总体来说,目标是通过这些操作确保渲染元素的类型和头部信息能够正确管理,便于后续操作的顺利进行。
在这里插入图片描述

检查游戏中一切是否正常

讨论了为了简化操作和提升效率,进一步优化了代码结构。通过进行一些调整,目标是让系统能够更方便地处理不同的任务,使得后续的操作更加高效。这种优化为系统提供了更好的区域化管理,使得处理过程更加便捷和直观
在这里插入图片描述

在这里插入图片描述

创建位图类型

在这段内容中,讨论了将原本的“位图”和“矩形”操作分离成两个独立的处理流程。通过这样做,系统能够分别处理位图和矩形,确保每个操作有针对性的实现。在处理时,对于位图,系统会执行相应的位图绘制操作;而对于矩形,则会按矩形的方式绘制。最终,两个不同的操作被分别调用,分别通过对应的推送方法来实现。这种方式提高了代码的清晰度和可维护性,使得不同的渲染操作可以被更独立地处理。
在这里插入图片描述

在这里插入图片描述

为位图调用 PushPiece 函数

在这段内容中,讨论了对位图操作进行逐步处理。首先,继续调用“PushPiece”函数来处理位图类型。在执行时,确保传入正确的类型,以便系统能够正确地处理位图。通过逐步调试和确认每个步骤,保证系统能够正确地处理位图数据。
在这里插入图片描述

由于 Entry->Bitmap 未填充,触发了断言

在这段内容中,讨论了在绘制固体矩形时,可能会遇到断言失败的情况,特别是当位图条目没有填充时。为了避免这种情况,接下来需要进行调整,确保在绘制固体矩形时相关的位图数据已经正确填充。
在这里插入图片描述

确保在调用位图类型时推送一个矩形

在这段内容中,讨论了如何调整代码,以确保在调用绘制矩形的函数时,实际推送的是一个矩形,而不是其他类型的数据。为了确保这一点,暂时通过复制代码的方式来处理,随后再优化代码,避免重复。
在这里插入图片描述

检查游戏中一切是否正常

在这段内容中,提到矩形的绘制虽然按预期工作,但代码中存在重复部分。接下来需要考虑将这些重复的代码提取出来,优化代码结构,以减少冗余和提高可维护性。

将代码压缩成更可用的形式

在这段内容中,计划通过压缩和简化现有的代码来提高可用性。主要目标是将与位置相关的计算(如偏移量和坐标)与形状的绘制分离,创建一个“实体基础”概念,这样可以更清晰地管理实体的位置信息。进一步地,打算通过引入一个函数来处理这些计算,以简化代码,并避免冗余。此外,还提到在处理过程中需要注意位图的尺寸问题,确保这些计算正确处理。
在这里插入图片描述

将偏移量嵌入 PushRect 中

在这段内容中,计划对矩形的绘制进行优化,主要目的是简化坐标和偏移量的计算。通过调整“中心”与“半尺寸”的处理,建议将计算过程更清晰地集中到一个统一的协调点,从而消除原本由于坐标变换带来的复杂性。此外,进一步调整了尺寸计算方式,通过引入“MetersToPixels”的转换来确保矩形绘制更加合理。还讨论了坐标系中的Y轴翻转问题,确保矩形在绘制时的偏移量计算正确。

提取 EntityBasis 计算

在这段内容中,计划对计算过程进行进一步优化,目的是简化并统一实体基础的计算。通过提取出一个用于计算“render_entity_basis”的函数,来避免重复代码。该函数将接受渲染实体基础并计算偏移量,最终返回一个包含这些计算结果的值。进一步的调整包括将entry改为EntityBasis,并清理冗余代码,确保整体代码更简洁和可维护。
在这里插入图片描述

在这里插入图片描述

清理

在这一段中,计划调整函数的输入参数,将ScreenCenterRenderGroup传递给相关的函数,并确保在计算过程中正确处理它们。ScreenCenter可能已经在管道中全程可用,因此可以进一步优化这一点。另外,dim被移除,因为它仅在矩形处理时使用,之后通过调整代码将其放置到矩形部分。接下来需要填充基础结构,调整命名保持一致,并修复可能存在的命名不一致问题。由于在处理时存在一定的注意力分散,可能会有一些错误,但目标是改进代码结构和简化操作。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

看看我们现在的进展

目前代码调整看起来已经顺利进行,基本上已经达到了预期的状态,所有的更改看起来是正确的。到此为止,工作可以暂时停下来,尽管还有一些小的调整,但整体上进展顺利。

当你在游戏中遇到 bug 并能重现它时,你会在编程中看到 bug 行吗,还是它是如何工作的?

当遇到游戏中的错误并能够重现时,通常有两种类型的错误。一种是比较容易追踪的,能快速定位到问题所在并进行修复;另一种则比较复杂,需要花费时间创建特定的情境来推断问题的根本原因,然后再进行修复。至于“bug line”这个术语不太清楚是什么意思,抱歉没有更明确的解释。

关于是否值得对渲染条目进行对齐,这个问题也涉及到优化和代码结构,可能要根据具体的需求来决定是否进行对齐。

是否值得对 render_entries 进行对齐?

目前来说,render_entries不需要特别对齐,因为所有的render_entries都会已经是8字节对齐的。这是因为render_entries中会包含指针,而指针通常是8字节对齐的,所以这种情况下已经足够。但是,当开始处理更为可变大小的内容时,可能需要对齐,以避免把数据放在不对齐的内存地址上,这样做有助于避免性能问题。至于进一步的对齐,可能不会做太多处理,但需要根据实际情况测试。对齐有时能带来性能提升,但有时也可能带来空间浪费,进而影响内存带宽或缓存效率,可能会抵消对齐带来的好处。

至于Mantle,它是一个由AMD推出的低级别图形API,旨在提供比OpenGL和DirectX更直接的硬件访问,从而提高性能。

Mantle 是什么?

Mantle 是AMD推出的一种图形API,旨在提供更直接的硬件访问,主要用于访问其GPU。它比传统的图形API(如OpenGL和DirectX)提供了更为直接的控制,使得开发者能够更高效地与硬件进行交互。

有关 GPU、渲染、光栅化的阅读推荐吗,除了谷歌搜索?

对于关于GPU渲染和光栅化的阅读推荐,推荐访问Fabien Gazin的博客,他是图形编程和优化领域的顶尖程序员之一。在他的博客中,尤其有一篇关于图形管线的文章,非常值得阅读。这篇文章深入讲解了图形工作原理,并且提供了一个良好的起点来理解图形渲染过程。虽然这篇文章发布于2011年,内容可能有些过时,但它依然能提供关于2015年及以前的图形管线的扎实理解,并帮助读者更好地理解后来的更新内容。

如果能花时间深入研究这篇文章,将能大大提高对图形管线的理解,并能轻松阅读其他与图形渲染相关的资料。总的来说,这篇博客被认为是了解图形渲染的一个极为重要的资源。
google 搜索The ryg blog
https://fgiesen.wordpress.com/
博客 不过这个博客好像外网才能访问
在这里插入图片描述

为什么使用指针而不是引用?

在讨论为什么使用指针而不是引用时,指出指针和引用之间实际上没有太大区别,尤其是在不使用C++特性时,二者在CPU执行上没有本质差异。指针和引用都可以实现相同的功能。指针是引用的超集,因为指针可以改变指向的对象,而引用则不能更改指向的对象(尽管有些C++的最新规范似乎允许引用指向的对象变化)。

之所以不使用引用,是因为它们并不带来额外的好处。在实际编码中,指针在做指针运算时更加灵活,而引用只能用于直接的引用,功能相对较弱。因此,倾向于使用指针,因为指针可以做更多事情,而引用则没有这些能力。

关于 Mantle,你是否知道 AMD 已经停止开发它,并将大量人力投入帮助推动 Vulkan?

关于Mantle,虽然已经知道AMD曾试图通过Mantle为Vulkan奠定基础,并在推动Vulkan的过程中做出贡献,但并不清楚AMD已经停止了对Mantle的开发。此前并没有关注到AMD停止支持Mantle的消息。实际上,可能仍然假设他们会在未来某个时刻继续进行Mantle的工作。总的来说,未对AMD的更新有深入关注,因此并不清楚最新的动态。

是一个依赖内存进行通信的抽象层,而不是一堆函数,如果我理解正确的话。这是你通常喜欢的 API 设计方式吗?

对于API设计,倾向于使用基于内存的设计,而不是基于函数的设计。基于内存的API更灵活,具有更高的可扩展性,并且能够支持如跟踪、捕捉等重要功能。相比之下,基于函数的API通常更复杂、更难以文档化,容易变得杂乱无章。对于渲染器这类问题明确、输入输出清晰的场景,基于内存的API设计尤其合适。然而,在一些更为复杂的场景中,比如整个游戏系统的API设计,基于内存的设计可能就不适用了,因为它会过于复杂。总体而言,在遇到明确问题时,倾向于采用基于内存的API设计。

相关文章:

游戏引擎学习第89天

回顾 由于一直没有渲染器,终于决定开始动手做一个渲染器,虽然开始时并不确定该如何进行,但一旦开始做,发现这其实是正确的决定。因此,接下来可能会花一到两周的时间来编写渲染器,甚至可能更长时间&#xf…...

备战蓝桥杯-洛谷

今天打算写一些洛谷上面的题目 P10904 [蓝桥杯 2024 省 C] 挖矿 https://www.luogu.com.cn/problem/P10904 看了大佬写的题解才写出来这道题的:题解:P10904 [蓝桥杯 2024 省 C] 挖矿 - 洛谷专栏 思路: 这是一道贪心的题目,用…...

动手学图神经网络(9):利用图神经网络进行节点分类 WeightsBiases

利用图神经网络进行节点分类Weights&Biases 引言 在本篇博客中,将深入探讨如何使用图神经网络(GNNs)来完成节点分类任务。以 Cora 数据集为例,该数据集是一个引用网络,节点代表文档,推断每个文档的类别。同时,使用 Weights & Biases(W&B)来跟踪实验过程和…...

如何在 FastAPI 中使用本地资源自定义 Swagger UI

要自定义 FastAPI 中的 Swagger UI,且使用本地资源来代替 CDN。只是需要稍微修改一下。 修改后的代码: 步骤: 挂载本地静态文件目录:我们将本地的 Swagger UI 资源文件(如 .js, .css, favicon.png 等)放…...

Swift 进阶:Observation 框架中可观察(@Observable)对象的高级操作(上)

概述 在 WWDC 24 中苹果推出了全新的 Observation 框架,借助于它我们可以更加细粒度的监听可观察(@Observable)对象 。同时,SwiftUI 自身也与时偕行开始全面支持 @Observable 对象的“嵌入”。 然而在这里,我们却另辟蹊径来介绍 @Observable 对象另外一些“鲜为人知”的故…...

aws(学习笔记第二十七课) 使用aws API Gateway+lambda体验REST API

aws(学习笔记第二十七课) 使用aws API Gatewaylambda体验REST API 学习内容: 使用aws API Gatewaylambda 1. 使用aws API Gatewaylambda 作成概要 使用api gateway定义REST API,之后再接收到了http request之后,redirect到lambda进行执行。…...

UE学习日志#23 C++笔记#9 编码风格

注:此文章为学习笔记,只记录个人不熟悉或备忘的内容 1 为代码编写文档 1.1 使用注释的原因 1.说明用途的注释 应该注释的信息:输入,输出含义,参数的类型含义,错误条件和处理,预期用途&#x…...

vue2-vue自定义指令

文章目录 vue2-vue自定义指令1. 什么是指令2. 自定义指令2.1 全局注册2.2 局部注册 3. 自定义指令的钩子函数4. 钩子函数的参数4. 用例 vue2-vue自定义指令 1. 什么是指令 在vue中提供了一套为数据驱动视图更为方便的操作,这些操作被称为指令系统我们平时使用的v-…...

[250202] DocumentDB 开源发布:基于 PostgreSQL 的文档数据库新选择 | Jekyll 4.4.0 发布

目录 DocumentDB 开源发布:基于 PostgreSQL 的文档数据库新选择DocumentDB 的使命DocumentDB 的架构 Jekyll 4.4.0 版本发布🆕 新特性与改进 DocumentDB 开源发布:基于 PostgreSQL 的文档数据库新选择 微软近日宣布开源 DocumentDB&#xff…...

matplotlib绘制三维曲面图时遇到的问题及解决方法

在科学计算和数据可视化中,三维曲面图是非常有用的工具,可以直观地展示数据的三维分布和关系。Matplotlib是Python中广泛使用的数据可视化库之一,提供了强大的三维绘图功能。然而,在实际使用过程中,用户可能会遇到各种…...

【数据结构】(4) 线性表 List

一、什么是线性表 线性表就是 n 个相同类型元素的有限序列,每一个元素只有一个前驱和后继(除了第一个和最后一个元素)。 数据结构中,常见的线性表有:顺序表、链表、栈、队列。 二、什么是 List List 是 Java 中的线性…...

简单React项目从0到1

文章目录 项目搭建基于CRA创建项目调整项目目录结构 使用scss预处理器组件库antd使用配置基础路由配置别名路径路径编译配置VsCode提示配置 基本结构搭建表单校验实现获取登录表单数据封装request工具模块使用Redux管理token安装Redux相关工具包配置Redux 实现登录逻辑token持久…...

IM 即时通讯系统-46-OpenIM 提供了专为开发者设计的开源即时通讯解决方案

IM 开源系列 IM 即时通讯系统-41-开源 野火IM 专注于即时通讯实时音视频技术,提供优质可控的IMRTC能力 IM 即时通讯系统-42-基于netty实现的IM服务端,提供客户端jar包,可集成自己的登录系统 IM 即时通讯系统-43-简单的仿QQ聊天安卓APP IM 即时通讯系统-44-仿QQ即…...

MFC 学习笔记目录

序章 MFC学习笔记专栏开篇语-CSDN博客 下载与安装 VS2010 下载与安装 VS2019...

一文讲解Java中的ArrayList和LinkedList

ArrayList和LinkedList有什么区别? ArrayList 是基于数组实现的,LinkedList 是基于链表实现的。 二者用途有什么不同? 多数情况下,ArrayList更利于查找,LinkedList更利于增删 由于 ArrayList 是基于数组实现的&#…...

【Linux系统】线程:线程的优点 / 缺点 / 超线程技术 / 异常 / 用途

1、线程的优点 创建和删除线程代价较小 创建一个新线程的代价要比创建一个新进程小得多,删除代价也小。这种说法主要基于以下几个方面: (1)资源共享 内存空间:每个进程都有自己独立的内存空间,包括代码段…...

HTML 复习

文章目录 路径问题标题标签段落标签换行标签列表标签<ol> 有序列表<ul> 无序标签标签嵌套 超链接标签多媒体标签<img> 图片标签<audio> 音频标签<video> 视频标签 表格标签<colspan> 跨行<rowspan> 跨列组合使用 表单标签基本表单标…...

网络爬虫学习:借助DeepSeek完善爬虫软件,增加停止任务功能

一、引言 我从24年11月份开始学习网络爬虫应用开发&#xff0c;经过2个来月的努力&#xff0c;终于完成了开发一款网络爬虫软件的学习目标。这几天对本次学习及应用开发进行一下回顾总结。前面已经发布了两篇日志&#xff1a; 网络爬虫学习&#xff1a;应用selenium从搜*狐搜…...

【数据结构】单向链表(真正的零基础)

放弃眼高手低&#xff0c;你真正投入学习&#xff0c;会因为找到一个新方法产生成就感&#xff0c;学习不仅是片面的记单词、学高数......只要是提升自己的过程&#xff0c;探索到了未知&#xff0c;就是学习。 目录 一.链表的理解 二.链表的分类&#xff08;重点理解&#xf…...

8. k8s二进制集群之Kubectl部署

创建kubectl证书请求文件生成admin证书文件复制admin证书到指定目录生成kubeconfig配置文件接下来完成kubectl配置文件的角色绑定【扩展】kubectl命令补全操作继续上一篇文章《k8s二进制集群之Kube ApiServer部署》下面介绍一下k8s中的命令行管理工具kubectl。 通过kubectl可以…...

115,【7】 攻防世界 web fileinclude

进入靶场 试着访问了几个文件&#xff0c;都没得到信息&#xff0c;f12看看源码 还真有 <?php // 检查是否开启了错误显示功能 // ini_get 函数用于获取 PHP 配置选项的值&#xff0c;这里检查 display_errors 选项是否开启 if( !ini_get(display_errors) ) {// 如果错误…...

RabbitMQ 从入门到精通:从工作模式到集群部署实战(二)

接上篇&#xff1a;《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;一&#xff09;》 链接 文章目录 4.安装RabbitMQ Messaging Topology Operator 裸金属环境部署RabbitMQ部署单实例部署集群 4.安装RabbitMQ Messaging Topology Operator 使用 cer…...

【MySQL】MySQL经典面试题深度解析

文章目录 一、MySQL与C的深度结合1.1 为什么C项目需要MySQL&#xff1f;1.2 典型应用场景 二、基础概念面试题精讲2.1 存储引擎对比2.2 索引原理 三、C专项面试题解析3.1 连接池实现3.2 预处理语句3.3 批量操作优化 四、高级应用面试题剖析4.1 事务隔离级别4.2 锁机制详解4.3 查…...

小程序-基础加强

前言 这一节把基础加强讲完 1. 导入需要用到的小程序项目 2. 初步安装和使用vant组件库 这里还可以扫描二维码 其中步骤四没什么用 右键选择最后一个 在开始之前&#xff0c;我们的项目根目录得有package.json 没有的话&#xff0c;我们就初始化一个 但是我们没有npm这个…...

vscode+CMake+Debug实现 及权限不足等诸多问题汇总

环境说明 有空再补充 直接贴两个json tasks.json {"version": "2.0.0","tasks": [{"label": "cmake","type": "shell","command": "cmake","args": ["../"…...

零基础Vue入门6——Vue router

本节重点&#xff1a; 路由定义路由跳转 前面几节学习的都是单页面的功能&#xff08;都在专栏里面https://blog.csdn.net/zhanggongzichu/category_12883540.html&#xff09;&#xff0c;涉及到项目研发都是有很多页面的&#xff0c;这里就需要用到路由&#xff08;vue route…...

【疑海破局】一个注解引发的线上事故

【疑海破局】一个注解引发的线上事故 1、问题背景 在不久前一个阳光明媚的上午,我的思绪正在代码中游走、双手正在键盘上飞舞。突然,公司内部通讯工具上,我被拉进了一个临时工作群,只见群中产品、运营、运维、测试等关键人员全部严阵以待,我就知道大的可能要来了。果不其…...

C语言:函数栈帧的创建和销毁

目录 1.什么是函数栈帧2.理解函数栈帧能解决什么问题3.函数栈帧的创建和销毁的过程解析3.1 什么是栈3.2 认识相关寄存器和汇编指令3.3 解析函数栈帧的创建和销毁过程3.3.1 准备环境3.3.2 函数的调用堆栈3.3.3 转到反汇编3.3.4 函数栈帧的创建和销毁 1.什么是函数栈帧 在写C语言…...

IDEA启动项目慢问题处理

IDEA启动项目慢问题处理 一、问题现象二、问题排查排查点1&#xff1a;idea内存排查点2&#xff1a;应用内存排查点3&#xff1a;shorten command lineclasspath filejar manifest 排查点4&#xff1a;jstack排查 三、问题定位 一、问题现象 多模块工程&#xff0c;启动模块为…...

Denavit-Hartenberg DH MDH坐标系

Denavit-Hartenberg坐标系及其规则详解 6轴协作机器人的MDH模型详细图_6轴mdh-CSDN博客 N轴机械臂的MDH正向建模&#xff0c;及python算法_mdh建模-CSDN博客 运动学3-----正向运动学 | 鱼香ROS 机器人学&#xff1a;MDH建模 - 哆啦美 - 博客园 机械臂学习——标准DH法和改进MDH…...

Unity 快速入门 1 - 界面操作

本项目将快速介绍 Unity 6的基本操作和功能&#xff0c;下载附件的项目&#xff0c;解压到硬盘&#xff0c;例如 D:\Unity Projects\&#xff0c; 注意整个文件路径中只有英文、空格或数字&#xff0c;不要有中文或其他特殊符合。 1. 打开Unity Hub&#xff0c;点击右上角的 O…...

美国网络司令部军事网络指挥框架战略转型与挑战分析

文章目录 前言一、框架核心内容&#xff1a;从分散到集中&#xff0c;构建标准化作战体系二、指挥体系重构&#xff1a;权责明晰与集中化管控三、风险管理创新&#xff1a;从被动防御到主动备战四、对美军网络作战的影响总结 前言 2024年9月&#xff0c;美国网络司令部发布《国…...

9-收纳的知识

[ComponentOf(typeof(xxx))]组件描述&#xff0c;表示是哪个实体的组件 [EntitySystemOf(typeof(xxx))] 系统描述 [Event(SceneType.Demo)] 定义事件&#xff0c;在指定场景的指定事件发生后触发 [ChildOf(typeof(ComputersComponent))] 标明是谁的子实体 [ResponseType(na…...

Linux 压缩打包

Linux压缩打包 文章目录 Linux压缩打包压缩的意义和原理压缩的意义压缩的原理压缩与解压缩的好处压缩打包命令.zipzip 命令用法unzip 的用法.gzgzip 的用法gunzip 的用法.bz2bzip2 的用法bunzip2 的用法.xzxz 命令用法tar04-Linux压缩打包课后习题压缩的意义和原理 压缩的意义…...

排序算法--堆排序

堆排序是一种高效的排序算法&#xff0c;适合大规模数据排序&#xff0c;尤其适用于需要实时获取最大&#xff08;或最小&#xff09;值的场景。 // 交换两个元素的值 void swap(int* a, int* b) {int temp *a;*a *b;*b temp; }// 调整堆&#xff0c;使其满足堆的性质 void …...

51c视觉~CV~合集10

我自己的原文哦~ https://blog.51cto.com/whaosoft/13241694 一、CV创建自定义图像滤镜 热图滤镜 这组滤镜提供了各种不同的艺术和风格化光学图像捕捉方法。例如&#xff0c;热滤镜会将图像转换为“热图”&#xff0c;而卡通滤镜则提供生动的图像&#xff0c;这些图像看起来…...

【数据结构】(6) LinkedList 链表

一、什么是链表 1、链表与顺序表对比 不同点LinkedListArrayList物理存储上不连续连续随机访问效率O(N)O(1&#xff09;插入、删除效率O(1)O(N) 3、链表的分类 链表根据结构分类&#xff0c;可分为单向/双向、无头结点/有头节点、非循环/循环链表&#xff0c;这三组每组各取…...

使用 Axios 获取用户数据并渲染——个人信息设置

目录 1. HTML 部分&#xff08;前端页面结构&#xff09; HTML 结构解析&#xff1a; 2. JavaScript 部分&#xff08;信息渲染逻辑&#xff09; JavaScript 解析&#xff1a; 3. 完整流程 4. 总结 5. 适用场景 本文将介绍如何通过 Axios 从服务器获取用户信息&#xff0…...

【hudi】基于hive2.1.1的编译hudi-1.0.0源码

hudi版本1.0.0 需要使用较低版本的hive&#xff0c;编译hudi只需要修改下类即可&#xff1a; org.apache.hudi.hadoop.hive.HoodieCombineHiveInputFormat 一、复制org.apache.hadoop.hive.common.StringInternUtils 找个hive2.3.9的源码包&#xff0c;创建包路径&#xff0c…...

物联网领域的MQTT协议,优势和应用场景

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为轻量级发布/订阅协议&#xff0c;凭借其低带宽消耗、低功耗与高扩展性&#xff0c;已成为物联网通信的事实标准。其核心优势包括&#xff1a;基于TCP/IP的异步通信机制、支持QoS&#xff08;服务质量&…...

MyBatis 调优指南:释放持久层性能潜力

MyBatis 作为一款优秀的持久层框架&#xff0c;以其灵活性和易用性深受开发者喜爱。然而&#xff0c;随着应用规模扩大和数据量增长&#xff0c;MyBatis 的性能问题也逐渐显现。本文将深入探讨 MyBatis 调优策略&#xff0c;帮助您释放持久层性能潜力。 一、 SQL 语句优化 避免…...

Unity扩展编辑器使用整理(一)

准备工作 在Unity工程中新建Editor文件夹存放编辑器脚本&#xff0c; Unity中其他的特殊文件夹可以参考官方文档链接&#xff0c;如下&#xff1a; Unity - 手册&#xff1a;保留文件夹名称参考 (unity3d.com) 一、菜单栏扩展 1.增加顶部菜单栏选项 使用MenuItem&#xff…...

注册中心不知选哪个?Zookeeper、Eureka、Nacos、Consul和Etcd 5种全方位剖析对比

本文给大家讲解 5 种常用的注册中心&#xff0c;对比其流程和原理&#xff0c;无论是面试还是技术选型&#xff0c;都非常有帮助。 对于注册中心&#xff0c;在写这篇文章前&#xff0c;我其实只对 ETCD 有比较深入的了解&#xff0c;但是对于 Zookeeper 和其他的注册中心了解甚…...

Windows下怎么安装FFFmpeg呢?

在Windows下使用Open-webui报错&#xff0c;说Couldnt find ffmpeg or avconv,解决open-webui报错Couldn‘t find ffmpeg or avconv-CSDN博客于是尝试解决问题&#xff0c;那么Windows下怎么安装FFFmpeg呢&#xff1f; 尝试了两种方法。 第一种方法pip安装&#xff08;失败&…...

CSS 基础:层叠、优先级与继承

CSS 基础&#xff1a;层叠、优先级与继承 一、层叠&#xff08;Cascade&#xff09;示例&#xff1a;层叠的顺序 二、优先级&#xff08;Specificity&#xff09;优先级规则示例&#xff1a;优先级的比较 三、继承&#xff08;Inheritance&#xff09;哪些属性会被继承&#xf…...

《翻转组件库之发布》

背景 继《翻转组件库之打包》_杨晓风-linda的博客-CSDN博客之后&#xff0c;组件库已经可以正常构建&#xff0c;那如何像elementUI等组件库那样&#xff0c;用npm安装&#xff0c;按照既定的用法使用即可呢&#xff1f;本篇便为你揭晓 资料相关 1、npm官方文档&#xff1a;…...

Spring Boot + Spring AI快速体验

Spring AI快速体验 1 什么是Spring AI 主要功能 2 快速开始 2.1 版本说明2.2 配置文件2.3 pom依赖 2.3.1 spring maven仓库2.3.2 核心依赖 2.4 定义ChatClient2.5 启动类2.6 测试 3 参考链接 1 什么是Spring AI Spring AI是Spring的一个子项目&#xff0c;是Spring专门面向于…...

windows linux常用基础命令

windows基础命令 cd …/ &#xff08;访问D盘 直接D: 进入目录cd…\baidudu) color 2 改变颜色 dir 浏览当前目录中有什么内容 例如 dir windows可以浏览windows中有什么文件 cls 清屏 cd windows 可以跳转到c盘目录的下面 cd…/可以返回到上一级目录 ./当前目录 cd \ 直…...

ZooKeeper单节点详细部署流程

ZooKeeper单节点详细部署流程 文章目录 ZooKeeper单节点详细部署流程 一.下载稳定版本**ZooKeeper**二进制安装包二.安装并启动**ZooKeeper**1.安装**ZooKeeper**2.配置并启动**ZooKeeper** ZooKeeper 版本与 JDK 兼容性3.检查启动状态4.配置环境变量 三.可视化工具管理**Zooke…...

【AI日记】25.02.06

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】【读书与思考】 AI kaggle 比赛&#xff1a;Backpack Prediction Challenge 读书 书名&#xff1a;理解公司&#xff1a;产权、激励与治理作者&#xff1a;张维迎下图感想&#xff1a;哲学家、思想家比如卢梭…...