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

游戏引擎学习第107天

仓库:https://gitee.com/mrxiao_com/2d_game_2

回顾我们之前停留的位置

在这段内容中,讨论了如何处理游戏中的三维效果,特别是如何处理额外的“Z层”。由于游戏中的艺术资源是位图而不是3D模型,因此实现三维效果变得非常具有挑战性。虽然可以通过让游戏保持在一个平面上并避免涉及上下的元素来简化问题,但这并不是当前的目标。相反,目标是探索如何在不放弃位图艺术的情况下,通过各种方法模拟Z深度,以增强游戏的三维感。

接下来,讨论了如何处理这些Z层的复杂性,尤其是在程序开发过程中没有一个完美的解决方案。相比于其他相对容易解决的问题,例如纹理映射,处理Z层涉及更多复杂的决策过程。在这一过程中,目标是逐步探索这些问题,并尝试找到清晰且有效的渲染设计,使得Z深度感能够在游戏中得到体现。

在之前的工作中,已经有一个包含两个Z层的测试世界,并且关闭了地面块的渲染。接下来的工作是重新启用这些地面块的渲染,并开始处理Z切片的概念。在这一过程中,开发者希望通过调整相机的位置并观察不同层级的元素如何变化,来更好地理解Z层的效果。最终的目标是让这些Z切片能够合理地展示,并为游戏中的三维效果提供更清晰的视觉呈现。

解释 Z 切片的必要性

这段内容讨论了在游戏中实现Z层次的具体变化,目标是确保Z层在游戏世界中能够有一致性和结构性。由于游戏使用的是位图艺术,而位图本身不能很好地表达三维信息,因此需要通过“固定的Z切片”来解决这一问题。

首先,提到的核心概念是“Z切片”,这些切片与当前的“chunkz”概念相吻合,目的是将世界分成不同的层次。每个层次都被视为一个独立的实体,游戏中的所有对象都被归类到不同的Z切片中,并且不能同时跨越多个Z切片。如果要跨越多个Z层次,则需要在每个层次上都有相应的艺术资源,这样可以避免在视觉上造成混乱。

在设计中,如果不同层次之间存在视觉断层,虽然可能导致一定的视觉破裂,但这也是艺术风格的一部分,因此可以接受。如果这种断层效果影响太大,可能会考虑关闭某些缩放效果,使所有层次之间更为一致,确保艺术资源的顶部和底部对齐。然而,由于游戏并不依赖于高大的结构,基本上可以通过将世界视作一系列独立的“外壳”来处理这些问题。

通过这样的设计,游戏中的实体可以在这些Z层之间自由移动而不会造成问题,整体来看,这种方法应该是可行的。

看一下我们的 SimRegion 如何处理实体的解包

目前的工作是检查如何在游戏中处理实体的解包,特别是关于模拟区域(SimRegion)部分。解包实体的过程大致是这样的:通过相机查看所有被触及的区域,遍历这些区域并将所有的实体提取出来,然后将它们添加到模拟区域中,最后完成解包操作。

在这个过程中,当前的做法是维护一个“Chunkz”概念,它帮助追踪实体的Z层次,但并没有实际利用偏移的Z值(Offsetz)。这意味着,虽然相机的Z坐标是被保留的,避免了Z值丢失,但在当前的实现中,相机在不同Z层之间的过渡并不是平滑的,而是以跳跃的方式进行。也就是说,相机在Z层之间移动时,并不会产生流畅的过渡,而是直接从一个层次跳到另一个层次。

最终,目标是使得相机在Z层之间的过渡更加平滑,而不是采用目前的跳跃式过渡。

在这里插入图片描述

去掉 ZOffset 并重新启用 DrawRectangle

在这个过程中,决定移除之前添加的Z偏移量(offset),并回退到之前的设置。Z偏移量的移除是为了简化代码并确保功能能够按预期运行。

在做这些修改之后,运行代码时发现之前的矩形绘制功能被禁用了,因此需要重新启用该功能。通过回顾代码,发现矩形绘制逻辑已经正确更新,只是因为工作时忘记启用绘制功能,所以没有显示出来。启用之后,矩形绘制功能恢复正常,房间的边界线再次显示出来。

此外,虽然目前没有艺术资源来填充楼梯的区域,但测试时能够看到角色成功地走上楼梯并进入上层。这表明Z层的逻辑在处理楼层过渡时已经能够正常工作,尽管在视觉效果上还没有完全实现。
在这里插入图片描述

关闭相机捕捉

在此过程中,决定关闭Z块的跳跃,使相机的运动更加平滑和连续。通过检查代码,发现相机的Z偏移量没有被使用,因此决定让偏移量基于相机的位置进行调整。通过这样修改,相机的Z轴运动变得更加平滑,能够看到层次之间的过渡效果。

接下来,需要引入一致性的概念,即控制哪些层在不同的Z轴位置上应当显示或隐藏。特别是当视角处于较低的位置时,地面可能会遮挡视线,使得上层内容无法被看到。因此,需要确保在视角向上移动时,原本遮挡的层会逐渐显示出来,避免不需要的内容在不合适的时机显示。

这一步骤的目的是确保视觉上的渐变效果,只有在相机移动到一定高度时,才会让上一层逐渐显现,从而实现更加自然和符合预期的画面过渡。
在这里插入图片描述

解释固定 Z 切片的概念

为了实现目标,首先需要引入“Z切片”的概念。这是为了确保能够明确知道相对于这些切片的位置。每个切片表示在世界中的不同高度层次,因此需要设计一个能够处理这些层次查询的系统。

目标是让世界结构能够回答以下问题:给定一个空间中的某个点,返回该点所在的地面层级,以及它上面和下面的层级。通过这种方式,能够更清楚地知道当前的位置以及所在层级,确保在不同的Z轴层次之间切换时能够获得正确的效果。

