黑马 SLG 游戏《三国:谋定天下》怎么用 Unity 技术实现高效地形渲染?

从0开始学Unity做SLG系列(GameFramework框架) 目录GameFramework框架启动流程 GameFramework框架启动流程   找了2个系列教程,照着写完后,应该就有些基础了解了。 先看第一篇 StarForce 在看第二篇 FlappyBird 还有一篇 下载最新框架,然后双击运行,导入到项目即可。演示 上面是纯框架的使用,我们用开发模版,很多内容已经写好了,首先下载 这里的工程是从0开始学Unity做SLG系列(1)的完成后的工程,这篇文章只是边学边记录,可能有很多理解偏差的地方,后面如果深入了解了会找机会回来修改的 这个就是初始场景了,下 阅读详情
AI摘要

SLG 游戏《三国:谋定天下》公测后获市场关注。游戏采用无极缩放技术,提升玩家体验。华娱网络 CTO 分享了无极缩放和地形渲染方案,包括地块加载、地表材质融合、精度优化及多层地表材质混合等内容,介绍了相关算法和技术实现。

三国时期以其风云变幻的政治环境和英雄辈出的时代背景,一直是游戏开发者与玩家创作的灵感源泉。SLG 游戏《三国:谋定天下》凭借多项对传统 SLG 手游的重大创新和改动,自 2024 年 6 月 13 日公测以来,迅速获得市场关注,iOS 手机端 6 月 16 日单日游戏收入高达 1,821,632 美元。

多职业的游戏设定不仅丰富了游戏的战略维度,也提升了玩家之间的互动性和合作性。更引人注目的是,为了给玩家带来更优的视觉与玩法体验,游戏采用了无极缩放技术,使得玩家可以流畅的从宏观战场切换到微观细节的观察视角。

在 Unite Shanghai 2024 游戏专场上,华娱网络 CTO 吴志强先生为大家分享了《三国:谋定天下》无极缩放和大世界地形渲染方案,讲解如何在移动平台实现更大观察视野、更流程丝滑的无极缩放与超多层地表材质混合等。

无极缩放功能

我是来自浙江华娱网络科技有限公司东风工作室的吴志强,我今天分享主题是《三国:谋定天下》无极缩放和地形渲染技术,我在《三国:谋定天下》主要负责引擎渲染、性能优化、基础设施的搭建。

《三国:谋定天下》是首款多职业战争策略手游,玩家可以选择天工、神行、青囊、司仓、镇军、奇佐六大职业,每个职业都能通过其特色的职业技能对沙盘局势造成影响。为了让玩家能够从战略视角清晰地查看沙盘上的局势,我们引入了无极缩放功能。

在《三国:谋定天下》里面一共有 13 个州,在这个视角下我们可以观察到 6 个州的局势。

随着相机高度的不断下降,可以看到局部地区更加详细的信息,比如说这张图我们能看到官道、同盟建筑、城池模型。

继续下降可以看到玩家建筑的图表、同盟标记的文本信息。

当相机下降到最低高度可以看到玩家建筑的模型、军队模型、行军线这些玩家更加关注的信息。

无极缩放对游戏体验的提升是巨大的。

它能让游戏目标更加清晰呈现在沙盘中,所有的同盟成员都能清晰知道需要攻打哪座城,哪里是战场的前线,哪里可能藏着老六。

基于上述原因我们在立项之初就决定要做好无极缩放,为了让无极缩放的需求得到满足,我们在《三国:谋定天下》的沙盘地形渲染中一共使用了 7 级 LOD,其中 LOD 0 的单个地块覆盖了 3.2×3.2 米的区域,约等于游戏中 4×4 个游戏格子。

LOD 级别每增加 1,其地块覆盖区域的边长会翻一倍,LOD 6 的单个地块是 284.8 米,我们全地图的尺寸是 1200×1200 米,一共包含了 225 万个游戏格子。

这张图是 LOD 0 的地块模型,它正好包含了游戏中的 16 个资源地。

第 6 级的地块会大很多,已经有小半个州的面积了,经过减面后其模型精度相比于 LOD 0 的 Mesh 会低很多。

地形渲染技术方案

地块加载

为了方便后续讨论我们先引入两个名词,一个是 Grid,整个大地图我们会把它均匀地划分成若干个 3.2×3.2 米的网格,每个小格子我们称为一个 Grid。第二个是 LOD Chunk,也叫 LOD 地块,每个 LOD 0 的 chunk 正好包含一个 Grid,每个 LOD 1 的 chunk 包含了 2×2 个 Grid,以此类推。

