用户在输入框里写下一句:“生成一座中型滑雪场,包含初级、中级和高级雪道,山顶有缆车。”几秒钟后,屏幕上出现了一座覆雪的山,三条缆车线从山脚拉向山顶,十几条绿色、蓝色和黑色的路线从山上铺下来。看起来一切齐全,但有一个问题没有人回答:凭什么这条是绿色,那条是黑色?
在很多生成结果里,难度标签是和路线一起“画”出来的,模型觉得这条路线在山的缓坡一侧,就标初级;那条从山顶陡壁出发,就标高级。这种做法在大部分时候看起来没错,直到一个初学者沿着绿色路线滑到一半,发现前面是一段连中级滑雪者都要犹豫的陡坡。雪道难度不是一个装饰性的颜色,它是给滑雪者的承诺。这篇文章就讨论AI生成滑雪场以后,怎么把这个承诺算出来。
先看山:从高程图到坡度图
滑雪场生成的第一层数据是地形高程图,也就是一张每个格点都记着海拔的网格。以一个模拟场景为例,山体垂直落差约600米,网格精度5米。高程图本身不能直接告诉我们哪里能滑,要先把它转换成坡度图:对每个格点,计算它与相邻格点之间的高差除以水平距离,得到这一点的坡度。
这里有一个经常被搞混的细节:坡度可以用百分比表示,也可以用角度表示。百分比是“每前进100米下降多少米”,角度是坡面与水平面的夹角。两者不是线性对应:40%的坡度约等于21.8度,100%才等于45度。如果生成系统内部用角度,展示给用户时又写成百分比,一条雪道的难度就可能被错判一整个级别。在乐鱼体育的地图生成流程里,内部统一用百分比坡度计算,界面上两种都显示。
常见的雪道分级通常以坡度为主要依据,同时考虑宽度、地形和障碍。作为设计参考,初级道常见坡度大约在8%到25%之间,中级道多在25%到40%上下,高级道可以超过40%。不同国家和雪场的标准并不一致,有的地方按四档分,有的按三档分,同样的坡度在不同地方可能标成不同颜色。所以生成器里的阈值应该是可配置的参数,而不是写死的真理。下文的数值全部是模拟示例。
在坡度图里找出能滑的线
有了坡度图,下一步是划出“可滑区域”。坡度超过一定上限的格点(模拟中设为约80%)视为不可滑的岩壁;坡度低于3%的区域滑雪板会停下来,也要单独标记;树林、岩石、水体和建筑区域在地表覆盖层里剔除。剩下的区域才是雪道可以经过的地方。
雪道不是一条最短路径。滑雪者天然倾向沿着“滚落线”(fall line)也就是最陡下降方向滑行,但初级道恰恰需要避开滚落线,用横切山坡的方式把坡度摊薄。一段50%的山坡,如果雪道与滚落线成约60度角斜着穿过,沿雪道方向的有效坡度就只剩一半左右。这也是为什么同一面山坡上可以同时有初级道和高级道:高级道顺着滚落线直冲,初级道之字形横切。生成器在找路线时,实际上是在可滑区域里做带约束的路径搜索,约束条件是沿路线方向的坡度不超过目标难度的上限。
横切也有代价:它会带来横向倾斜。雪道沿前进方向只有15%,但左右方向倾斜了20%,初学者会一直被往山下那一侧推,比滑一段干净的20%直坡还难受。所以每一段路线都要同时记录纵向坡度和横向坡度。
把一条雪道切成段来算
一条雪道不能只用一个坡度数字描述。以一条模拟生成、长约1.4公里、落差约230米的“初级道候选”为例,系统按约100米一段切开,逐段计算:
| 分段 | 平均坡度 | 最大坡度 | 宽度 | 转弯 | 备注 |
|---|---|---|---|---|---|
| 1–3段 | 12% | 16% | 45米 | 缓弯 | 缆车下站附近,平缓开阔 |
| 4–6段 | 18% | 23% | 35米 | 一个约70度左转 | 横向倾斜约8% |
| 7段 | 31% | 38% | 22米 | 无 | 持续约80米的陡段 |
| 8–11段 | 15% | 20% | 40米 | 缓弯 | 第9段有一处汇流点 |
| 12–14段 | 6% | 9% | 30米 | 无 | 接近山脚,偏平 |
全程平均坡度约16%,看平均数,这是一条标准的初级道。但第7段持续约80米的31%,最大处到38%,而且宽度收窄到22米。一个刚学会犁式转弯的初学者滑到这里,速度会快速增加,能用来转弯减速的横向空间却变少了。
最陡的一段和平均坡度吵起来,听谁的
这是雪道分级里最常见的矛盾。只看平均坡度,第7段会被前后的缓坡“稀释”掉;只看单点最大坡度,又可能被一个5米见方的小鼓包误导,把整条雪道标成高级。
比较合理的规则是:难度下限由“持续最陡段”决定,而不是由单点最大值或全程平均值决定。所谓持续,是指坡度超过某个阈值的连续长度达到一定距离,例如30米以上。一个只有几米长的小鼓包不影响标签;一段80米长的31%,就足以让这条雪道不能再叫初级。平均坡度则用来描述整体体感,比如“大部分路段轻松,有一处较陡段”。
标签被抬高以后,生成器有三条路可以选,并且应该把选择权交给用户:
- 改线:在第7段附近重新搜索路径,用一段横切把坡度摊到22%以内,代价是雪道变长约120米,横向倾斜增加;
- 加宽并降速处理:把第7段加宽到40米,给初学者足够的转弯空间,同时在段首设置减速提示区,但如果坡度仍在30%以上,标签仍应至少是中级;
- 如实升级:把整条雪道标为中级,并在地图上单独标注“第7段较陡”,同时检查是否还有别的初级路线可以代替它。
生成器不应该做的,是为了满足用户“要有初级道”的要求,把这条雪道硬标成绿色。
宽度、转弯、地形和雪况:会把难度往上推的变量
坡度决定难度的底线,其他因素决定要不要往上调。这里有一条重要的原则:这些修正因素只能升级,不能降级。一条40%的雪道哪怕宽得像广场,也不能因为宽就标成初级。
- 宽度(Width):初学者靠大半径转弯控制速度,需要足够宽的横向空间。模拟中初级道建议宽度不低于30米,窄于20米的路段即使坡度只有15%,也应把该段难度上调一级。
- 转弯(Turn):在较快速度下出现的急转,尤其是转弯外侧紧邻树林或陡坎,会明显提高要求。系统会用上一段的预估速度和转弯半径判断,而不是只看转弯角度。
- 地形(Terrain):凸起的坡顶会挡住视线,滑到顶上才看到下面是陡坡;雪包地形、狭窄林间道、横向倾斜都会增加操作难度。
- 雪况(Snow):压实的雪道、粉雪和冰面对同一坡度的难度影响差别很大。雪况会随天气和时间变化,所以系统把它作为动态修正:基础标签不变,但在冰面条件下给出“今日难度偏高”的提示。
最后综合出来的难度,是“持续最陡段决定的下限”加上各项修正后的结果,同时附带每一项的来源,让用户能看到这条雪道为什么被标成中级。
缆车、汇流点和一张路线图的拓扑检查
单条雪道的标签算对了,整座滑雪场仍然可能出错。把缆车上下站、雪道交汇点和山脚服务区看作节点,把每段雪道看作带难度的有向边,整座雪场就是一张图。在这张图上需要做几项检查:
- 初级闭环:对每一个初学者可以乘坐的缆车,从上站出发,只沿初级边,是否存在一条路径回到山脚?如果某条缆车上站只连接中级和高级道,这条缆车就必须标注“不适合初学者”。
- 被迫经过:一条初级道中间如果有一段是中级边,而且没有绕行边,这条路线整体只能按中级计算。
- 汇流点冲突:高级道在第9段汇入初级道,汇入时高级滑雪者速度可能超过50公里/小时,而初级道上的人正在慢速转弯。汇流角度过大、汇流处视线不足,都要标记,并在高级道末端设置减速区。
- 平地陷阱:坡度低于3%且长度超过150米的路段,单板滑雪者可能停下来需要步行,特别是连接两条缆车的过渡道。
- 缆车线路:缆车线不能从雪道正上方低空穿过,下站附近要有足够的排队和汇集区,上站要有平缓的下车区。
这套思路和赛车地图检查自相交、捷径是同一类问题,只是关注点不同。赛车赛道生成更关心弯道和超车,滑雪场更关心坡度和路线图能不能让每个水平的人都有路可走。
让三种水平的虚拟滑雪者各滑一百次
计算得出的标签还需要验证。在乐鱼体育的测试流程中,可以为同一座雪场配置三类虚拟滑雪者,每一类有自己的能力参数:
| 虚拟滑雪者 | 舒适速度上限(模拟) | 转弯方式 | 能稳定处理的最大坡度 |
|---|---|---|---|
| 初级 | 约20公里/小时 | 犁式、大半径 | 约25% |
| 中级 | 约40公里/小时 | 平行转弯 | 约40% |
| 高级 | 60公里/小时以上 | 卡宾、短半径 | 40%以上 |
每类虚拟滑雪者在每条雪道上滑一百次,路线选择带有一定随机性。系统记录速度曲线、超过舒适速度的时长、失去控制和摔倒的位置、被迫停下的位置,以及完成时间。回到那条1.4公里的候选初级道:初级虚拟滑雪者在第7段的速度有六成次数超过舒适上限,摔倒事件中约七成集中在第7段末端和第9段汇流点。这两个位置就是修改的优先级。
改线方案执行以后再模拟一遍:第7段的超速比例降到一成以下,摔倒分布变得分散,第9段汇流点在高级道末端加了减速区之后冲突次数减半。标签“初级”这才算被验证过。
标签是算出来的,也要允许被改
用户看到结果后,也许会说“我想要一条更刺激的中级道”,或者“把山顶那条黑道改得再陡一点”。每一次修改都会触发重新计算:坡度、分段、修正因素、路线图拓扑和虚拟滑雪者模拟。如果某次修改让唯一的初级闭环断掉,系统应该立即提醒,而不是等到有人滑下去才发现。修改前后的版本也应该保留,用户觉得新版本太难,可以回到上一版。
回到开头的问题:AI自动生成一座滑雪场以后,怎么知道一条雪道是初级还是高级?答案不是看它在山的哪一侧,也不是看它画成了什么颜色,而是把这条雪道切成段,找出持续最陡的那一段,再叠加宽度、转弯、地形和雪况的影响,检查它在整座雪场路线图里的位置,最后让不同水平的虚拟滑雪者真正滑一遍。更多运动类型的地图如何处理各自的规则,可以在AI体育地图生成栏目里继续对照。