这意味着不需要在代码的其他地方到处手动管理每个层次的位置,而是通过集中查询来获取有关层次的信息。这样可以简化未来可能的修改,使得即便在未来需要为某些特殊区域设计不同的层次处理逻辑时,也能够在不影响其他部分的情况下处理这些特殊情况。

此外,提供了一个可以灵活处理不同区域特殊需求的查询机制,让世界结构可以在必要时做出相应调整,但对其他部分的逻辑不会造成影响。这种结构可以为以后可能的复杂情况留出空间,并使得世界的层次划分更加清晰、可维护。

移动 GlobalAlpha

在当前的世界结构中,使用了一个全局透明度值(GlobalAlpha),虽然这个值被认为不太理想,但目前会先用它来确保功能正常运行。在确保基础功能后,计划将全局透明度值移除,转而使用渲染目标的方式来处理渐变效果,使得不同层次之间能够实现更精确的过渡。

每个实体的透明度(alpha)值将根据其在世界中的位置来动态调整,而不再依赖全局透明度。这意味着每个实体可以根据其高度来设定透明度,而不需要通过全局透明度控制整个场景。

然而,当前存在一个问题,即在渲染实体时,无法准确确定敌人的最终位置,因为模拟尚未完成。这暴露了一个潜在的问题,即渲染过程与更新过程之间的耦合性过高。为了解决这个问题,可能需要在更新和渲染之间做出明确的分离,尽管这一点最初并不打算提前处理,但这可能是接下来需要考虑的重要改进。
在这里插入图片描述

关于分离实体的更新和渲染

之前讨论过一个问题,更新和渲染为什么要合并为一个过程。这样做的架构设计是为了提高效率,使得某些内容能够在同一过程内更新和渲染,避免不必要的操作。不过,在一些情况下,更新和渲染可能需要分开处理,尤其是在需要更多灵活性的实体和粒子系统中。

对于实体,考虑到目前的工作方式,可能会将更新和渲染分成不同的阶段,这样可以提供更多的灵活性和控制。而粒子系统等其他内容,可能更适合同时更新和渲染,因为这样做会更高效。

总的来说,建议在没有明确需求的情况下,保持更新和渲染一起进行,只有在确定分开能够带来效率提升时,才会将其分开。这样可以避免不必要的操作,比如频繁地从缓存中拉取和存入数据。但当前的阶段可以暂时不考虑这些优化,使用一帧的延迟来处理透明度问题,等以后再做进一步调整。

根据 GroundP 设置 GlobalAlpha

首先,设置了一个全局透明度(GlobalAlpha)值,并且希望根据实体的位置来调整这个透明度值。为了实现这一点,首先需要查看实体的实际位置,并通过一个查询函数(比如 getGroundPoint)来确定该实体的地面位置。

然后,根据实体与相机之间的距离,来调整全局透明度值。相机的位置是固定的,通常位于同一空间区域的中心。通过计算实体位置和相机位置之间的差距,便可以得出透明度应该如何变化。

目前,全局透明度值的设定是一个临时解决方案,只是为了测试而使用,不打算长期保持。在代码中,使用了 getGroundPoint 函数获取实体的地面位置,并基于这个位置来调整透明度。但由于全局变量的使用存在一定的风险,因此希望将这种方法替换为更干净的实现方式。

总的来说,现在的透明度调整机制只是一个临时手段,用来测试效果,未来会考虑更合适的方式来处理这一问题,避免依赖全局变量,保持代码的清晰和可维护性。
在这里插入图片描述

引入 CameraP

在这里讨论了相机位置的处理问题。最初,认为相机的位置应该固定在原点,但考虑到将来可能需要支持相机不在原点的情况,因此决定加入相机位置的处理。目的是确保无论相机位置如何,都能正确渲染实体。

为此,决定引入相机位置的概念,并计算相机相对于当前区域的位移。通过这种方式,在渲染时可以根据相机的位置调整实体的位置,确保它们能够相对于相机正确显示。

虽然现在假设相机位于中心,但为了更灵活地处理将来的需求,相机位置会被计算并保存,以便在未来的渲染过程中调整。当前假设相机的初始位置为区域的中心,在实现时可以通过减去相机位置和区域中心点的位置来得出相机相对区域的位置。

这种方法确保了可以在不破坏系统的情况下调整相机位置,并且会自动处理在不同位置的相机。在实际实现时,可能会通过调整相机位置来实现不同的视角需求。

在这里插入图片描述

从 CameraRelativeGroundP 设置 GlobalAlpha

首先,想要做的是计算相机相对地面的位置。具体方法是,将地面点的坐标减去相机的位置,这样就能得到相对位置。接下来,通过计算该位置的 z 值来确定实体的高度,从而得出该实体相对于相机的高低。

为了实现渐变效果,使用某种函数来控制透明度,确保透明度的值在 0 到 1 之间。具体操作是,如果实体的位置在相机下面(即 z 值为负或零),则不进行处理。否则,采用某种方式来控制其透明度,设定一个距离阈值(例如 1.5 米),当实体超过这个距离时,它的透明度将稳定下来,逐渐消失。
在这里插入图片描述

看看游戏中的淡入效果

整体上,效果看起来相当不错。当角色向上移动时,透明度逐渐增加,产生了平滑的淡入效果;而当角色向下移动时,透明度则逐渐减少,产生了淡出效果。通过这种方式,实体的位置变化与透明度的过渡相结合,营造出了良好的视觉效果,表现出随着位置变化,实体在视觉上的渐变变化。
在这里插入图片描述

使其更正式一点

当前的透明度渐变处理方式采用了一种临时的、即兴的方式,因此需要进行规范化,以便能够基于实际值进行调整。首先,定义渐变的起始FadeStartZ和结束位置FadeEndZ,在z轴上划分切片,这些切片需要进行渐变处理。目标是明确渐变何时开始,何时结束,确保没有任何混乱。通过设定渐变的开始和结束位置,可以更加精确地控制每个切片的透明度变化,从而实现更加灵活和清晰的渐变效果。
在这里插入图片描述

Blackboard: 指定关卡的可见性