每级 LOD 的 chunk 位置和数量是固定的,LOD 级别每增加一级,chunk 的数量会降低至四分之一,其面积也会相应地扩大四倍,这张图中有 64 个 Grid,64 个 LOD 0 的 chunk,16 个 LOD 1 的 chunk,4 个 LOD 2 的 chunk。

前面提到 7 级 LOD,每一级 LOD 都会加载距离视野中间点最近的 5×5 个地块进内存,一共是 25×7,175 个地块。

这里有几个点是需要注意的,从上面的三张图可以清晰看出不同级别的 LOD 加载的地块区域会相互重叠的。另外相机大约需要移动一个 Grid 的距离才会触发 LOD 0 的刷新,而 LOD 2 的刷新大约需要移动 4 个 Grid 才会触发,也就是说 LOD 的级别越大它的刷新频率越低。

我们会设定一个相机的基础高度 H0,当相机高度大于 H0 后会隐藏所有 LOD 0 的地块,大于 2 倍 H0 会开始隐藏所有 LOD1 的地块,当相机高度达到 32 倍 H0 后,全场景只会显示 LOD6 的地块。这样的好处是当相机高度很高时,不用再刷新低级别的 LOD 地块,否则随着相机高度的增加,其移动速度也会成倍增长,从而导致每帧都需要刷新大量低级别的 LOD 地块。

这个算法是很简单的,有兴趣的同学可以看一下PPT。

通过上面的算法我们就能够知道每帧需要加载、卸载哪些 LOD chunk。而加载 LOD chunk 又需要做哪些事情呢?

第一步肯定是异步加载 LOD chunk 需要的资源,包括 Mesh 和地块相关的材质贴图。由于我们项目中使用了 RVT 来做地形渲染,所以在加载完这些地块资源之后,我们会在 GPU 中做地表的贴图混合,输出这个地块的 Albedo、Normal、Roughness 贴图,其中 Normal、roughness 我们选择存储在同一张贴图的 RG 通道和 B 通道。大致的渲染流程也比较简单,首先是修改相机矩阵和投影矩阵,保证相机的方向是自顶向下,并且使用正交投影,这样可以让当前烘焙的地块正好覆盖整个 RT。

然后是渲染地形,将地形的 Albedo 和 Normal 输出到 RT0 和 RT1 中,然后再渲染和当前地块相交的山体、贴花、道路、逻辑网格线这些地形上的静态元素,这里有一个好处是只需要通过 Alpha Blend 就能实现山体、贴花和地形做材质融合。

第三步是需要在 GPU 上做实时的 ASTC 贴图压缩,我们会将 RT0 和 RT1 都压缩成 ASTC 6×6 的格式,有两个好处,一个是降低内存占用,一个是降低后续的 RVT 采样带宽,实时压缩 ASTC 这部分代码我在去年的时候已经在 github 开源了,有需要的同学可以直接在 github 上搜索 UnityAstcGpuEncoder 项目。

图上这一步是将地形渲染到两个 G-buffer 的 RT 中,由于这个地块没有包含山体,所以它的 Mesh 也很简单只有两个三角形,如果有山体的话 Mesh 会复杂很多。

将官道直接以 Alpha Blend 的形式叠加到 RT 上,贴花、山体这些都会以这样的形式叠加到地形上。

经过上面的步骤我们会得到当前地块两张 ASTC 格式的 G-buffer 贴图,为了后续支持场景建筑跟地表做材质融合,这两张贴图是不能直接使用的,而是需要将所有地块的 G-buffer 贴图都存储到两个全局的 texteure array 中,这样才能够实现在场景建筑的材质中可以采样任意位置的地表贴图,这也是 RVT 对资源占用最大的部分。两张 ASTC 6×6 格式的贴图,尺寸是 720×720,会包含三级 Mipmap,包含 175 个 slice,这大约需要 100 兆的内存,低配我们可以通过限制贴图尺寸,将内存降低到 25 兆左右,效果勉强能接受。

最后是将当前地块的 VT copy 到 textere array 后还需要处理 Mipmap,但是我们并不能直接通过 GenerateMipmap 这个接口自动生成 Mipmap,这是因为同一个区域在不同 LOD 的表现可能差异很大,这个差异主要有两个因素造成,其一是我们的贴花它只会在 LOD 小于等于 3 的地块上显示。其二是为了降低相机拉高后的贴图重复感,我们会在渲染 LOD 大于等于 2 的地块 VT 时使用更大的 tiling 值去采样另外一组没有明显特征的低精度地表贴图,使用无明显特征的贴图是为了避免贴图中的一个小坑它突然变成一个很大的坑这种问题,所以说除了最后一级 LOD 外,其他的 LOD Mipmap 都是从相邻的 LOD 中复制过来的。