为了实现透明度渐变效果,需要对渐变区域进行参数化处理,确保能够控制不同层次之间的可见性。具体来说,可以通过设置多个渐变起始和结束位置来定义可见区域与不可见区域之间的过渡。首先,在摄像机与某个特定高度之间的区域内,物体将保持完全可见。然后,随着高度的增加,物体将开始逐渐消失,直到完全不可见。为了进一步细化控制,可能需要设置不同的渐变参数,以处理上下不同的渐变区域。比如,可以定义上方和下方的渐变起始和结束点,确保在某些特定高度区域物体不会完全消失,而是在视线中逐渐淡出。

此外,由于物体的高度范围可能不同,需要考虑不同层次的地面之间的渐变效果。为了避免遮挡视线,尤其是在俯视场景时,需要将每一层的渐变值根据其在场景中的实际位置进行调整。因此,每个地面层的渐变范围可能需要不同的处理方式,从而确保每一层的地面在适当的时候可以逐步显现或消失,而不会影响玩家的视野。

引入FadeIn淡入位置标记

为了实现渐变效果,需要定义渐变的起始和结束高度,并在这些高度之间进行平滑的透明度变化。首先,可以设定一个“渐变开始”的上方高度和下方高度(例如上方距离1米,下方距离2层楼)。这些值会决定物体开始淡出的时机和位置。上方和下方的渐变将根据设置的起始位置、结束位置以及透明度值来调整。

对于上方的渐变,物体会在从摄像机开始的某个高度处逐渐淡出,直到到达一个特定的高度(例如地面高度或某个层次),并且一旦超过这个高度,物体就完全不可见。对于下方的渐变,物体会在一个较低的高度开始淡出,直到到达另一个不可见的底部区域。

透明度(Alpha)值的计算将根据物体与摄像机的相对高度来决定。如果物体的相对高度大于“渐变上方起始值”,则物体开始在上方渐变消失;如果物体的相对高度小于“渐变下方起始值”,则物体开始在下方渐变消失。根据这些条件,可以动态调整透明度,实现上方和下方的渐变效果。

最终,整个渐变过程会根据具体的游戏世界设置来调整,使物体在不同高度区域内平滑过渡,不会直接消失或突然出现。
在这里插入图片描述

引入 Clamp01MapToRange

为了实现透明度渐变,计划引入一个范围函数,用于将一个值标准化到0到1之间。这个函数接收三个参数:最小值(min)、最大值(max)和目标值(t)。它的目标是计算出目标值相对于最小值和最大值的位置,并将结果转化为一个0到1之间的值。

首先,定义一个范围值,即最大值减去最小值。接着,通过检查范围是否大于零,避免除零错误。如果范围大于零,则计算目标值与最小值的差,并将其除以范围值,从而将目标值规范化为0到1之间。如果范围为负值,计算方式也能正常工作,只是会反转计算的方向,这依然是可以接受的。

通过这个函数,可以将相对位置(如相机相对的Z坐标)与渐变起始和结束的Z坐标进行比较,并计算出该值在渐变范围内的位置。根据计算的结果,可以决定渐变的透明度,从而实现平滑的过渡效果。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

游戏中查看并修正淡入方向

接着,发现问题的根源可能是 fade end z 的设置问题。为了避免物体在未达到目标高度时就部分可见,fade end z 必须与地面高度对齐。即如果 fade end z 没有在地面高度时结束,物体就会部分可见,从而导致问题。

方便调试改一下窗口大小
在这里插入图片描述

在这里插入图片描述

允许我们上升到另一个层次

目前的世界生成系统只允许楼层之间堆叠两个房间,但希望能够扩展到多个楼层,以支持更多复杂的结构。当前的实现存在限制,无法自由选择上楼或下楼。要实现这一目标,可以修改房间生成逻辑,让门的方向(向上或向下)可以分别独立选择,从而允许房间在不同的高度进行堆叠,避免一开始就局限于两层。

在尝试解决这个问题时,遇到一个困境:生成的楼层没有正确堆叠,导致玩家可以走下楼梯进入一个空的空间。这是因为生成门时没有正确处理门的方向,默认假设门总是指向正确的位置。为了解决这一问题,需要修改生成逻辑,确保根据门的方向调整相应的高度。如果门是向下的,则需要调整 Z 坐标以便正确生成下层,如果是向上的,则相应调整 Z 坐标以生成上层。

为进一步调试,尝试优化了墙壁的生成,限制了墙壁的数量,以便减少渲染负担,同时避免不必要的计算。然而,当前的生成逻辑依然存在问题,例如玩家可以随意穿越墙壁,这需要进一步改进。

此外,为了测试多层堆叠房间的效果,需要调整生成逻辑,使其更倾向于创建多个上下楼的门,而不是随机生成。具体来说,可以引入一种方法,使得生成的楼梯不会重叠,从而可以自由地堆叠多个楼层,避免生成逻辑中出现重复的楼梯。最终,目标是创建一个能够生成多层建筑,并且每层之间有清晰上下通道的世界。
在这里插入图片描述

做了什么

在尝试修改生成逻辑以确保门始终朝下时,意图是将门的方向固定为向下,从而避免其他情况的出现。然而,这样的修改带来了一些意外的后果。现在生成的楼层似乎过多,并且发生了交叉现象,看起来好像超出了预定的阈值,并且可能触发了某种翻转错误。这个问题需要进一步调试,以了解为什么会有这么多层级,并找出原因。

同时,也对实体的生成产生了疑问。原本只打算在一个有限的区域内生成实体,但现在发现有许多实体出现在不该出现的地方。这个问题需要检查生成过程中是否存在误操作,特别是在 Z 坐标的处理上,可能导致了不必要的实体生成。

在这里插入图片描述

在这里插入图片描述

这是一个 bug

这是一个明显的错误,需要尽快修复。同时,另一个问题是为什么没有任何实体在逐渐消失。似乎某个环节出现了问题,导致应有的渐隐效果没有生效。需要进一步排查,找出问题的根源。

调查发生了什么

问题可能出在Z轴范围的计算上,导致从不应该包括的区域加载了过多的实体。看起来在查询时,不仅是与实体的Z轴坐标不匹配,而且查询范围异常大。这个问题可能是由最大实体半径导致的,使得查询范围过于宽泛,导致不需要的区域也被加载进来。

目前的解决方案是暂时关闭优化,逐步调试代码,以查看Z轴范围的实际值。通过这一步可以进一步确认是哪个参数(例如最大速度或最大实体半径)导致了异常范围的出现。

将 Z 的 MaxEntityRadius 设置为 0.0f

问题的根源在于由于最大速度的影响,Z轴的查询范围过大,因此会加载到不必要的区域。为了解决这个问题,决定暂时不使用实体半径来限制查询范围,这样可以减少加载的实体数量。接下来需要查看是否可以通过调整安全边距(safety margin)来进一步减少Z轴上的波动。

目前的思路是,只在Z轴上添加一个较小的边距,而不是过多地扩展范围,避免不必要的实体被加载。同时,检查update safety margin是否正确生效,以确保在没有附加额外限制的情况下,Z轴的波动不会过大。接下来的步骤是检查这些调整是否能够有效地缩小查询范围。

将 Z 的 SimBoundsExpansion 设置为 0.0f,然后设置为 GameState->TypicalFloorHeight

首先,查询的初始范围被发现过大,最大值为15,最小值为-15,显得非常不合理。问题在于Z轴的处理没有考虑中心对齐,代码的设计显得非常随意,没有深思熟虑。考虑到这一点,认为在Z轴上不应添加任何额外的扩展,只需使用当前的楼层高度,并通过安全边距扩展来处理。

为了修正这一点,决定不进行任何Z轴的边界扩展,只在每一侧添加一个单位的安全边距。这样处理的目标是确保只包含当前区域,同时避免不必要的扩展。接下来,将尝试检查这一调整后的效果,确保没有遗漏或其他潜在问题,并观察这种方式是否能更好地控制范围。
在这里插入图片描述

在这里插入图片描述

查看这会带来什么

在修正了Z轴范围之后,发现问题仍然存在,尤其是在实体渐变淡出的部分。怀疑问题出在ClampMapToRange的实现,可能是因为编写时有误。检查代码后发现问题的根源:在处理范围时,计算最大值和最小值,并进行加减运算后再除以它们,但没有考虑支持负数范围。原本的实现假设范围必须大于零,但实际上,应该支持负数范围。因此,这个问题的原因就是没有正确处理负数的情况,导致无法正确判断值是否大于零。

通过这一发现,能够确定问题出在对范围的处理方式上,需要调整代码以支持负值范围,从而解决这个问题。

修复 Clamp01MapToRange

经过检查发现,之前编写的代码其实是正确的,只是由于忽略了负数范围的处理,导致没有按照预期工作。曾经认为代码有问题,但实际上是理解上的错误。这次的发现确认了之前的代码是合理的,问题出在对负数范围的支持不够,导致了错误的行为。

在面对这类问题时,始终保持“总是假设存在bug”的心态是重要的,尤其是在处理复杂的物理计算时。
在这里插入图片描述

查看淡入效果并让 FadeBottom 生效

在进行调试时,发现淡出效果在顶层现在已经正确工作,采用了合适的代码。之前的代码本应该有效,但当时未能坚持正确的方法。现在,淡出效果从起始Z位置到结束Z位置,应该如预期般工作。然而,问题依然存在:效果消失了,可能是因为同一区域包含了某些过低的实体。

为了解决这个问题,需要重新审视相机的区域范围,考虑从相机的位置向下扩展一些,通常可以向下扩展到2或3层楼,向上则查看1层楼。此举可以避免不必要的区域扩展,尤其是在Z轴方向上的扩展。

接下来调整了相机范围,但发现没有正确执行。错误在于相机范围计算时使用的矩形没有正确设置最小和最大值。因此,需要通过手动设置这些值来确保正确的范围计算。最终,调整为从相机位置向下扩展3层楼,上面1层楼,这样可以避免不必要的复杂计算。

然而,问题依旧出现,即淡出效果的方向是错误的。通过回顾发现,这又是由于alpha值的设置问题。尽管代码应该按照从起始位置到结束位置的顺序写,但实际上需要反转alpha值,以便正确实现淡出效果。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

查看所有效果并调整楼梯位置

现在,淡出效果已经能够按照预期正常工作,可以在两侧进行淡出。然而,堆叠的楼梯相互之间存在碰撞问题,导致玩家无法走下另一侧的楼梯。为了解决这个问题,决定采取一种方法,通过错开楼梯的位置来避免碰撞。

具体做法是判断楼梯的Z坐标是偶数还是奇数,通过检查Z值的绝对值是否为偶数来决定楼梯的位置。如果Z值为偶数,则将楼梯放置在一个位置;如果Z值为奇数,则将楼梯放置在另一个位置。这样做可以有效避免楼梯之间的相互碰撞问题。
在这里插入图片描述

在这里插入图片描述

走下各个层次并记录一些待解决的问题

目前,系统已经能够正常处理淡出效果,并且堆叠的楼梯碰撞问题得到了修复。接下来,观察到的一个新问题是,某些元素的缩放效果不正确,特别是当物体距离远时,它们似乎会快速缩放。这是因为没有正确处理透视效果的问题。

此外,还有另一个未解决的问题,就是当前的“伙伴物体”并没有被放置在正确的楼层上。这个问题的暴露正是为了后续的调整。虽然这些问题仍然存在,但它们也提供了一个清晰的目标,即要处理透视和地面处理相关的代码。地面处理还没有实现,当前的情况是相机的Z轴位置被误认为是地面位置,因此物体跟随相机的移动而下落。