比如说这里加载到上图中 LOD 1 的红色地块的时候,这个红色地块的第一级 Mipmap,它是直接从 LOD 2 的绿色地块的 VT 的左下角区域复制出来的,同样如果 LOD 0 四个地块已经加载完成了,也需要将 LOD 1 中的红色地块对应区域分别复制到这四个 VT 的第一 Mipmap 中。这个可以看出 LOD chunk 它们之间是存在一定的层级关系的,我们将 LOD 1 中的红色地块称为绿色地块的 child chunk,同时它也是 LOD 0 中四个地块的 parent chunk,而 LOD 0 中的四个 chunk 它们是互为 sibling chunk。完成了上述过程后,我们就可以为每一个地块创建其对应的 game object,然后通过加载出来的 Mesh 和烘焙后的 VT 进行最终的地块渲染。

但是并不是所有的创建出来都会直接显示,它是否需要显示是根据这里列出的 4 条显示规则决定的:

首先从我们之前提到的 Mipmap 更新算法可以看出,如果一个 chunk 它的 Parent chunk 没有加载完成的话,这个 chunk 是不能显示的,因为它的 Mip1 还没有更新。

第二如果一个 chunk 它的四个 Child chunk 没有全部加载完成,那么当前已经完成加载的 Child chunk 也不能显示的,不然就会出现 Parent chunk 的 Mesh 和 Child chunk 的 Mesh 会发生重叠,换句话说除了最后一级 LOD 外,其他的 LOD chunk 只有当自己的 sibling 全部加载完成自己才能显示。

第三点是 Child chunk 全部加载完成之后,这个 Parent chunk 就不需要显示了,这也是避免发生重叠。

最后再加上之前说过的相机高度增加后需要隐藏低级别 LOD 这一点,一共组成了四条显示规则。

有了这些规则我们就可以实现一个递归的算法来决定哪些加载完成的地块它应该要显示,这里首先是遍历所有第 6 级 LOD 的chunk,调用 UpdateChunkVisibility 这个函数,如果这个 chunk 它的 LOD 是大于 min visible LOD,并且这个 chunk 的所有 children 都是加载完成的状态,就递归遍历它的 child chunks,不然这个地块它就可以显示了。

地表材质融合

再回到之前提到过的地表融合问题上,前面已经说过了为了让融合材质能够采样任意位置的地表材质信息,我们会将所有地块的 G-buffer 贴图放进两张全局的 texture array 中,这为在 PS 中采样任意位置的贴图提供了可能性,但是想要知道某一个世界坐标位置它对应了 texture array 中哪一层贴图中哪一个像素,仍然是很麻烦的事情。

因为我们并不能知道某一个世界坐标位置它当前使用的是哪一级 LOD,由于 LOD chunk 它的最小单位是一个 Grid,所以最简单的做法是创建一张 lookup 贴图,这个贴图的每个像素对应沙盘中每一个 Grid,像素中这个 Grid 应该采样 texture 的哪一层贴图,以及这一层贴图的 LOD 层级。但是这个 lookup 贴图会比较大,在游戏中大概需要 375×375 这个分辨率的尺寸,这样在相机大范围移动的时候可能需要单帧更新上万个像素的值,这个开销也是不小的,同时一旦地图的面积扩大,开销会成倍增长。

另一种做法是将当前显示的地块信息通过 cbuffer 传递进 shader 中,然后按 LOD 级别从高到低的顺序依次判断应该使用哪一级 LOD,我们直接看下面的例子。

这个例子中绿色的地块表示正在显示的,红色表示隐藏的地块,白色是未加载的。

左边是 LOD3,右边是 LOD2,黑色的点表示的是查询点,黑色的大方框是当前 LOD 的加载区域。在这个例子中我们首先进行 LOD3 的查询,可以计算出查询点所处的 LOD3 chunk,在整个加载列表中的 index 是 4,这个 chunk 的状态是隐藏中,因此我们继续向下查询 LOD2,查询点所处的 LOD2 chunk 在 LOD2 的加载列表中 index 是 3,经过查询发现这个 chunk 的状态是显示中可以直接采样,这样只需要将查询点的坐标转化为 chunk 的贴图 UV 坐标可以采样得到查询点的地表信息。