整体来说,尽管存在一些问题,这些问题的暴露为后续的工作提供了非常清晰的方向,现在已经进入了能够彻底解决Z轴相关问题的阶段。接下来的重点是处理地面相关的功能,这样就可以进一步完善引擎的稳定性和性能。

为什么有些树是倒立的?

树木出现倒立的原因是因为系统尚未正确处理透视效果。当前所使用的Z轴“调整值”只是通过乘法将物体在屏幕上的X和Y位置放大或缩小,以模拟物体靠近或远离相机时的大小变化,但这种做法并没有实际计算透视。因此,这只是一种不准确的方法。

具体来说,当Z值足够负时(例如低于-0.0015),该表达式会变为负值,导致物体翻转。因为这种方法是基于乘法,而不是正确的透视计算,物体会被镜像翻转。正确的透视计算应该使用除法,而不是乘法。通过除法,物体会随着远离相机而变小,但不会发生翻转。

因此,解决这个问题的方法是引入真正的透视计算,通过除法来确保物体的缩放和显示更加真实,避免出现翻转现象。在实施之前,需要先在黑板上详细讲解透视原理,确保每个人理解这种转换的过程。
在这里插入图片描述

头部和身体实体偏离主角的位置是否应该随主角一起缩放?

头部和身体实体应该与主角一起缩放,当前它们的移动与Z轴有关。当实体移动时,它们被错误地当作与相机一起移动,而不是固定在正确的地面位置。问题的根本原因是目前系统没有正确处理地面位置,导致实体随着相机的位置变化而发生不正确的行为。

具体来说,地面处理的逻辑存在问题,这些实体被错误地认为与地面直接关联,似乎在相机下方移动,就像是地面在它们下面移开一样。当前的代码没有完成,导致无法确定实体为何会这样移动,但可以确定问题与地面值的处理有关,可能是因为这些实体正在与相机一起移动,而不是固定在正确的地面高度。

为了测试和找出问题的根源,可以尝试不更新相机的Z值,只让实体沿着Z轴移动。如果不更新相机Z值,实体会保持在原位不动,表明问题出在地面和相机的关系上。目前系统没有一个明确的地面处理方式,导致实体位置随着相机的移动而改变。

解决方法是加强Z轴的处理,确保实体和地面的位置正确关联,这样问题就能解决。

什么是 Z-fighting,它在这种游戏中需要担心吗?

Z-fighting 是指在3D图形中,由于两个物体的表面非常接近,导致它们在渲染时不断相互干扰,显示出闪烁或跳动的效果。通常发生在两个平面或多边形几乎在同一个位置时,尤其是在深度缓冲区的精度不足时。虽然Z-fighting是一个常见的问题,但在这种游戏引擎中不需要特别担心它。

简而言之,Z-fighting是因为渲染系统无法区分非常接近的两个表面,导致它们在屏幕上产生视觉上的冲突。尽管这个问题在某些情况下可能出现,但在当前的开发中,暂时不需要特别关注这个问题。

Blackboard: Z-Fighting

Z-fighting 是和深度缓冲区相关的。如果没有深度缓冲区,通常不会发生 Z-fighting。虽然可以在其他方面出现类似问题,但我这里先专注讲解深度缓冲区中的 Z-fighting。

在三维图形中,如果你没有处理 Z-fighting,通常会依赖一个叫做深度缓冲区(Depth Buffer)的东西来解决隐藏面移除(Hidden Surface Removal)的问题。这个技术可以用来决定在两个物体相交的地方,哪个物体应该遮挡另一个物体,从而避免错误的渲染。

举个例子,假设有两个立方体,一个离相机近,另一个远一些。当渲染这些立方体时,正确的顺序是先绘制远离相机的立方体,后绘制靠近相机的立方体,这样重叠的部分就能正确地被覆盖。

然而在三维图形中,由于物体的位置、角度的不同,如何判断哪个物体应该先绘制并不总是那么简单。如果物体比较复杂,可能需要不断调整绘制顺序。为了简化处理,通常的做法是逐像素处理:每个像素都有一个深度值,告诉它距离相机的远近。如果一个新的物体在绘制时,像素的深度值比原来的值小,就会替换原来的像素。

但如果深度计算精度不足,就会出现 Z-fighting。这个问题出现在计算机的浮点数运算中。如果两个物体非常接近,它们之间的距离差异可能非常小,以至于在浮点数表示中无法精确区分。这种情况下,当物体越来越远时,精度会丢失,导致这两个物体的深度值变得无法区分,从而导致 Z-fighting 的现象——物体在重叠区域交替显示,产生不希望看到的“闪烁”或“锯齿”效果。

特别是在深度值非常接近时,深度缓冲区的精度可能会不足,导致两个物体的深度信息丢失,从而产生 Z-fighting。比如,当一个物体的表面比另一个物体的表面更接近相机时,如果浮点精度不足,计算机会将它们的深度值视为相同,从而导致渲染错误。

此外,Z-fighting 还可能出现在没有深度缓冲区的情况下,比如在某些情况下物体的排序会受到浮点数精度的影响。没有深度缓冲区时,你可能会依赖排序算法来决定物体绘制顺序,但如果 Z 值过大或精度不足,可能会出现错误的排序,导致 Z-fighting。

总体来说,Z-fighting 的本质是由于浮点数计算精度导致深度值无法区分,最终导致错误的图形显示。

相关文章:

游戏引擎学习第107天

仓库:https://gitee.com/mrxiao_com/2d_game_2 回顾我们之前停留的位置 在这段内容中,讨论了如何处理游戏中的三维效果,特别是如何处理额外的“Z层”。由于游戏中的艺术资源是位图而不是3D模型,因此实现三维效果变得非常具有挑战性。虽然可…...

网页制作01-html,css,javascript初认识のhtml的基本标记

一、 Html简介 英文全称是 hyper text markup language,超文本标记语言,是全球广域网上描述网页内容和外观的标准. Html作为一款标记语言,本身不能显示在浏览器中.标记语言经过浏览器的解释和编译,才能正确地反映html标记语言的内容. 1.html 的基本标记 1)头部标…...

WebSocket在分布式环境中的局限性及解决方案

WebSocket 在分布式环境中存在一些局限性,特别是当系统需要扩展多个服务实例时,单个 WebSocket 连接的管理和消息推送就变得比较复杂。因此,必须采取一些额外的措施来确保 WebSocket 能在多个服务实例之间正确工作。 WebSocket 在分布式环境…...

Windows日志分析

查看服务日志文件 windows下我们可以通过时间查看器来查看windows系统下服务,应用,系统等产生的事件以及日志 1.打开方式是: winr 输入eventvwr.msc 2.控制面板--系统与安全--事件查看器 事件类型分为5种 错误:标识问题很严重…...

青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试

青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试 一、软件测试二、自动化测试三、单元测试四、Django 单元测试(一)、创建测试用例(二)、运行测试(三)、常用测试功能 课题摘要: 本文全面介绍了软件…...

WPF 中为 Grid 设置背景图片全解析

WPF 中为 Grid 设置背景图片全解析 在 WPF(Windows Presentation Foundation)开发中,界面的美观度是吸引用户的重要因素之一。而添加背景图片是提升界面视觉效果的常见手段。今天,我们就来深入探讨在 WPF 里如何为 Grid 设置背景…...

3.10 实战Hugging Face Transformers:从文本分类到模型部署全流程

实战Hugging Face Transformers:从文本分类到模型部署全流程 一、文本分类实战:IMDB电影评论情感分析 1.1 数据准备与预处理 from datasets import load_dataset from transformers import AutoTokenizer # 加载IMDB数据集 dataset = load_dataset("imdb") …...

Android中获取so文件来源于哪个库

Android app中可能有很多的.so文件,有时我们不确定这些.so文件都是来源于哪些库的,可以通过在build.gradle中添加代码来统计。具体方法如下: 1.在com.android.application模块的build.gradle文件最后添加如下代码: // 获取所有的…...

地面沉降监测,为地质安全保驾护航

地面沉降,不容忽视的城市隐患 随着城市化进程的加速,大规模的工程建设、地下水过度开采等因素,导致地面沉降现象日益严重。地面沉降不仅会使建筑物开裂、倾斜,影响其使用寿命和安全性,还会破坏地下管线,引…...

宝塔docker 安装oracle11G

1、拉取镜像 sudo docker pull iatebes/oracle_11g #iatebes为用户名2、查看镜像 sudo docker images3、创建并运行容器 docker run -d --privileged --name oralce11g -p 1521:1521 iatebes/oracle_11g4、登录到容器 5、进入容器并修改system用户密码 docker exec -it orac…...

unity学习39:连续动作之间的切换,用按键控制角色的移动

目录 1 不同状态之间的切换模式 1.1 在1个连续状态和一个连续状态之间的transition,使用trigger 1.2 在2个连续状态之间的转换,使用bool值切换转换 2 至少现在有2种角色的移动控制方式 2.1 用CharacterController 控制角色的移动 2.2 用animator…...

DeepSeek等大模型功能集成到WPS中的详细步骤

记录下将**DeepSeek功能集成到WPS中**的步骤,以备忘。 1. 下载并安装OfficeAI插件 访问OfficeAI插件下载地址:https://www.office-ai.cn/,下载插件(目前只支持windows系统)。 注意,有两个插件&#xff0…...

基于Python的Flask微博话题舆情分析可视化系统

✅️配套lun文 1w9字 ✅️爬虫可用 12月数据 ✅️实时微博热点分析 技术栈:爬虫➕Flask后端框架➕bert深度学习模型➕mysql数据库系统功能:爬取微博数据(可以是同类型文章或者制定文章),微博文章情感分析,微博评论情感…...

服务器A到服务器B免密登录

#!/bin/bash # 变量定义 source_host"192.168.42.250" # 源主机 IP target_host"192.168.24.43" # 目标主机 IP target_user"nvidia" # 目标主机的用户名 ssh_port"6666" # SSH 端口号 # 生成 SSH…...

Unity中可靠的UDP实现

可靠 UDP(Reliable UDP)是一种在用户数据报协议(UDP)基础上,通过添加额外机制来实现可靠数据传输的技术。与传统 UDP 相比,它克服了 UDP 本身不保证数据可靠性、顺序性以及可能丢失数据的缺点,同…...

轮播图html

题十二:轮播图 要求: 1.鼠标不在图片上方时,进行自动轮播,并且左右箭头不会显示;当鼠标放在图片上方时,停止轮播,并且左右箭头会显示; 2.图片切换之后,图片中下方的小圆…...

二十多年前的苹果电源Power Mac G4 Mdd 电源接口

在1999年,苹果推出了最初的Power Mac G4电脑。第一代Power Mac G4有与G3系列相似的外壳和两种主板设置,分别使用PCI和AGP显示总线。第二代电脑被昵称为快银或水银机,来自2001年的它们有更高速的PowerPC 7450系列芯片,增强了L2缓存…...

java听书项目

项目的架构 网关:1路由转发 2.认证鉴权(token)3.统一处理(跨域) Mysql:关系型数据库 ES:搜索数据库 Redis:页面级缓存,会话状态存储 GitLab:私有托管平台 K8S:自动化部署、扩展和管理容器化应用程序的开源系统 Jenkins:自动化部署 1.环境搭建 创建一个父工程…...

RadASM环境,win32汇编入门教程之三

;运行效果 ;win32汇编环境,RadAsm入门教程之三 ;在这个教程里,我们学一下如何增加控件,比如按钮,其它的控件类似这样增加 ;以下的代码就是在教程一的窗口模版里增加一个按钮控件,可以比较一下,增加了什么内…...

【机器学习】线性回归 多元线性回归

【机器学习系列】 KNN算法 KNN算法原理简介及要点 特征归一化的重要性及方式线性回归算法 线性回归与一元线性回归 线性回归模型的损失函数 多元线性回归 多项式线性回归 多元线性回归 V1.0多元线性回归一元线性回归与多元线性回归多元线性回归模型的误差衡量多元线性回归的最…...