这个算法虽然很直观,但是性能比较差,因为大部分视野内能看到的建筑都位于 LOD0 的地表上,因此可以反转一下遍历的顺序,改为从 LOD0 开始遍历,如果查询点的 LOD chunk 不是显示中的状态,再查询更高级别的 LOD。除此之外我们可以把当前可见最小的 LOD 级别传到 shader 里面去,使得可以快速跳过完全不可见的 LOD,这个在相机拉高之后会很实用。

这是最终的伪代码。我们首先从 min visible LOD 一直到最高级 LOD,然后计算查询点在当前 LOD 当中的 chunk index,如果 chunk index 小于 0,就表示这个查询点并不在当前的 LOD 的加载区域内,就直接去查询下一级 LOD。如果在加载区域内,我们通过 chunk 去拿到当前这个 chunk 它在 VT 中是属于哪一层 slice,如果 slice 也是大于等于 0,就表示这个 chunk 处于显示中的状态,不然还是只能继续查询下一级 LOD。

地表精度优化

上面的渲染方式实现后,偶尔会在屏幕边缘出现这个图里面的明显分割线,这里应该也能看清,在分割线的一侧是比较清晰的地表,另外一侧是比较模糊的地表。这个很明显在分割线那里发生了 LOD 的切换,在很长一段时间内我们都认为这是一个比较合理的情况,一直没有处理。

但是这种情况出现很频繁,对画面的影响已经到了不能忽视的程度,经过一番排查后分割线下方是 LOD0 的地块,但是上面那一部分不是 LOD1,是 LOD2 的地块,这就相当不合理了。

经过排查我们发现 LOD0 到 LOD2 的显示区域如下面这三张图所示,从左到右依次是 LOD0、LOD1、LOD2,我们能够看到 LOD0 中显示的地块数量是 16 个,我们加载 25 个,为什么少了 9 个?是因为显示规则中的第二条导致的,只有当自己的 sibling chunk 全部加载完毕才能显示,所以这里少了 9 个。LOD1 同样是因为这个规则而导致有 9 个 chunk 没有显示,直接导致了我们 LOD0 和 LOD2 地块是直接相接的。

所以虽然最终表现上觉得不太合常理,但是经过分析后我们发现它是正常的现象,图中的模糊区域我们实际已经加载了精度更高的地块,但是因为显示规则导致无法使用高精度的地块。第二条显示规则本质是因为 parent chunk 和 child chunk 的 Mesh 会相互重叠,所以只能要么隐藏所有的 child chunk 只显示 parent,要么隐藏 parent 然后显示全部的 child chunk。

但是我们现在碰到的问题是地表的贴图精度不够,并不是 Mesh 精度不够,所以可能只使用 parent chunk 的 Mesh,但是贴图使用 child chunk 吗?这是完全可以的,而且我们只需要做非常小的改动。在地表材质融合的时候我们已经实现了传入世界坐标位置就可以采样出任意位置 G-buffer 的功能,但是这个只能采样出已经显示的地块,不过我们可以直接忽略当前地块是否显示,只要地块完成了加载,我们就将地块信息写入刚刚的 ChunkInfo 数组中,这样的话就能够实现任意位置 G-buffer 的功能。

最后我们需要将地表 shader 修改一下,改成和融合材质一样,直接调用刚才实现的 SampleTerrainAtPosition 这个函数,去获取地表的信息,而不是说直接采样某一层贴图,这是一个动态的采样。

优化后同样视角下已经完成看不到分割线了,之前采样 LOD 贴图的区域已经转为采样 LOD0 的贴图了。

多层地表的材质混合

最后一个话题是多层地表的材质混合,2022-2024 年将近两年的时间我们只支持四层地表材质贴图的混合,而且由于一开始没有专门的美术同学复杂场景地形的绘制,当时完全是靠在 Photoshop 中盲画地形的分布图,随着一次次的画质迭代,在 2024 年 1 月下旬我们决定至少要支持 16 层地表贴图的混合,这其实在当时是非常大胆的决定,因为当时离公测封包只有不到 4 个月的时间了,程序实现完机制还需要美术熟悉工具,去绘制、去调优,所以我们要在 4 个月的时间把之前两年没有解决的问题解决。

从 1 月 20 日开始动工,大概耗费 1 个月的时间实现渲染方案和工具,我们为了敏捷开发直接在工具上使用了 Unity 的 terrain tool package 来支持地形的笔刷功能,所有的笔刷操作都是在 Unity 上进行的,编辑完成之后再导出自定义的资源格式。

上图是当隐藏 Unity Terrain 切换成游戏内的 LOD Terrain 的效果图,我们对 URP 自带的 TerrainLit 材质做了大量的修改,来保证 Unity 的地形效果和游戏内 LOD 地形效果是几乎完全匹配的。

我们会将整个场景拆分成 36 个分组,每个分组下面包含了 16 个 Unity 节点,每个节点覆盖了 51.2 米的范围,所有这些节点都位于单独的编辑场景中,运行时不会加载这个场景的。每个 Unity 节点都有一个对应的 terrain data 资源文件存储美术绘制的地形数据,这样可以支持美术协作绘制同一个场景的不同区域,在导出运行时需要的地形数据时,也会根据 terrain data 的 hash 判断是否需要导出,通常导出时间只需要几秒钟,全部导出不到 2 分钟的时间,能够加快美术的迭代效率。

我们目前支持 16 层地表贴图,技术上已经实现了最多 256 层,只是美术暂时用不上就没有开放,16 层虽然不多但是运行时不能在 PS 里直接采样,所以传统的 SplatMap 方案是不可行的,为了解决这个主要的方法是使用 IDMap,每个控制点存储的不再是 16 层贴图的混合强度,而是材质 ID,然后通过双线性插值做不同 ID 贴图的混合,这 16 层贴图会被存储到多个 texture array 中,一般会有 Normal texture array 和 Albedo texture array,贴图的 ID 对应其在 texture array 中的索引,但是 IDMap 的效果并不够好,主要还是因为双线性插值的结果不太可控,很多区域只能使用单层材质,对于确实需要多层混合效果的区域是不能支持的。

我们最终使用了一个 hybrid 的方法,在每个 3.2×3.2 米 block 内,我们可以单独指定使用 4 层地表贴图,这个 block 有 32×32 个控制点,每个控制点可以单独控制这 4 层地表贴图的混合强度,也就是说我们会有一张低精度的 IDMap,IDMap 中的每个像素记录的是一个 Block 内的 4 层地表贴图 ID,以及一张记录了控制点混合强度的全精度的 splat map,splat map 的分辨率大约是 IDMap 分辨率的 32×32 倍。

这个做法听起来很简单,但是有一个非常麻烦的问题需要解决,那就是 Grid 之间它的 splat map 插值问题,我们直接看下面的例子。

它的一个 block 中是 4×4 个控制点,左边的 block 是使用了 ID1、2、3、4 的地表贴图,右边的 block 使用了 ID1、2、4、5 的贴图,我们可以看到控制点 A 记录的混合权重是 0.3、0、0、0.7,它表示的是 30% 的 1 号贴图和 70% 的 4 号贴图做混合,控制点 B 中记录了权重是 0.6、0.2、0.2、0,它表示的是 60% 的 1 号贴图,20% 的 2 号贴图和 20% 的 4 号贴图。

如果直接使用双线性插值的话,在 AB 的中间插值权重是 0.45、0.1、0.1、0.35,但是中点左右两侧的像素会对这个权重值有不一样的解释,比如说 B 通道的值是 0.1,会被左侧的像素理解成是 10% 的 3 号贴图,右侧的像素会把它理解成是 10% 的 4 号贴图,这个是错误的,会在最终的图像上产生一条很明显的接缝。

为了解决这个问题我们需要把边界上的顶点复制一份,使其同时存在于左边的 block 和右边的 block 中,修改之前一个 block 包含了 4×4 个控制点,影响世界坐标系下 0.4×0.4 米的区域(假定这个小格子是 0.1 米),修改之后一个 block 中仍然包含 4×4 个控制点,但是它只影响 0.3×0.3 米的区域。图中左边的 0.3×0.3 米的区域包含 4×4 个控制点,每个控制点记录的混合强度、含义都是一样的,也就是它 4 个通道都依次表示 ID1、2、3、4 的贴图混合强度,也就不会出现插值问题,右边的 0.3×0.3 米的区域同样也包含了 4×4 个控制点,并且也包含了 A 点。但是这个 block 中它存储的控制点 A 的值和左边 block 中 A 的值是不一样的左边是 0.3、0、0.7,右边 0.3、0.7、0,因为左边区域第四个 ID 是 4,右边区域的4号贴图是第三个 ID。