线性代数中的正交和标准正交向量

在线性代数中,理解正交向量和正交向量至关重要,尤其是对于机器学习中的应用。这篇博文将简化这些概念,而不会太深入地深入研究复杂的数学。 正交向量 如果两个向量的点积等于零,则认为这两个向量是正交的。但点积到底是什么呢&am…...

Vue 项目登录的基本流程

Vue 用户登录的基本流程包括以下6个步骤&#xff1a; 步骤&#xff1a; 1. 创建登录表单 在前端&#xff0c;首先要创建一个登录表单&#xff0c;用户输入账号&#xff08;用户名、邮箱、手机号等&#xff09;和密码。 示例&#xff1a;Login.vue <template><div…...

坐井说天阔---DeepSeek-R1

前言 DeepSeek-R1这么火&#xff0c;虽然网上很多介绍和解读&#xff0c;但听人家的总不如自己去看看原论文。于是花了大概一周的时间&#xff0c;下班后有进入了研究生的状态---读论文。 DeepSeek这次的目标是探索在没有任何监督数据的情况下训练具有推理能力的大模型&#…...

Spring 是如何解决循环依赖问题的?

Spring框架通过使用三级缓存机制来解决单例Bean之间的循环依赖问题。以下是详细的解释&#xff0c;包括循环依赖的概念、Spring的解决方案以及三级缓存的具体作用。 什么是循环依赖&#xff1f; 循环依赖是指两个或多个Bean之间相互依赖&#xff0c;形成一个闭环。例如&#…...

【数据可视化-17】基于pyecharts的印度犯罪数据可视化分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...

thingboard告警信息格式美化

原始报警json内容&#xff1a; { "severity": "CRITICAL","acknowledged": false,"cleared": false,"assigneeId": null,"startTs": 1739801102349,"endTs": 1739801102349,"ackTs": 0,&quo…...

Javaweb中,使用Servlet编写简单的接口

案例&#xff1a;网页提交用户名和密码信息&#xff0c;后端校验密码长度需在6-12位之间 后端部分 WebServlet("/valid") public class SimpleServlet extends HttpServlet{public void service(HttpServletRequest req, HttpServletResponse resp) throws IOExcepti…...

三层渗透测试-DMZ区域 二三层设备区域

DMZ区域渗透 信息收集 首先先进行信息收集&#xff0c;这里我们可以选择多种的信息收集方式&#xff0c;例如nmap如此之类的&#xff0c;我的建议是&#xff0c;可以通过自己现有的手里小工具&#xff0c;例如无影&#xff0c;密探这种工具&#xff0c;进行一个信息收集。以免…...

Java 开发者需要了解的 PDF 基础知识

PDF 代表“可移植文档格式”&#xff08;Portable Document Format&#xff09;&#xff0c;它是全球最流行的文件格式。因此&#xff0c;Java 开发人员很可能会经常需要处理它。然而&#xff0c;与 Microsoft Word 或 HTML/XML 这样的格式相比&#xff0c;PDF 并不那么直观。理…...

基于图像处理的裂缝检测与特征提取

一、引言 裂缝检测是基础设施监测中至关重要的一项任务,尤其是在土木工程和建筑工程领域。随着自动化技术的发展,传统的人工巡检方法逐渐被基于图像分析的自动化检测系统所取代。通过计算机视觉和图像处理技术,能够高效、精确地提取裂缝的几何特征,如长度、宽度、方向、面…...

Webpack 基础入门

一、Webpack 是什么 Webpack 是一款现代 JavaScript 应用程序的静态模块打包工具。在 Web 开发中&#xff0c;我们的项目会包含各种类型的文件&#xff0c;如 JavaScript、CSS、图片等。Webpack 可以将这些文件打包成一个或多个文件&#xff0c;以便在浏览器中高效加载。它就像…...

掌握SQLite_轻量级数据库的全面指南

1. 引言 1.1 SQLite简介 SQLite 是一个嵌入式关系型数据库管理系统,它不需要单独的服务器进程或系统配置。它的设计目标是简单、高效、可靠,适用于各种应用场景,尤其是移动设备和嵌入式系统。 1.2 为什么选择SQLite 轻量级:文件大小通常在几百KB到几MB之间。无服务器架构…...

大数据处理如何入门

大数据处理的入门可以从以下几个方面入手&#xff1a; 1. 基础知识学习 在深入大数据领域之前&#xff0c;建议先掌握一些基础知识&#xff0c;包括数据类型、存储与处理的基本概念&#xff0c;以及常用的数据处理工具。例如&#xff0c;Python或Java编程语言在大数据领域应用…...

算法与数据结构(最小栈)

题目 思路 为了返回栈中的最小元素&#xff0c;我们需要额外维护一个辅助栈 min_stack&#xff0c;它的作用是记录当前栈中的最小值。 min_stack的作用&#xff1a; min_stack的栈顶元素始终是当前栈 st 中的最小值。 每当st中压入一个新元素时&#xff0c;如果这个元素小于等…...

LeetCode 1287.有序数组中出现次数超过25%的元素:遍历

【LetMeFly】1287.有序数组中出现次数超过25%的元素&#xff1a;遍历 力扣题目链接&#xff1a;https://leetcode.cn/problems/element-appearing-more-than-25-in-sorted-array/ 给你一个非递减的 有序 整数数组&#xff0c;已知这个数组中恰好有一个整数&#xff0c;它的出…...

春招项目=图床+ k8s 控制台(唬人专用)

1. 春招伊始 马上要春招了&#xff0c;一个大气的项目&#xff08;冲击波项目&#xff09;直观重要&#xff0c;虽然大家都说基础很重要&#xff0c;但是一个足够新颖的项目完全可以把你的简历添加一个足够闪亮的点。 这就不得不推荐下我的 k8s 图床了&#xff0c;去年折腾快…...