在《三国:谋定天下》我们提到一共会创建 576 个 unity terrain 节点,每个都会导出一张 Splat 贴图,每一个 Splat 贴图包含了 17×17 个 block,每个 block 包含 32×32 个控制点,并且覆盖 3.1×3.1 米的区域。可以算出来我们每张 Splat 的贴图尺寸是 544×544,这里有一个注意点,由于跨 block 的 Splat 像素没有办法插值的,不能让它们同时出现在 ASTC 中的 block 中,我们的 block 现在是 32×32 的,所以它存储在 ASTC8×8 中是不会有插值问题的,但是如果 block 是 36×36,那就只能是使用 ASTC6×6 或者 4×4 这种格式了,要让它整除 36。

然后 IDMap 只有一张全局的,贴图宽度是 24×17 408 个像素,每个 IDMap 的像素需要两个字节存储 4 个 ID。

由于每张 Splat 贴图覆盖的区域是 51.2×51.2,正好等于一个 LOD4 chunk 的面积,所以在渲染 LOD0 到 LOD4 chunk 时,只需要采样一张 Splat 贴图就可以完成渲染,但是 LOD5 和 LOD6 chunk 需要更多张 Splat 贴图,因此我们将 4 张 544×544 的 Splat 贴图合并成一张新的 544×544 尺寸的 Splat1,这个 Splat1 的贴图是用于 LOD5 的 chunk 渲染。同样我们会将 4 张 Splat1 的贴图合并一张同尺寸的 Splat2 的贴图用于 LOD6 的 chunk 渲染,这个跟Mipmap是很像的,也是一种 LOD。

最终所有的 Splat 贴图加起来是 53.3 兆,由于每级 LOD 同时加载进内存的地块数量是 25 个,所以大约需要加载 75 张 splatmap,也就是 5.3 兆左右的贴图完成单个视角的渲染,在生成的第二级 Splat 贴图中,每个 block 包含的控制点的数量也将从 32×32 降低至 8×8 个,它更好可以放进 ASTC8×8 的 block 中,这是为什么我们要选 32×32 作为 block。

Unity:SLG游戏画线模块 最近学Shader有点心得,做了一个SLG画线模块。github地址:https://github.com/871041532/SLGDrawLine1.介绍画线模块,可用于SLG游戏行军线。多个不同速度、颜色、长度的线在一个DrawCall中实现。材质中ShowLength控制两端显示的长度,AlphaLength控制渐隐长度,AllShowLength是一个临界值,长度小于它的线全部显示,长度... 阅读详情

相关推荐

Unity游戏源码 305 SLG战棋游戏

Unity游戏源码 305 SLG战棋游戏

1361

unity3d的优化场景技术LOD+IOC

unity3d的优化场景技术LOD+IOC unity3d的优化场景技术   LOD+IOC 遮挡剔除(occlusion culling)其实就是在摄像机范围内的物体才被渲染出来,没有在视野范围内的,统统关掉渲染,这样能让性能大大提高。   IOC技术就是实现的这个功能,叫做无缝拼接,原理其实就是摄像机的所有范围内,每一帧都发射许多的射线,与射线碰撞器发生碰撞的物体(此物体必须挂有IOC的脚本和有碰撞器)就会被渲染出来。当镜头转向另一边的时候那一边的所有物体被渲染出来,原来的方向就会自动关掉渲染。LOD技

枯木萧的博客 861

Power Automate 最常用的十大场景以及解决方案

3.2 获取指定主题含有附件邮件,然后读取csv附件内容,插入数据库,调度执行存储过程,最后通过Power automate 发送paginated report 特殊格式报表给发件人。Power Automate 作为微软推出的自动化工作流工具,其适用场景非常广泛,尤其在数据库查询自动化方面能显著提升效率。2.8发送邮件,把生成csv文件当作附件,把生成html当作邮件内容在邮件boty展示。3.1 读取数据库数据,定时发送预警邮件并抄送附件和展示内容在邮件中。:已有微软产品栈,需快速实现部门级自动化。

qq_24388807的博客 3683

从0开始学Unity做SLG系列(发布篇)

Unity发布流程

super_mali的博客 4997

halcon 查找圆形

先找到大概位置进行拟合,然后再以拟合出的位置作为测量的大概位置进行找圆;

qq_59062726的博客 732

EPICS pythonSoftIOC教程

EPICS pythonSoftIOC教程

yuyuyuliang00的博客 1521

从0开始学Unity做SLG系列(1)

从0开始学Unity做SLG系列(一) 做前端开发最幸运也最悲催的就是永远走在技术的前排,做了十多年的的开发从AS3到H5到cocos2dx到unity,跟着浪潮一阵翻滚,好在兴趣在这里,一路走来倒也不觉得累,不过还是羡慕服务器的同学,一门语言搞到退休。 言归正传,最近要做个unity的SLG项目,这里记录下整个历程,方便之后复盘和加深理解。 因为是工作之余搞项目,所以基本是边学边搞,很多内容可能没有深入分析研究,用到才会说的详细点,所以这个系列可以理解为把各种第三方成熟的东西转化组装成一个SLG,等项目做

super_mali的博客 3775

解决/usr/lib64/libstdc++.so.6和/lib64/libc.so.6版本过低问题

在CentOS7.0中编译好MySQL5.7.14之后,然后在CentOS6.5中初始化MySQL,执行:/usr/local/mysql/bin/mysqld --version出现如下问题:./bin/mysqld: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by ./bin/mysqld)

poxiaonie的博客 2万+

Unity手游实战:从0开始SLG——概览

1 游戏是一个项目 这是从0开始SLG系列的开篇,但是本篇却不准备讲SLG类型相关的东西。在开始SLG项目搭建之前,想先说下我理解的游戏开发到底是个什么东西。 游戏开发从开发模式上可以理解为一个做一个项目,和各种工程项目相比它们都有一个共同的特征,用PMP里的定义就是: 项目是为创造独特的产品、服务或成果而进行的临时性工作。 对的 你没看错,它其实是一个临时性的工作。或许你会拿《魔兽世界》来打比方,05年运行到现在已经10几年了,怎么可能是临时性的呢?那么我要说明两点: 1、即使一个项目持续100年,它也是

公众号:壹种念头,知乎:放牛的星星 2084

《阵列信号处理及MATLAB实现》阵列响应矩阵(均匀线阵、均匀圆阵、L型阵列、平面阵列和任意阵列)

《阵列信号处理及MATLAB实现》内容总结,如需阅读更详细内容请购买正版书籍。

APPLECHARLOTTE的博客 1万+

大模型风电功率预测:短期,超短期,中长期的完整实现与代码详解

本文全面介绍了基于深度学习大模型的风电功率预测方法,涵盖超短期(15分钟-1小时)、短期(1-6小时)和中长期(1天-1周)三种时间尺度。文章详细阐述了数据准备与特征工程,包括数据收集、预处理和可视化分析。针对不同时间尺度,分别介绍了Temporal Fusion Transformer (TFT)、Informer和N-BEATS模型的构建、训练与评估方法,并提供了完整的开源代码实现。此外,文章还探讨了模型部署与生产环境集成,包括模型保存与加载、实时预测API以及模型监控与再训练。最后,文章总结了关键创新

专注AI大模型,软件混淆,授权 1885

支持无级缩放的360展示技术实现之一

两种技术路线 本节介绍展品360展示的两种技术路线,对比其特点。 一、定义即用途 本文所讲的360展示是指用于产品或商品展示的Web浏览方式,它不是以下技术: 360实景:例如谷歌街景,这种技术是观察点在固定点旋转,将拍摄的全景图实现Web互动。360展示则是观察点固...

chunning1112的博客 368

基于PyTorch+Transformer实现谣言检测系统

本项目使用基于`PyTorch+Transformer`的谣言检测模型,将文本中的谣言事件进行连续向量化,通过一维卷积神经网络的学习训练来挖掘表示文本深层的特征,避免了特征构建的问题,并能发现那些不容易被人发现的特征,从而产生更好的效果。

优快云 精品推荐 6349

一些SLG中体会到的设计

快照:玩家属性快照 和 伙伴属性快照,公会快照,然后如果有变化,则同步给中心服和游戏服1份,同时,快照也是有专门的Entity的,从而实现就算没同步,起码也能用,不会空指针。根据摄像机高度,看看哪些需要发,哪些不发,及其能看到的范围,从而实现单位信息下发。全部行军的车都下发,防止路径不容易处理。信任客户端发的能看到的,再做下差值。日志工具: 有哪些bug,耗时统计。rpc:异步rpc。

focus-unchanged-thing 158

YOLO26改进策略【Neck】| arXiv 2025 分层多头注意力HMHA 子空间拆分提多样 + 通道重排降冗余,强化目标检测精度