Vue 记录用户进入页面的时间、离开页面的时间并计算时长

在 Vue 项目中&#xff0c;要记录用户进入页面的时间、离开页面的时间&#xff0c;并在用户离开时计算时长并调用后端接口&#xff0c;可以借助 Vue 的生命周期钩子和浏览器的一些事件来实现。以下是具体的实现步骤和示例代码&#xff1a; 实现思路 记录进入时间&#xff1a;…...

解锁豆瓣高清海报(三)从深度爬虫到URL构造,实现极速下载

脚本地址: 项目地址: Gazer PosterBandit_v2.py 前瞻 之前的 PosterBandit.py 是按照深度爬虫的思路一步步进入海报界面来爬取, 是个值得学习的思路, 但缺点是它爬取慢, 仍然容易碰到豆瓣的 418 错误, 本文也会指出彻底解决旧版 418 错误的方法并提高爬取速度. 现在我将介绍…...

机器学习--逻辑回归

机器学习–逻辑回归 一、认知革命&#xff1a;从线性回归到逻辑回归 1.1 本质差异对比 维度线性回归逻辑回归输出类型连续值概率值 (0-1)目标函数最小二乘法极大似然估计数学表达式 y w T x b yw^Txb ywTxb p 1 1 e − ( w T x b ) p\frac{1}{1e^{-(w^Txb)}} p1e−(wTxb…...

gradio创建openai前端对接deepseek等模型流式输出markdown格式文本

环境 gradio3.50.2 openai1.63.1代码 import openai import gradio as gr#导入gradio的包api_key "sk-**a8" api_base "https://api.deepseek.com/v1"import gradio as gr import openai from typing import List, Any, Iteratorclient openai.OpenAI…...

【LeetCode Hot100】最大子数组和|动态规划/贪心,Java实现!图解+代码,小白也能秒懂!

&#x1f4bb; [LeetCode Hot100] 最大子数组和&#xff5c;动态规划/贪心&#xff0c;Java实现&#xff01;图解代码&#xff0c;小白也能秒懂&#xff01; ✏️本文对应题目链接&#xff1a;最大子数组和 &#x1f4cc; 题目描述 给定一个整数数组 nums&#xff0c;找到一个…...

【Go语言快速上手】第二部分:Go语言进阶之网络编程

文章目录 前言&#xff1a;网络编程一、TCP/UDP 编程&#xff1a;net 包的使用1. TCP 编程1.1 TCP 服务器1.2 TCP 客户端 2. UDP 编程2.1 UDP 服务器2.2 UDP 客户端 二、HTTP 编程&#xff1a;net/http 包的使用&#xff0c;编写 HTTP 服务器和客户端2.1 HTTP 服务器2.2 HTTP 客…...

AI法理学与责任归属:技术演进下的法律重构与伦理挑战

文章目录 引言:智能时代的新型法律困境一、AI技术特性对传统法理的冲击1.1 算法黑箱与可解释性悖论1.2 动态学习系统的责任漂移1.3 多智能体协作的责任稀释二、AI法理学的核心争议点2.1 法律主体资格认定2.2 因果关系的技术解构2.3 过错标准的重新定义三、责任归属的实践案例分…...

Linux探秘坊-------8.进程详解

1.概念详解 1.运行&&阻塞&&挂起 内容基础&#xff1a;方框中的就是调度队列&#xff0c;是一个 双向队列&#xff0c;每一个元素是PCB其对应的代码数据 1.运行 只要进程 在调度队列中&#xff0c;进程的状态就是运行&#xff08;running&#xff09;. 2.阻塞…...

C#使用文件读写操作实现仙剑五前传称号存档修改

手把手教学仙剑五前传 称号存档修改器 首先找到 Pal5Q所在目录的save\global.sav 文件,这是一个只有488字节的文件,这里存放称号对应的编号ID,以及是否已获得该称号,1为已获取称号,0为未获取称号 [称号:是否获取]这是一个键值对 称号的编号ID是一个Int32数字,使用C#的方法Bi…...

Kubernetes知识点总结(十)

什么是 K8s 的 namespace&#xff1f; 在 K8s 中&#xff0c;Namespace&#xff08;名字空间&#xff09;提供了一种机制&#xff0c;将同一集群中的资源划分为相互隔离的组&#xff0c; 是在多个用户之间划分集群资源的一种方法。 名字空间作用域仅针对带有名字空间的对…...

【达梦数据库】disql工具参数绑定

前言 在达梦数据库的使用过程中尽管管理工具很好用&#xff0c;但是命令行工具还是有着得天独厚的优势&#xff0c;但是在参数绑定方面就没有管理工具做的更加完美&#xff0c;现在就汇总下disql 工具参数绑定的常用几种方式 disql 参数绑定 使用 ? select * from v$dm_in…...

箭头函数的this指向谁

先看1个重要原则&#xff1a; 由Vue管理的函数&#xff0c;一定不要写箭头函数&#xff0c;箭头函数的this就不再是Vue实例了 箭头函数的 this 指向在定义时确定&#xff0c;继承自外层作用域&#xff08;即定义时的上下文&#xff09;的 this&#xff0c;且无法通过 call、app…...

Node.js技术原理分析系列——Node.js调试能力分析

本文由体验技术团队屈金雄原创。 Node.js 是一个开源的、跨平台的 JavaScript 运行时环境&#xff0c;它允许开发者在服务器端运行 JavaScript 代码。Node.js 是基于 Chrome V8引擎构建的&#xff0c;专为高性能、高并发的网络应用而设计&#xff0c;广泛应用于构建服务器端应…...

网络基础 【UDP、TCP】

1.UDP 首先我们学习UDP和TCP协议 要从这三个问题入手 1.报头和有效载荷如何分离、有效载荷如何交付给上一层的协议&#xff1f;2.认识报头3.学习该协议周边的问题 UDP报头 UDP我们先从示意图来讲解&#xff0c;认识报头。 UDP协议首部有16位源端口号&#xff0c;16位目的端…...