HMHA(Hierarchical Multi-Head Attention,分层多头注意力)旨在解决传统多头注意力(MHA)在图像恢复任务中的核心缺陷——特征冗余。传统MHA将通道均匀拆分给各个头,导致不同头学习的子空间信息相似,进而出现多头关注同一区域、忽略退化区域修复的问题,限制了模型的特征表达能力。HMHA通过“分层子空间拆分+通道重排序”策略,让每个头学习差异化、互补的上下文特征,从根源上缓解冗余,提升图像恢复任务中对复杂退化场景的特征捕捉能力。

Limiiiing的博客 208

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Unity手游实战:从0开始SLG——浅谈CPU缓存命中和Unity面向数据技术栈(DOTS)

本文以逻辑与表现分离和实战ECS架构和优化进行讲解。本系列前四章相关内容之前已经推送,ECS设计思想和Entitas插件戳此回顾,逻辑与表现分离以及实战ECS架构和优化戳此回顾,本文由第五章开始。 五、浅谈CPU缓存命中 ECS在游戏里的运用,最初是用来解决预测和回放问题的。但是由于面向数据的编程结构,天然符合了现代CPU的编程思想,所以目前Unity ECS主要还是推动展现性能方面的优势。那...

UWA—简单优化,优化简单! 3224

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【Unity】如何在 Unity 中创建带有缩放效果的滚动视图?(简单方法)

【Unity】如何在 Unity 中创建带有缩放效果的滚动视图?使用UGUI实现滑动居中的放大、其他的缩小(简单方法)

weixin_56166431的博客 1070

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

SLG项目开发经验一_大地图方案

前言:现在负责新开的SLG项目,趁现在有时间讲一些SLG地图相关的开发经验。这篇文章主要目的是分享我在项目中遇到的一些问题,同时也算是抛砖引玉,希望能跟各路大佬一起优化方案。 现在这篇主要是讲大地图数据获取的一些心得和经验。PS:现在项目还没立案,以下所说方案不一定能够满足项目的所有需求 1、数据来源 首先数据基本来自前端和后端 基本大地图上面建筑、npc、玩家等信息 ...

weixin_47274565的博客 7693

Unity手游实战:从0开始SLG——逻辑与表现分离以及实战ECS架构和优化

这是侑虎科技第612篇文章,感谢作者放牛的星星供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859) 作者主页:https://www.zhihu.com/people/niuxingxing,作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩! 本系列前两章...

UWA—简单优化,优化简单! 3843

Unity手游实战:从0开始SLG——客户端技术选型

项目背景 所谓选型,我认为就是为了实现某(些)个需求或者解决某(些)个问题所使用的解决方案。它可能是一个技术方案,也可能是一个管理方案,也可以是一个软件、工具或者是流程规范。 这篇的主题是技术选型,所以主要会分析项目客户端部分的技术解决方案。那么做选型分析之前就要先收集需求,分析需求,搞清楚我们的项目需要什么,达到什么效果,实现什么功能。除了项目本身章程和范围之外,还要看同项目的其他部门分工和合作方案(比如服务器的技术对接,美术资源的规范流程以及部分效果的实现对接),在这之外还需要考虑公司的大环境,比如

拓跋江的专栏 761

第六章 3D地形搭建(上)

unity地形Terrain介绍

konkon2012的博客 3225

如何用U3D写一个SLG战斗场景

一般分为图形层和逻辑层 1.图形层: 1.1 地图层:最底层为地图层,用于放置战斗地形图片,需要注意的是图形的大小和分辨率。 1.2 地块层:该层是由一个个战斗地块(四边形/六边形/菱形)拼凑组成,注意给每个地块添加一个布尔属性用于控制该地块是否可以通过(脚本代码如下)。 public class IsCross : BattleManage { public bool isCross = false; } 1.3 角色层 : 该层主要实现人物的模型显示,移动动画,技能等特效。 1.4 UI层:

weixin_47803451的博客 1737

Unity手游实战:从0开始SLG——本地化篇(二)TMP的优势与缺点

1字体的基础知识本地化的常用手段是文本翻译,而文本翻译除了上一篇文章中提到的翻译质量之外,还需要从技术手段上支持多语言在游戏中的显示。在电子产品上展示语言或者文本,最常用的方式就是提供一...

公众号:壹种念头,知乎:放牛的星星 3250
上一篇: UUG 深圳站 | Unity 6 新功能详细介绍和演示
下一篇: 助力 Tuanjie OpenHarmony 开发:如何使用工具包 Hilog 和 SDK Kits Package?
Unity官方开发者社区
博客等级 码龄3年 597粉丝 752原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值