From 3d8845b8528a14052436048bd4beef8d28420836 Mon Sep 17 00:00:00 2001 From: littlesulley <494597918@qq.com> Date: Sat, 29 Jul 2023 13:40:24 +0800 Subject: [PATCH] Site updated: 2023-07-29 13:40:02 --- index.html | 6 + page/2/index.html | 6 + page/3/index.html | 6 + page/4/index.html | 6 + search.xml | 8502 ++++++++++++++++++++++----------------------- sitemap.txt | 10 +- sitemap.xml | 114 +- 7 files changed, 4337 insertions(+), 4313 deletions(-) diff --git a/index.html b/index.html index 6f51c02e..ad937071 100644 --- a/index.html +++ b/index.html @@ -690,6 +690,12 @@

Sulley

+
  • + Access Object Property by Name:

    A toy plugin for Unreal Engine to access (get and set) any object +property by name.

    + +
  • + diff --git a/page/2/index.html b/page/2/index.html index 7e285fe1..4b4421d3 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -690,6 +690,12 @@

    Sulley

    +
  • + Access Object Property by Name:

    A toy plugin for Unreal Engine to access (get and set) any object +property by name.

    + +
  • + diff --git a/page/3/index.html b/page/3/index.html index 1b8a0982..2213560e 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -690,6 +690,12 @@

    Sulley

    +
  • + Access Object Property by Name:

    A toy plugin for Unreal Engine to access (get and set) any object +property by name.

    + +
  • + diff --git a/page/4/index.html b/page/4/index.html index fab7ac97..9ad65d4a 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -690,6 +690,12 @@

    Sulley

    +
  • + Access Object Property by Name:

    A toy plugin for Unreal Engine to access (get and set) any object +property by name.

    + +
  • + diff --git a/search.xml b/search.xml index 7702ba70..b5aeeaba 100644 --- a/search.xml +++ b/search.xml @@ -1638,2435 +1638,1801 @@ Verlet and adding Vetlet damping - Midjourney和NovelAI不完全使用指南 - /2022/10/22/17/37/ - 显然,AI绘画已经发展到了一个新的阶段。尽管现在市面上已经有不少AI绘画工具,但要熟练地掌握使用它们也绝非易事。本文从实践出发,为读者讲解如何更好地使用Midjourney和NovelAI这两个时下火热的AI绘画工具,但由于笔者使用时间较短,无法完全驾驭AI绘画工具,因此本文是“不完全指南”。如果本文有任意谬误或缺漏,希望读者能不吝指出。

    + The Jittering Issue with Damping in Cinemachine and How to Tackle it + /2023/07/08/18/22/ + If you are familiar with Cinemachine. you probably know there is a +knotty problem with Cinemachine' damping if you are using +Framing Transposer or some other components to track a +follow point. That is, the camera jitters with damping enabled under +unstable frame rate. The more unstable frame rate is, the more heavily +camera will jitter. This post will discuss this phenomenon and proposes +a workaround to solve this issue.

    -

    Midjourney不完全使用指南

    -

    太长不看版:使用规范

    -
      -
    1. 首先根据公式 Prompt = 构图说明 + 画面内容 + 美术风格 + -光影设置 + 其他描述 + 参数列表 按照下面的模板写Prompt: -
        -
      • 人物特写:a {headshot | closeup} portrait of [content], [art style], [lighting], [other keywords], [MJ parameters]
      • -
      • 人物半身照:a {medium shot | over the shoulder shot | head and shoulder shot} portrait of [content], [art style], [lighting], [other keywords], [MJ parameters]
      • -
      • 人物全身照:a full body portrait of [content], [art style], [lighting], [other keywords], [MJ parameters]
      • -
      • 风景/建筑照:[content], [art style], [lighting], [other keywords], [MJ parameters] -上面用大括号{}括起来且用竖线|分割的内容是多选一,即从所有可选的关键词中选一个即可。用中括号[]括起来的是我们需要根据画面内容填写的。下面介绍中括号填写的基本规范:
      • -
      • [content]:是我们要填写的画面内容。如果是人物,主要填下面的内容(不一定都需要,也不一定完整,根据你的需求): -
          -
        • 什么人:{boy | girl | woman | old lady | warrior | witch | anthropomorphic white tiger | ...}
        • -
        • 脸部特征:{beautiful face | dedicate facial features | colorful tattoos on her face | ...}
        • -
        • 表情:{smile | crying | moaning | angry | ...}
        • -
        • 眼睛:{beautiful blue eyes | shining diamond eyes | ...}
        • -
        • 头发:{long curly black hair | flowing hair | braided hair | ... }
        • -
        • 装饰:{exquisite garland | opal decorations | wearing feather headdress | ...}
        • -
        • 穿着:{wearing tall black high heel boots | in purple and white kimono | ...}
        • -
        • 其他细节:{made of flower | rain on her face | ...} -如果是非人物,则一般不需要写这么细,只要描述大概是什么物体就好了。比如magnificent mountain, -interior of a cyber punk city等等。
        • -
      • -
      • [art style]:指定艺术风格,可以通过三种方式指定: -
          -
        • 直接指定主题/绘画风格:比如cyber punk, -steam punk, japanese anime, -oil painting, realistic painting, -ink painting, ukiyo-e, -bookstory illustration等等;
        • -
        • 直接指定相关风格的艺术家:比如吉卜力风格可以说art by {ghibili | koji hoshino | hayao miyazaki},皮克斯/迪士尼风格可以说art by {pixar | disney},等等;
        • -
        • 直接指定作品:比如breath of the wild, -dark souls, world of warcraft, -lord of the rings等等。 这里推荐使用第二种方式。
        • -
      • -
      • [lighting]:画面的光影效果,一般来说使用{cinematic lighting | volumetric lighting}比较通用。但对人物,你偶尔还需要用{back lighting | rembrandt lighting | spotlight};对非人物,你可能还要{morning lighting | flare}等等。
      • -
      • [other keywords]:其他关键词包括: -
          -
        • 材质:{cubic | bronze | wood | liquid | glass | prism | smoke | plume | milky way | ...}
        • -
        • 色彩:{dark pink | rainbow | vibrant | warm color | black and white | monochrome | ...}
        • -
        • 形状:{star | torus | polygonal | low poly | interior | stellation | stellation | ...}
        • -
        • 其他一般默认加上用来叠BUFF的词:{intricate details | 8K | enchanting | masterpiece | octane render | unreal engine 5 | well composed | award winning | high resolution | ...}
        • -
      • -
      • [MJ parameters]:Midjourney要填写的参数,一般使用下面的参数组合(但也要有意识地灵活运用): -
          -
        • 人物特写照:{--ar 1:1 | --ar 3:4} --q 1.5
        • -
        • 人物半身照:{--ar 3:4 | --ar 9:16} --q 1.5
        • -
        • 人物全身照:{--ar 2:3 | --ar 9:16} --q 1.5
        • -
        • 非人物照:根据你的画面内容选择宽高比,如果是横板,则用--ar 16:9 --q 1.5;如果是竖版,则用--ar 9:16 --q 1.5;如果是加长竖版,则用--ar 9:32 --q 1.5
        • -
      • -
    2. -
    3. 写好之后,多次出图,你也可以尝试几次参数--test --creative--testp,一般来说效果会更好些,但注意风景图不要用--testp
    4. -
    5. 从所有的图中找到让你比较满意的图,使用UpscaleVariantRemaster功能对它们增强,反复出图;也可以继续在Prompt中增删细节,直到满意为止。
    6. -
    -

    关键词参考工具
    -更完整的关键词参考
    -艺术家参考
    -风格参考 -其他人的作品参考1 其他人的作品参考2

    -

    概述

    -

    Midjourney是当前最流行的AI绘画工具之一,它部署在Discord上,因此你需要注册一个Discord账号才能使用。

    -

    所有的AI绘画工具最重要的就是如何写Prompts,也就是文本描述。在开始之前,你需要知道写Prompts的几个基本准则:

    -
      -
    • 详略得当:描述越详细,图片越有可能接近你想的画面,但是也有更大的概率生成的图片质量更低;描述越简略,图片越多样化,质量也可能更高。但注意不要加太多细节,否则会图片会很低。一般来说,我们只需要写”意象“,而不要写得过于具体。
    • -
    • 以短代长:少用超过10个词的句子,而用多个短语,每个短语描述画面的一个细节/部分/风格。即使要用长句,也不要太长,保持在20词以内。
    • -
    • 反复润色:不可能第一次生成的图片就完全符合你的想象,需要不断给Prompts润色修改,这不是一个简单的活,因此请保持耐心。
    • -
    • 具象描述:尽量用一些具象的名词、形容词,比如river, -rockstar, Zeus, landscape, -happy, -dark等等,不要用一些难以在现实中找到对应实体的词,比如knowledge, -notion, type等等。
    • -
    • 指定量词:显式指定对象的数量,如果是一个就用a,如果是多个就指定具体数量。
    • -
    • 描述风格:在多数情况下都需要增加风格关键词,比如cyberpunk, -surreal, abstract, -realistic,也可以指定一个或多个艺术家,比如hiroshi yoshida, -Max Ernst, MC Escher, -Yoji Shinkawa等。此外,你还可以指定具体的绘画形式,比如sketch, -woodblock print, oil painting, -watercolor painting等等。
    • -
    • 描述构图:可以显式指定构图,比如a portrait of, -an ultrawide shot of, a headshot of, -a closeup of等。
    • -
    -

    MJ官方文档:https://midjourney.gitbook.io/docs/

    -

    注册账号

    -

    Midjourney当前作为Discord的内置服务,你可以按照下面的步骤注册账号开始使用:

    -
      -
    1. 登陆官网,点击Join the beta: -
    2. -
    3. 进入后输入昵称,加入Discord,如果你没有discord,可能需要根据提示注册一个,之后进入服务器: -
    4. -
    5. 进入一个以#newbies开头的频道,比如#newbies-117:
    6. -
    7. 在下方的输入框中输入/imagine,此时就能在弹出来的prompt框中输入你想要生成图片的文本描述了,比如我这里输入的是a -white flower is crying,稍等片刻,就能在聊天框中看到生成的4张图像了: -
    8. -
    9. 除了生成的4张图像外,下方还有两行按钮,分别是U1/U2/U3/U4和V1/V2/V3/V4,分别表示增大每张图的分辨率,以及为每张图重新随机生成。在点击增大分辨率之后,对应大图会重新发送在频道中,下方也会随之出现几个新按钮,见字如义: -
    10. -
    11. 如果你不想在公共频道,你也可以自己创建一个频道,然后邀请Midjourney -Bot到你的频道中。首先在左侧点击添加服务器;然后创建一个私有服务器;最后回到Midjourney的官方服务器,找到Bot,点击后把它添加至服务器即可。 -
    12. -
    -

    然后你就可以在你自己的服务器里愉快地玩耍了!

    -

    使用教学

    -

    首先记住下面的公式:

    -

    Prompt = 构图说明 + 画面内容 + 美术风格 + 光影设置 + -其他描述 + 参数列表

    -

    其中,“构图说明”也可以放在“美术风格”后面,但一般来说直接通过a portrait/closeup/wide angle shot of ...指定了。除了“画面内容”是必须的之外,其他的都可以省略。

    -

    建议初学者在这个网站这个网站找对应的关键词,多做尝试。

    -

    构图说明

    -

    构图说明指定是怎样的构图,比如特写、近景、远景等等。有下面基本的构图: -- 特写: closeup, portrait - -全身照:full body, full body portrait - -风景:wide angle, epic composition, -low angle, high angle

    -

    Prompt一般直接用a [composition] of ...开头,其中[composition]就是你选择的构图,比如你想要一个特写,你就可以说a closeup shot of ...或者a headshot portrait of ...;如果你想要一个全身照,你就可以说a full body portrait of ...

    -

    对于风景图,一般不用上述格式,而是直接以内容开头,把构图放在后面,比如vast grassland, wide angle, epic composition,首先说明内容是草原,然后再说用广角镜头和宏大构图。

    -

    下图分别是特写/中景/远景的例子,Prompt为a [composition] of an old asian lady --ar 3:4 --q 1.5,其中[composition]分别替换为closeup shot, -medium shotfull body portrait,同时把宽高比分别设置为3:4, -2:39:16。最后一张图是风景图,Prompt是vast grassland, wide angle, epic composition --q 1.5 --ar 32:9

    -

    -

    你可以看到几种构图之间的差别,至于为什么要更改宽高比,详见下面的参数列表。

    -

    画面内容

    -

    画面内容指定画面内容。该部分根据需求可详可略,但一般都以多个短语组成,比如下面我想以凤凰为原型设计一个角色,全身照,有红色和黄色的花,穿着彩色华丽的装饰,因此输入的Prompt为a full body portrait of a phonix goddess, red and yellow blossoms, wearing rainbow opal accessories, exquisite decorations --ar 9:16

    -

    -

    第一张图加了参数--test,因此细节更加丰富。

    -

    对于非人物也是相同的,比如我现在想设计一个亚特兰蒂斯城,它矗立在悬崖边,有着豪华的建筑,我就可以用the city of Atlantis on steep cliff, enormous beautiful palace, exquisit architecture --aspect 9:32 --q 1.5,得到下面的图:

    -

    -

    前两张图用了--test

    -

    再次强调:描述内容的详略会极大影响生成的结果,越详细,生成的图片会越接近你想象中的画面,但有更大概率质量更低;越简略,越有可能生成非常酷的图片。因此,是否详略取决于你在脑海中是否已经有一个大致的画面,如果你完全没有想法,请尽量保持简略!

    -

    比如对我想要的凤凰角色,我不知道她具体是什么样子的,就只需要输入a full body portrait of a phonix goddess --ar 9:16就可以了,然后再不断添加细节(前两张图是原始Prompt,第三、四张图增加了red and yellow blossoms):

    -

    -

    美术风格

    -

    美术风格指定图片的美术风格是怎样的。美术风格非常重要,它直接决定了图片内容是否与你想象中的相符。我们可以通过三种方法指定美术风格:(1)绘画风格,如realism, -realistic, abstraction, -impressionism, oil painting, -cover art, -comic book等等;(2)艺术家名字,如Rolf Armstrong, -Lois van Baarle, -Aubrey Beardsley等等;(3)与该风格有关的作品/游戏,如breath of the wild, -genshin impact

    -
      -
    • 指定绘画风格:比如现在我想对上面的凤凰角色风格化,我可以指定不同的绘画风格,比如下图是依次指定为realism, -abstraction, watercolor painting, -oil paintingcartoon, anime的结果:
    • -
    -

    -
      -
    • 指定艺术家:相比指定风格,一个更好的方法是直接指定艺术家,比如我依次指定了下述艺术家Alphonse Mucha, -Alyssa Monks, Andreas Rocha, -Miyazaki HayaoEric Lacombe,所生成的图片是:
    • -
    -

    -

    你也可以指定多个艺术家,但最好它们风格相似。你可以在这个表里找到一些参考艺术家。

    -
      -
    • 指定相关作品:你还可以显式指定作品,下面的图依次显式指定了作品naruto, -breath of the wild, dark soul, -genshin impactminecraft
    • -
    -

    -

    一般来说,推荐直接指定艺术家,辅之以绘画风格和相关作品,注意这三者之间的风格要尽量保持一致。当混用的时候,艺术家放在前面。

    -

    光影设置

    -

    图片的光影也是重要的一部分,我们可以直接指定光影的类型。比如我们以vast grassland with a lake in the center, a giant tree growing by the lake, --ar 16:9 --q 1.5为基础Prompt,分别考虑下述光影moody lighting, -morning lighting, cinematic lighting, -soft lighting, volumetric lighting, -rembrandt lighting, -godrayschiaroscuro

    -

    -

    除了风景图之外,人物也可以应用不同的光影。下面以a full body portrait of a phoenix goddess, red and yellow blossoms, wearing rainbow opal accessories, exquisite decorations --ar 9:16 --q 1.5为基础Prompt,同样依次加入上面的光影设置:

    -

    -

    可以看到,光影能够影响画面的整体风格,因此,根据内容选择一个合适的光影至关重要。

    -

    其他描述

    -

    除了上面的构成要素外,你也可以增加其他你想要的关键词,大致可分为下面几类。

    -

    材质

    -

    材质(Material/Texture)也可以用来描述画面的整体风格和细节,比如cubic就可能会使画面出现方块状物体。

    -

    下面以a beautiful moon above the desert, the moon is in intricate details, marvel cosmic, Cory Loftis, Conrad Roset, epic composition, low angle, dramatic lighting, spotlight, greyscale, cubic, [material], psychedelic, 8k --ar 2:3 --q 1.5为基础Prompt,分别使用材质cubic, -bronze, carbon fiber, foil, -glass, wood, -liquidsmoke, plume

    -

    -

    可以看到,加入不同的材质会整体或局部地影响画面。carbon fiber使画面增加了颗粒感,glass让月亮出现了玻璃状物体,smoke, plume使得画面出现烟雾。当然这里由于Prompt前面的内容足够丰富了,导致部分材质的影响较小,所以区别不是很明显。

    -

    如果用简单的描述,再搭配材质关键词,效果会更明显些(Prompt为a tree, [material] --ar 9:16):

    -

    -

    颜色

    -

    在Prompt增加一些与颜色有关的关键词有助于生成你想象中的画面。最简单的就是直接添加颜色词,比如red, -black, -blue等等,但这样效果不一定好。一般来说,我们可以增加带有色彩意向的词,比如rainbow, -vibrant, warm color, prismatic, -black and white, monochrome, -high contrast等等。

    -

    下面以a medium shot portrait of a beautiful women in dark green kimono, beautiful face, smile, blue eyes, long black hair, painted by Anne Stokes, rembrandt lighting, [color], ultra detailed, plume --ar 2:3 --s 5000为基础Prompt,分别以vibrant color, -prismatic, black and white, -monochrome, -colorful, rainbow为颜色关键词:

    -

    -

    形状

    -

    你还可以添加形状关键词。这个形状不一定是常见的三角形、正方形,也可以是跟形状有关的物体,比如金字塔pyramid, -星星star,心形heart等等。

    -

    比如以a mountain, [shape] --ar 9:16为基础Prompt,考察下述形状star trapezohedron, -star prism, torus, polygonal, -polyhedron, interior, stellation, -square, heart, gear

    -

    -

    polygon(多边形)是一种常见的风格,interior则会绘制物体的内部。

    -

    其他

    -

    一些其他对画面有帮助的词包括: - -细节程度:very detailed, spectacular details, -ultra detailed, intricate details - -清晰度:4k, 8k, high definition - -景深:depth of field, Canon 50mm - -情绪:enchanting, impressive - -气氛/环境:vintage, retro, -cosmic, celestial, seaside, -lucid dream, plume, Gossamer - -绘法:spatter, drips

    -

    你也可以增加其他的意象词。

    -

    参数列表

    -

    你可以在Prompt的最后添加一些参数,用于生成你想要的图片风格和质量。下面列出所有参数,其中加粗的是最常用的。

    - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    参数功能
    /imagine呼出prompt,根据文本描述生成四张图片
    /info查看当前正在运行的任务
    /fast(/relax)切换为使用Fast/Relax GPU时间
    /private切换为private模式,其他人不可见你的图片
    /public切换为public模式,其他人可见你的图片
    --hd使用旧算法,适用于抽象和风景图,图片分辨率更高
    --ar 显式指定图片的宽高比,比如 --ar 16:9
    --w 显式指定图片的宽度,比如 --w 320
    --h 显式指定图片的高度,比如 --h 256
    --seed 显式指定种子数
    --no 生成的排除该关键词,比如--no -plants为去掉文本中的”plants”
    --iw 设置prompt中的图片/文本权重比,默认0.25
    --s 指定生成图片的风格化程度,值越大,图片越“抽象”,默认为2500
    --q 指定图片质量,默认为1,值越大,细节越多,但耗时越长
    --chaos 指定图片的随机性,值越大,生成图片越多样,范围[0,100]
    --fast更快地生成图片,但质量会更低,近似于--q -0.5或--q 0.25
    --stop 在n%的时候停止终止生成
    --uplight在Upscale的时候用light版本,增加更少的细节,与原图更接近
    --testp生成更接近现实的图片
    --test生成更多样化、风格化的图片
    -

    指定宽高比:--ar

    -

    --ar指定了生成图片的宽高比,默认为1:1。宽高比会极大影响所生成的图片,比如下面的例子(基础Prompt为Utah teapot, wood --seed 1,从上到下、从左到右分别是宽高比为1:1,2:3,4:9,4:16,3:2,16:9,9:4,16:4): -

    -

    可以看到,对于同样的内容描述,宽高比直接影响所生成的内容,这是因为AI默认会“填满”整个图,所以在设定宽高比时,要注意你要生成的内容是怎样布局的。

    -

    指定风格化程度:--s

    -

    -s指定了图片的风格化程度,或者"天马行空度"。默认值为2500;20000会让你的图片看起来比较抽象,但也没有完全偏离你的prompt;但是60000会让图片完全无视prompt自由发挥。

    -

    下面举几个例子说明(基础Prompt为Utah teapot, wood --ar 16:9 --seed 1,左边是2500,中间是20000,右边是60000):

    -

    -

    可以看到,--s 20000时图片的某些部分已经不符合输入的Prompt里,比如这里丢失了木头材质的信息;--s 60000时就开始放飞自我了。

    -

    对于这个参数,一般来说保持默认即可,如果你想要更多样化的结果,可以用5000~10000之间的值。

    -

    指定细节度:--q

    -

    -q指定了图片的质量,也就是细节的丰富度。默认值为1;2会让图片细节更加丰富,但生成速度也是原来的一半;5会让图片细节爆表,但也有可能导致图片整体效果很差。

    -

    下面举几个例子说明(基础Prompt为Utah teapot, wood --ar 16:9 --seed 1,左边是0.25,中间是1,右边是2):

    -

    -

    可以看到,图片的细节度是递增的。当然这个例子过于简单了,导致细节度高的茶壶反而有点奇怪。

    -

    这个参数我比较喜欢用--q 1.5,谁不喜欢更多细节呢?

    -

    生成更逼真/风格化的图片:--testp, ---test

    -

    --testp让生成的图片更加逼真,而--test会让图片更加风格化。注意这二者都会只输入一张图片而不是通常的四张图。

    -

    下面有个例子(基础Prompt为Japanese house with pink roof --ar 16:9 --seed 1,左边为--testp,右边为--test):

    -

    -

    左侧的房子很逼真,右侧则不完整。当然这个例子可能不够好,但足以说明这两个参数的区别。

    -

    值得注意的是,并不是增加了--testp生成的图片就一定是更现实的,但一般而言是更逼真的。比如你想生成一张二次元萌妹,加了--testp之后反而可能会让萌妹更加仿真,虽然我们都知道她不是现实中存在的。

    -

    加入参考图片

    -

    除了纯文字内容外,Prompt还支持插入图片,让生成的图片在内容和风格上参考给定的图片。

    -

    要插入图片,只需要把图片的链接放在Prompt开头就可以了,比如: -https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Utah_teapot_(solid).stl/1200px-Utah_teapot_(solid).stl.png Utah Teapot --ar 16:9 --seed 1 -这个Prompt最开始的链接就是图片地址,然后就是常规的文本内容,把原图和生成的图片做个对比:

    -

    -

    再对比一下没有参考图生成的图片Utah Teapot --ar 16:9 --seed 1

    -

    -

    显然,有参考图生成的图片在风格和形状上都更接近所提供的图,而没有参考图所生成的图片差异较大。

    -

    此外,你还可以通过参数--iw控制参考图的权重,默认是0.25。下面再分别给出权重为0.5和1时所生成的图:

    -

    -

    可以看到,AI在很努力地模仿参考图的颜色、形状,但仍然颇有难度。一般来说,用默认的数值就可以了,如果你想要参考图的权重更大些,设置为0.5也足够了。

    -

    实战操作

    -

    我们把上面说的综合起来使用给几个例子。

    -

    吉卜力风格的风景

    -

    第一个例子,我想生成一只小船在水村中航行的图,村落有着丰富的细节,吉卜力的风格,同时增加一些晨光。我可以用这个Prompt:A boat ride through a flooded seaside village, beautiful elaborate architecture, painted by Miyazaki, Nausicaa Ghibli, morning lighting, high saturation, spectacular details, epic composition, wide angle, low angle --ar 9:32 --q 1.5,经过几轮比较随意的迭代,我找到下面几张还不错的图:

    -

    -

    黑暗系风格的怪物

    -

    在第二个例子中,我想设计一个黑暗系风格的怪物。女神似乎在一般的作品中是一个正面的形象,那如果是一个腹黑女神呢?从这个出发,我试着尝试让AI画出一个黑暗系的腹黑女神,有白色裙子、邪恶笑容、黑色翅膀和金色花饰,绘画风格偏现实主义,艺术家选定为Dorothea -Tanning。

    -

    最后我把Prompt设定为a full body portrait of a wicked goddness, beautiful white dress, evil smile, red eyes, black wings, shining gold flowers on her hair, concept art, photo realistic, painted by Dorothea Tanning, back lighting, dramatic lighting, greyscale, intricate details, bold brushstrokes, mystical --ar 2:3,给出了下面的几张图(最后两张图使用了--testp):

    -

    -

    上面的图比较明显的不足是人物脸部,尤其是眼睛都没有得到很好的处理,这是当前MJ画全身照的缺点。当我们画半身照人物特写的时候一般没有这个问题。

    -

    蒸汽朋克风格的建筑

    -

    第三个例子,我们想画一个蒸汽朋克风格的建筑,细节越多越好。坐落在水边,有丰富的光影,整体基调呈现暖色。

    -

    因此,我们选用Prompta beautiful magnificent steampuck building by the seaside, view from the sea, rigorous architecture, ultra realistic, epic composition, wide angle, close up, morning lighting, volumetric lighting, warm colors, intricate details, 8K, hd, unreal engine, enchanting --ar 9:32 --test --creative,生成了下面几幅图:

    -

    -

    加入一点艺术家得到下面的图(图一二painted by Earl Norem, Edwin Lord Weeks,图三painted by Elizabeth Shippen Green,图四Ford Madox Brown,图五Farel Dalrymple,图六François Schuiten,图七Franz Marc,图八Georges Rouault):

    -

    -

    在实验的过程中发现:不要将--testp用于风景图,否则会有奇怪的东西;相反,在人物图上用--testp效果很好。

    -

    使用建议

    -

    基于上面的使用方法和我自己的实验,初步建议大家在使用的时候遵循下述规范:

    -
      -
    • 重视参数--ar!很有时候宽高比会严重影响生成的图片,即使输入的其他内容完全一致。比如你想画个人物肖像,如果你的宽度太小无法容纳一张脸,那么AI就完全不会生成正确的肖像画;而如果宽度太大,则可能会出现多个人或者其他不必要的元素。一般来说,宽高比和画面内容的关系如下: -
        -
      • 人物特写/Headshot:使用--ar 1:1或者--ar 3:4,并搭配headshot, -closeup, portrait等关键词
      • -
      • 人物半身照/全身照/角色设计:使用--ar 3:4--ar 9:16,搭配full body, -head and shoulder shot, over the shoulder, -medium shot等关键词
      • -
      • 风景图/远景:使用--ar 16:9,搭配landscape, -establishing shot, epic composition等关键词 -宽高比的选择完全取决于你想要生成怎样的内容,如果你想生成一个竖版的风景图,也完全可以使用--ar 9:16,总的原则就是!!#e06666 -画面内容与宽高比保持一致!!
      • -
    • -
    • 重视艺术风格!一个合适的艺术风格可以给你的画面带来极大的改变。当你需要偏现实的风格时,可以尝试realistic, -photo realistic, -ultra realistic等关键词,然后去找合适的现实主义风格的艺术家。当你需要特定的风格时,请精准描述艺术风格,比如浮世绘ukiyo-e,油画oil painting,流行艺术pop art,赛博朋克cyber punk,封面画cover art, -吉卜力Ghibli等等,这需要你对现有的艺术风格有比较丰富的了解!很多时候并不是你画不出来,而是你找不到对应的风格。你可以使用同一风格的多个艺术家作为关键词让画面更加倾向该风格。
    • -
    • 重视参数--test--testp!有时候仅用普通的2*2图片不能得到比较好的结果,尤其是Prompt较长的时候。此时,可以多用一下参数--test--testp,也许会带来意想不到的结果。注意,--testp不要用于风景图。
    • -
    • 重视参考图!尽管本教程没有过多阐述参考图的效果,但是当你手头有很多参考图时,不妨直接使用它们。记得调整参考图的权重--iw
    • -
    • 重视”魔法“关键词!有一些比较通用的关键词,比如intricate details, -unreal engine 5, enchanting, -ornate, after effect, -well composed, elaborate, -Sony Alpha等等,可能会提升画面的细节效果,不妨多试试它们。
    • -
    • 多尝试,出一张效果好的图需要运气,也需要认真地调试。
    • -
    -

    最后奉上几张AI绘制的浮世绘风格的图片,希望大家使用愉快 ;p

    -

    -

    参考资料

    -

    MJ官方文档
    -关键词参考工具
    -更完整的关键词参考
    -艺术家参考
    -风格参考
    -其他人的作品参考1
    -其他人的作品参考2

    -

    NovelAI不完全使用指南

    -

    太长不看版:使用规范

    -
      -
    1. 首先按照公式 Prompt = 起手叠BUFF + 构图说明 + -画面内容 + 画面风格 + 光影设置 + 颜色设置 + 其他意象 -去写Prompt,具体来说:

      -
        -
      • 起手叠BUFF:把下面的内容放到你要写的Prompt最前面,起手BUFF还是比较重要的: -{masterpiece}, {best quality}, {ultra-detailed}, illustration, beautiful, 8K, small breasts -最后的small breasts可以换成madium breasts或者其他(你懂的)。
      • -
      • 构图说明:人物在画面中的位置、大小、角度等等,常用的有portrait(特写)、medium shot(半身照)、full bodyupper body(全身照)、dutch angle(倾斜镜头)、wide angle(广角镜头)、side view(从侧面看)、back view(从后面看)等等。
      • -
      • 画面内容:画面里需要包含的各种内容,可以从人物本身和背景两个角度分别描述。人物内容包括头发、脸部、眼睛、肩膀、耳朵、配饰、手、服装、手套、鞋子等等,但首先需要指定包含几个人,比如1 girl, -solo;背景就根据自己的需求增加内容即可,比如dragon background, -forest background, beautiful milkyway, -burning bettlefield等等。此外,你还可以使用关键词reference sheet生成三视图、设计图。
      • -
      • 画面风格:画面的美术风格,常用的包括realistic, -outline, sketch, flat color, -watercolor (medium), grey scale, -ukiyo-e, cover art, poster, -comic, art nouveau, cyberpunk, -sci-fi, wildstyle, 等等。
      • -
      • 光影设置:和MJ一样,设置画面的光影,主要包括:背光backlight, -电影打光cinematic lighting, 圣光holy light, -日光sunlight, 月光moonlight, -波光粼粼glistening light of waves, -金色光golden light等等,你也可以根据需求创造属于你的光影。
      • -
      • 颜色设置:使用颜色关键词让画面整体更偏向某种颜色。
      • -
      • 其他意象:你可以加入任意多的其他意象词为画面添加细节和内容,比如:阳光sunlight, -河流river, 水晶crystal, -棱镜prism, 冰ice, 浮动floating, -照射shine, 影子shadow, -装饰ornament/decoration/frills, 火焰flames, -火花sparks, 光晕flares, -核爆nuclear explosion, -飞溅的血splashing blood, -飞舞的花瓣flying petals, 等等。
      • -
    2. -
    3. 把下面的内容写到Undesired -Content中,然后再加入你想屏蔽的其他关键词: -{{{ugly}}},{{{duplicate}}},{{morbid}},{{mutilated}},{{{tranny}}},{breast},mutated hands,{{{poorly drawn hands}}},{{bad anatomy}},{{{bad proportions}}},extra limbs,cloned face,{{{disfigured}}},{{{more than 2 nipples}}},{{{{missing arms}}}},{{{extra legs}}},{{{{{fused fingers}}}}},{{{{{too many fingers}}}}},{{{unclear eyes}}},{{{fused hands}}},{{{fused leg}}},{{{bad feet}}},nsfw,lowers,bad anatomy,bad hands,text,error,missing fingers,extra digit,fewer digits,cropped,worst quality,low quality,normal quality,jpeg artifacts,signature,watermark,username,blurry,bad

    4. -
    5. Steps默认28,Scale默认为7,当然你可以根据实际需求调整这两个值。Samping使用默认的k_euler_ancestral即可;

    6. -
    7. 对你比较满意的图使用VariationEnhance,反复迭代,直到满意为止。

    8. -
    -

    概述

    -

    NovelAI是基于Stable -Diffusion模型改进的AI绘画工具,它擅长绘制二次元人物图,虽然也可以把它当作综合性的绘画工具,但是生成的图片偏写实,质量不如Midjourney。

    -

    写NovelAI -Prompt的基本准则是:用关键词(或者称为Tag)描述,而不要用短语甚至句子。关键词包括画面内容(人物头发、眼睛、表情、服饰、姿势、手部、胸部、肩部,等等)、画面风格、构图设置、光影设置、颜色设置、意象词和叠BUFF词等等。

    -

    总的来说,写NovelAI -Prompt相比MJ更容易些,但要实现精准调教仍然难度很大。下面会详细介绍。

    -

    NovelAI官方文档
    -关键词参考

    -

    注册账号(官方)

    -
      -
    1. 登陆官网,注册并登陆账号。

    2. -
    3. 之后在打开的页面上点击“Generate Images”,或者直接通过网页进入:

    4. -
    5. 最后输入Prompt并调整右侧参数开始使用:

    6. -
    -

    本地版本

    -

    To do

    -

    使用教学

    -

    NovelAI的Prompt跟MJ差不多,主要遵循下述公式: Prompt = -起手叠BUFF + 构图说明 + 画面内容 + 画面风格 + 光影设置 + 颜色设置 + -其他意象

    -

    在介绍每个部分之前,需要先讲解下NovelAI各个参数的作用。

    -

    NovelAI的参数

    -

    -

    从上到下,从左到右:

    -
      -
    • Prompt:在这个地方输入你的Prompt,使用大括号{}增加一个关键词的权重,使用中括号[]去减少关键词的权重,支持嵌套,比如{{magical}}就表示生成图像的时候会特别关注magical的内容,而[[[green]]]则表示生成时尽量避免生成绿色的内容;
    • -
    • 分辨率:在这里设置你图像的分辨率,可以使用预设,也可以手动输入,这个参数非常重要,同MJ,要和你生成的内容相匹配
    • -
    • Number of images:生成图像的数量;
    • -
    • Undesired -Content:输入不想要AI生成的内容的关键词;
    • -
    • Add Quality Tags:默认勾上就行;
    • -
    • Steps:生成一张图需要的步数,步数越大,生成的时间越长,而且效果也不一定好,一般使用默认值28就好了,除非你已经找到一个很好的Prompt想要增加更多的细节;
    • -
    • Scale:控制所生成图像匹配你输入Prompt的程度,值越小,画面越风格化和柔和,值越大,画面越细节和尖锐,但设置过大可能导致效果变差,一般来说使用小于10的值;
    • -
    • Sampling:生成时的采样方法,一般而言使用默认的即可。
    • -
    -

    -

    在生成图像后,会多出来一排选项,其中比较重要的是后面两个:

    -
      -
    • Variations:生成当前图片的变体,在细节上会有不同,但大体都是一样的;
    • -
    • Enhance:对当前图像进行增强,会较显著地增加细节。但注意不要把Noise调太高。
    • -
    -

    起手叠BUFF

    -

    NovelAI要把关键信息放在Prompt的前面,因此我们一开始就要叠BUFF,可以先无脑加入下面的BUFF,然后再根据你的需求自行添加: -{masterpiece}, {best quality}, {ultra-detailed}, illustration, beautiful, 8K, small breasts

    -

    注意上面的最后一个BUFFsmall breasts限制了生成角色胸的大小,对于女性角色必须要有(否则全是涩图)!你如果不喜欢平胸,可以用medium breasts,或者你生成的不是女性,就把这个去掉即可。

    -

    构图说明

    -

    和MJ一样,可以用portrait表示特写,用medium shot/upper body表示上半身构图,用full body shot表示全身照。

    -

    除此之外,还可以用dutch angle表示倾斜镜头,用wide angle表示广角镜头,用low angle表示低角镜头,用depth of field增加景深,用side view表示从侧面看,等等。你可以根据自己想象中的内容选择合适的组合。

    -

    !!#3d85c6 这个网站有一些主要的关键词:https://aitag.top/ -。下面的所有内容都可以去参考这个网站,不再赘述。!!

    -

    比如下面我用了一些不同的构图关键词去生成a beautiful girl(关键词分别是portrait, -medium shot, full body shot, -full body shot, dutch angle, -portrait, dutch angle, depth of field, -portrait, side view, -full body shot, back view, -full body shot, from above):

    -

    -

    画面内容

    -

    你首先需要明确图片中包含几个角色,一般来说是一个,那么你只需要加入solo1 girl/1 boy即可。如果是两个,就是two girls,以此类推。

    -

    然后,你需要描述这个角色的各种细节,可以从下面角度考虑(不一定都要,看你需求):

    -
      -
    • 头发:disheveled hair, floating hair, -azure hair, long hair, -short hair, beautiful hair, -white hair, curly hair, bob hair, -polytails, updo, -twintailsside blunt bangs,等等
    • -
    • 脸部:tears, cold attitude, -smile, sad, annoyed, -delicate beautiful face, -detailed face,等等
    • -
    • 眼睛:Lavender eyes, crystal eyes, -bright eyes, beautiful detailed eyes, -half closed eyes, hollow eyes, -blank stare, rainbow eyes, -gradient eyes, sparking eyes,等等
    • -
    • 肩膀:bare shoulder, off shoulder
    • -
    • 耳朵:pointy ears
    • -
    • 手:outstretched arms, arms behind back, -hands on hips, hand on own face, -hugging own legs, hand in own hair, -holding flowers,等等
    • -
    • 配饰:gold accessories, white lightsaber, -tail, scarf, armor headdress, -ribbon, neck ribbon, hair ribbon, -halo, necklace, wings, -tassel, earrings, wizard hat, -headphone, -red swordfloral print, 等等
    • -
    • 服装:detailed mechanical armor, -detailed organdie dress, skyblue dress, -princess dress with delicate gold metal decorations, -witch dress, white thin detailed cloak, -summer long skirt, angel suit, -very long dress, -translucent fluttering dress with lacekimonotrench coat, -cheongsampettiskirt, -lolita gothicpleated skirt, 等等
    • -
    • 手套/袖子:detailed white gloves, -elbow gloves, sleeveless, -wide sleeves, large top sleeves, 等等
    • -
    • 鞋子:barefoot, thigh boots, -getauwabaki, 等等
    • -
    -

    建议平时可以多看别人的关键词然后记录下来。

    -

    使用不同的组合并加入不同的权重可以产生你想要的效果,比如下面的例子:

    -

    -

    除了角色本身的细节之外,你还可以指定背景,比如没有背景no background, -以龙为背景dragon background/loong background,以森林为背景forest background,大火为背景fire background/burning background,如下(不同的背景需要不同的权重):

    -

    -

    特别说明:如果你想要生成人物设计图(即三视图),你可以用reference sheet,并同时修改分辨率

    -

    -

    画面风格

    -

    顾名思义,就是需要选择图片的美术风格,下面有一些供参考的风格及其关键词选择:

    -
      -
    • 写实:realistic, photorealistic
    • -
    • 素描:sketch, rough sketch, -pencil sketch
    • -
    • 描边:outline
    • -
    • 线稿:lineart
    • -
    • 像素:pixel art
    • -
    • 平涂:flat color
    • -
    • 平面着色:flat shading(注意和平涂不一样,下有例子)
    • -
    • 水彩:watercolor (medium), -watercolor pencil (medium)
    • -
    • 单色:monochrome, spot color, -greyscale
    • -
    • 浮世绘:ukiyo-e
    • -
    • 苏维埃海报:soviet poster
    • -
    • 封面:cover art
    • -
    • 漫画书:comic book
    • -
    • 动漫:comic
    • -
    • Q版:chibi
    • -
    • 复古艺术:retro artstyle
    • -
    • 新艺术派:art nouveau
    • -
    • 年代:1970s, 1980s, -1990s
    • -
    • 赛博朋克:cyberpunk
    • -
    • 狂野风:wildstyle
    • -
    • 科幻:sci-fi
    • -
    • 奇幻:fantasy
    • -
    • 传统日本风格:traditional Japanese art
    • -
    -

    建议把风格使用至少三个大括号{{{}}}甚至更多包裹起来进行强调,确保可以生成正确的风格图。

    -

    你可以选择同一个风格里的多个关键词,或者结合不同的风格。比如你可以融合像素风pixel art和奇幻风fantasy形成像素奇幻风。但最好不要融合超过两种风格,否则生成结果未知。

    -

    下面是一些例子(依次是{{{flat color}}}, -{{{flat shading}}}, -{{{soviet poster}}}, {{{flat color}}}, -{{{outline}}}, {{{sketch}}}, -{{{{{traditional media}}}}}, -{{{ukiyo-e}}}, {{{outline}}}, -art nouveau, -{{{pixel art}}}, {{fantasy}}, -{{{black and white}}}, {outline}, {flat shading}, {flat color}, {concept art}, {lines}, -{{{{wildstyle}}}}, {flat color}, -{{{{{{{{wildstyle}}}}}}}}, {cyberpunk}, {{{outline}}}, -{traditional japanese art}, {anime}, {fantasy}):

    -

    除了显式指定美术风格之外,你还可以指定艺术家和作品让画面偏向某种特定的风格。但是和MJ不同的是,NovelAI并不像MJ那样非常依赖艺术家,一般不加,或者最多只加一个艺术家或作品即可。比如下面我分别指定了ghibili, -Hayao Miyazaki, -breath of the wilddark soul

    -

    -

    可以看到,加入艺术家和作品并没有想象中的那样有效,所以推荐不加。

    -

    注:当然如果你非常熟悉某个艺术家,那加入艺术家也是可以的,但一般来说需要给艺术家比较强的权重模型才会生成比较相似的风格,而且也不是所有艺术家都支持的,还是建议多做尝试。这个表是已记录的一些艺术家,可以根据风格先在谷歌上搜索,然后自行尝试。

    -

    光影设置

    -

    这里的光影设置和MJ是一样的,比如下面的光影: -背光backlight, 电影打光cinematic lighting, -柔和光soft lighting, -体积光volumetric lighting, -点光(聚光灯)spotlight, 圣光holy light, -日光sunlight, 月光moonlight, -波光粼粼glistening light of waves, -金色光golden light

    -

    -

    颜色设置

    -

    颜色没太多好说的,如果你想要画面整体偏某种颜色,直接加入颜色关键词即可。 -但更好的方法是直接指定某个物体的颜色,比如red eyes, -cyan hair,以实现精准控制。有时候需要加大物体的权重,避免这个颜色控制了其他部件。

    -

    其他意象

    -

    其他意象词一般用来增加前景和背景的丰富度,以及人物身上的细节,比如下面的一些关键词: -羽毛feather, 自然nature, -叶子leaves, 阳光sunlight, -河流river, 水晶crystal, -棱镜prism, 冰ice, 齿轮gear, -流动flowing, 浮动floating, -照射shine, 影子shadow, 时钟clock, -装饰ornament/decoration/frills, 火焰flames, -火花sparks, 光晕flares, -核爆nuclear explosion, 闪电lightning, -飞溅的血splashing blood, -飞舞的花瓣flying petals, 微风breeze, -风wind, 雨rain, 云clouds, -烟smoke, 雾mist, 纱yarn, -沙sand, 星尘stardust, -银河milkyway, 旋转swirling, -头骨skull, 骨骼skeleton, -几何geometric, 立方体cubic, -多边形polygon

    -

    总之你可以添加任何你想要在图片中出现的意象词,但要注意和整体画面内容的搭配。你可以通过调整词的权重控制意象出现的频率。

    -

    还是建议找一些相关的参考图和别人给的关键词,多做尝试。

    -

    负面关键词

    -

    负面关键词是你不想让它出现在图片中的内容,填入Undesired -Content中即可。虽然是根据你不想要的内容去选择负面关键词,但是也要一些通用的负面关键词。下面是默认添加的关键词,其他关键词根据需求自行添加: -{{{ugly}}},{{{duplicate}}},{{morbid}},{{mutilated}},{{{tranny}}},{breast},mutated hands,{{{poorly drawn hands}}},{{bad anatomy}},{{{bad proportions}}},extra limbs,cloned face,{{{disfigured}}},{{{more than 2 nipples}}},{{{{missing arms}}}},{{{extra legs}}},{{{{{fused fingers}}}}},{{{{{too many fingers}}}}},{{{unclear eyes}}},{{{fused hands}}},{{{fused leg}}},{{{bad feet}}},nsfw,lowers,bad anatomy,bad hands,text,error,missing fingers,extra digit,fewer digits,cropped,worst quality,low quality,normal quality,jpeg artifacts,signature,watermark,username,blurry,bad

    -

    实战操作

    -

    下面还是给几个实战操作的例子。

    -

    和服风的设计稿

    -

    第一个例子,我们想要一个三视图设计稿,主角是一个穿着和服的传统日本女孩,盘发、头上有红色的花、化妆、精致的手镯、漂亮的印花。因为是设计图,所以要调整下分辨率,用默认的Landscape就好了。因此,我用的Prompt是:{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, beautiful, 8K, small breasts, full body, solo, a japanese girl, {{{{{reference sheet}}}}}, flat color, concept art, brown hair, red flower in hair, {updo}, smile, beautiful face, beautiful makeup, delicate bracelet, {beautiful kimono with intricate floral print}

    -

    下面是生成的一些图(尝试了不同的Steps和Scale,Steps大则细节更丰富,Scale越小则多样性越强,但建议Steps<=40, -Scale>=6。最后一张图给和服加了blue):

    -

    可以看到,人物的手和脚是重灾区,但其他地方还是可以的。另外,活用Enhance能够极大地修复手的问题,关键在于Strength的参数不要太大(0.3左右),Noise设置为0或者非常小。

    -

    机甲少女全身照

    -

    第二个例子,我想要画一个机甲少女的全身照,有着冷酷的表情、红色的眼睛、脸上有纹身、拿着一把红色的刀,我并不太想指定其他过多的元素,但是想要图片的背景是弥漫着硝烟的战场,空中也飞舞着火星。因此,我使用的Prompt是{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, beautiful, 8K, small breasts, full body, depth of field, solo, a mechanical girl, detailed mechanical armor, detailed mechanical body} {holding a red sword}, disheveled hair, short hair, cold stares, half-closed eyes, {{dark red eyes}}, gradient eyes, ruined battlefield background, {detailed background}, burning buildings, splashing sparks, flames, holy light

    -

    下面是生成的图(使用了不同的Steps和Scale,最后四幅图修改了机甲的颜色): -

    -

    狂野赛博艺术图

    -

    作为我们的第三个例子,我们将探索wildstyle这个风格与其他关键词的组合会得到怎样的效果。wildstyle意味着丰富的色彩,尤其是大面积深色的应用。我们将融入赛博朋克的元素,并搭配不同的关键词看AI会给出我们怎样的结果。我使用的基础Prompt是{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, {{{{wildstyle}}}}, beautiful, small breasts, solo, {{a girl}}, cyberpunk

    -

    下面是生成的图(每张图都调整了wildstyle的权重,附加Prompt依次是, -{flat color}, -{{flat color}}, {colorful}, -{{flat color}}, {{outline}}, -sci-fi, -{flat color}, beautiful kimono with cherry floral print, -{flat color}, watercolor (medium), -{{{pixel art}}}):

    -

    结果发现,wildstyleflat color, -outline等关键词搭配效果很好。

    -

    华丽高贵女神范

    -

    第四个例子,我想要得到一个华丽高贵的女神,被白色的花簇拥着,穿着华丽的白色礼服,点缀金色丝边,戴着项链、手镯、花环,蓝色的发光的眼睛。分别尝试不同的构图,即特写、半身、全身,和不同的风格,对背景不做要求。采用的Prompt是{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, beautiful, 8K, very detailed, small breasts, [composition], [style], solo, a royal goddess, disheveled hair, detailed blue eyes, gradient eyes, glowing eyes, vibrant colorful garland, gorgeous princess dress with delicate gold metal decorations, {{white flower decorations}}, {{surrounded by flowers}}, exquisite bracelet, exquisite necklace, bare foot, {{flowing flowers}}, {{liquid}}。其中,[composition]填写构图,[style]填写风格。

    -

    下面是生成的一些图片(前两张是portrait, -第三四张是head and shoulder shot, -最后四张是full body;风格第一张是cartoon, anime, -第二张realistic, 第三张cartoon, anime, -第四张fantasy, flat shading, -第五张flat color, geometric, cubic, -第六张cartoon, anime, -第七张flat color, flowing,第八张dark magic, Cthulhu): -

    -

    使用建议

    -
      -
    • 重视分辨率!道理和MJ一样,即图片的分辨率要和想要生成的内容匹配,不再赘述,详细请看MJ页面。
    • -
    • 尝试权重!NovelAI对关键词加权是非常重要的一个操作,有时候你写的关键词没有生效极有可能就是关键词的权重不够导致的,这时候多尝试嵌套几层大括号{{{}}}。一般来说,对
    • -
    • 叠通用BUFF!上面给出了最基础的通用BUFF,但是对某些类型的图来说,还有一些额外的BUFF可以叠,建议多看看对不同的美术风格、画面内容,别人怎么叠BUFF的,总结一套属于自己的BUFF表。之后有时间我也会帮大家总结。
    • -
    • 加入风格!加入风格(包括与风格有关的关键词)会有助于生成你想要的内容,但注意与MJ不同,NovelAI对艺术家的支持并不好,所以尽量不要用艺术家。加入flat shadingflat color偶尔会有奇效,其他的一些意向词比如flowing, -geometric也能创造很好的风格。
    • -
    • 多尝试参数!NovelAI的参数虽然没有MJ多,但是调试更加困难。一般来说用Steps=28, -Scale=7的默认参数能够得到还不错的效果,如果你发现怎么改关键词都不生效的话,果断尝试修改参数吧(当然也有可能是NovelAI的训练集中没有你输入的内容,弃疗吧)!
    • -
    -

    参考资料

    -

    NovelAI官方文档
    -NovelAI图像生成注意事项
    -关键词参考
    -元素法典——Novel AI -元素魔法全收录(第一卷)

    -]]>
    - - 随笔 - - - 随笔 - 计算机 - 游戏 - 工具 - 绘画 - 深度学习 - -
    - - The Jittering Issue with Damping in Cinemachine and How to Tackle it - /2023/07/08/18/22/ - If you are familiar with Cinemachine. you probably know there is a -knotty problem with Cinemachine' damping if you are using -Framing Transposer or some other components to track a -follow point. That is, the camera jitters with damping enabled under -unstable frame rate. The more unstable frame rate is, the more heavily -camera will jitter. This post will discuss this phenomenon and proposes -a workaround to solve this issue.

    - -

    Camera jitters with -damping in Cinemachine

    -

    Unity's Cinemachine has a notoriously severe problem that may cause -the follow object to seemingly jitter when you are using the -Framing Transposer component with damping enabled.

    -

    To show this, I did a simple experiment. I created a new blank scene -and spawned a new attached with the following script:

    -
    public class CubeMove : MonoBehaviour
    {
    public float speed;
    public int fps;

    public float CurrentSpeed
    {
    get { return currentSpeed; }
    }

    private float elapsedTime = 0.0f;
    private float currentSpeed;

    void Start()
    {
    if (fps != 0)
    {
    Application.targetFrameRate = fps;
    }

    currentSpeed = speed;
    }

    void Update()
    {
    elapsedTime += Time.deltaTime;

    if (elapsedTime >= 5.0f)
    {
    if (currentSpeed > 0.0f)
    {
    currentSpeed = 0.0f;
    }
    else
    {
    currentSpeed = speed;
    }

    elapsedTime = 0.0f;
    }

    transform.position += new Vector3(1, 0, 0) * currentSpeed * Time.deltaTime;

    }
    }
    -

    This script moves the cube for 5 seconds and then keeps it steady for -another 5 seconds and continues moving. The move speed as -well as the fps (frames per second) can be set for test -under different conditions.

    -

    A new virtual camera is then created with a -Framing Transposer component following this cube. A default -damping of 0.2 is used.

    -

    Here is result with speed is 100 and fps is -0 (when set to 0, the real fps is determined by Unity, may but -unstable).

    -

    -

    The jitters are very clear. You can also notice that the frame rate -(presented in the Statistics panel) is very unstable, and we will know -soon it is the unstable fps that results in camera jitters.

    -

    Cinemachine proposes a workaround to alleviate this problem, that is, -to use the revised version of damping where they sub-divide each frame -and simulates damping in the consecutive series of sub-frames. To enable -this functionality, go to Edit -> Project Settings -> Player -> -Script Compilation and add the -CINEMACHINE_EXPERIMENTAL_DAMPING marco to it.

    -

    -

    OKay, now we have enabled the new damping algorithm and let's see how -it will mitigate the jittering issue. Here is result with the same -setting we used in our previous experiment, i.e., speed is -100 and fps is 0.

    -

    -

    It is astonishing to see the jittering issue becomes even more -severe. I conjecture that the variance of fps will significantly amplify -camera jitters when this feature is enabled. In other words, the -experimental damping algorithm responds to the variance of fps in a -NON-linear way: when the variance is small, the experiment damping will -reduce the gaps of camera location between contiguous frames; but when -the variance is large, it will enlarge the gaps, leading to unacceptable -jittering. (Note: I did not validate this conjecture. If you are -interested, just review the code and test it yourself.)

    -

    What about the expected result if fps is stable? Let's take more -experiments!

    -

    Here is result with speed is 100 and fps is -120 (very high fps, which is usually prohibitive in shipped games).

    -

    -

    Very steady camera! What about setting fps to 60? Here -is the result.

    -

    -

    An fps of 60 performs equally well with 120, which is anticipated as -fps is stable. Okay, let's try a final experiment where fps is set at an -extreme value of 20.

    -

    -

    Even a low fps of 20 makes our camera stable, only if fps itself is -stable.

    -

    Now we can conclude that it is the instability of fps that induces -camera jitters, regardless of the exact value of fps. But, why?

    -

    Why camera jitters

    -

    Before answering this question, let us first take a look at the -source of damping implemented in Cinemachine.

    -
    public static float Damp(float initial, float dampTime, float deltaTime)
    {
    if (dampTime < Epsilon || Mathf.Abs(initial) < Epsilon)
    return initial;
    if (deltaTime < Epsilon)
    return 0;

    public const float kNegligibleResidual = 0.01f;
    const float kLogNegligibleResidual = -4.605170186f; // == math.Log(kNegligibleResidual=0.01f);
    float k = -kLogNegligibleResidual / dampTime; //DecayConstant(dampTime, kNegligibleResidual);

    #if CINEMACHINE_EXPERIMENTAL_DAMPING
    // Try to reduce damage caused by frametime variability
    float step = Time.fixedDeltaTime;
    if (deltaTime != step)
    step /= 5;
    int numSteps = Mathf.FloorToInt(deltaTime / step);
    float vel = initial * step / deltaTime;
    float decayConstant = Mathf.Exp(-k * step);
    float r = 0;
    for (int i = 0; i < numSteps; ++i)
    r = (r + vel) * decayConstant;
    float d = deltaTime - (step * numSteps);
    if (d > Epsilon)
    r = Mathf.Lerp(r, (r + vel) * decayConstant, d / step);
    return initial - r;
    #else
    return initial * (1 - Mathf.Exp(-k * deltaTime));
    #endif
    }
    -

    Translating into mathematics, we have:

    -

    -

    where is the damp time -parameter and the elapsed -time in this frame. This equation decays the input , the distance for the -camera to go to the desired position, by an exponential factor . If , the residual will be , meaning that at -this frame, the camera will traverse 99% of the desired distance to go, -only remaining 1% amount for future frames.

    -

    OK, let's assume we've placed a cube in the origin and it moves along -the x-axis at a fixed speed, say, -m/s. A camera is placed to track the cube with damping where damp time -. Let's further denote the -delta time for each frame by , where is the -th -frame.

    -

    Having all variables fully prepared, we can then simulate the object -movement and camera track process.

    -

    In the beginning of 0-th frame, the camera and the cube are both at -the origin, i.e., (0, 0, 0). As the cube only moves along x-axis, we can -emit the y and z dimensions and use a one-dimensional coordiante to -represent cube and camera positions.

    -

    At the 1-th frame, the cube moves to , the -distance the camera traverses is , and the residual is . We set for simplicity.

    -

    At the 2-th frame, the cube moves to , the distance the camera traverses is -, and the residual is .

    -

    At the k-th frame, we have , -, and -.

    -

    Without loss of generality, we can set . The following sections will use this -settings unless otherwise stated.

    -

    For different combinations of , may have different results. Let's dive into and see how it influences -the results.

    -

    Case 1: Stable FPS, -all are equal

    -

    When all are -equal, say , our equations -reduce to:

    -

    -

    apparently has a -limitation of when -since . This -explains why a camera with damping always has a maximum distance to its -following target. There maximum distance, also the supremum, is exactly -. When is larger, will be larger, implying the -maximum distance between the camera and its following target will be -larger.

    -

    What if is -mutable? In this case, we can assume there exists an upper bound such that all satisty . Then we are -able to derive the same conclusion.

    -

    Another question is, why camera does not jitter when FPS is stable? -We turn to examine the sign of :

    -

    -

    Therefore, when FPS is stable, is always larger than , and jitter will never -happen.

    -

    Case 2: Unstable FPS, vary

    -

    When FPS is unstable, where may mutate, how will the camera move in response to its -following target? We can still examine the sign of , but in another -way:

    -

    -

    This equation uncovers why camera jitters happen with unstable FPS. -The residual at the k-th frame is essentially an interpolation -between the following target's current position increment and the last frame's -negative residual , where -the interpolation strength is the decaying factor . -As both and are fixed, a change in will incline the resulting -residual to different ends, -either or .

    -

    In our simplified case in which the target moves at a fixed speed in -the direction of x-axis, will always be positive (though its magnitude can vary) and - will always be negative. -A mutating thus has -a chance to alter the sign of , which further brings -about camera jitters.

    -

    So when will camera jitter? From the above equation, we know that -camera will jitter when the sign of consistently changes -over time, i.e., the value of oscillates around zero. -Let's make it equal to zero and see what we can find then.

    -

    -

    This equation tells us when is near , camera will have a large chance to jitter. This -motivates us to improve damping by filtering out the occasions where - is very close to -.

    -

    What about going deeper? We can treat as variable, and all other -as constants. This abstraction gives us a function of :

    -

    -

    Taking the derivative of , -we know that is monotonically -decreasing when and monotonically increasing when , and . Hence, to make the sign of mutable, must be positive and the -minimum of must be -negative.

    -

    The minimum of can be -easily computed:

    -

    -

    The last inequality holds because .

    -

    -

    This reveals the fact that: when , a variant is likely to cause to change its sign, -thus resulting in camera jitters. Suppose is large enough, so then -the k-th residual gets -smaller than while is positive. A smaller pushes to become smaller for the next frame, -which further pushes the root of the function to become larger. In this -case, even with the same delta time, will have a larger chance wo -fall in the negative area, i.e., is more likely to be less than the root.

    -

    -

    Solutions

    -

    Solution 1: imposing an -invalid range

    -

    Based on what we've discussed so far, we can immediately come up with -a simple solution: enforce to be if they are very close. That is to say, we use a -small value , if , we just set to .

    -

    Note that can be zero or negative. If this is the case, we keep the -original without -doing anything. Besides, you should be aware that here is not the time this -frame actually takes, instead, it is just the duration used to calculate -damping.

    -

    Let us explain it more quantitatively. Suppose , -where . -Then according to our algorithm. We then -plug into the original -expression of :

    -

    -

    This demonstrates that now the camera lags behind its following -target more than the previous frame since the residual is larger. After -substituting -with , would be zero, meaning -that the camera now keeps the same frame as last frame. Camera does not -jitter.

    -

    Here comes the question: what if the following target slows down, or -stops, or even turns back to the opposite direction and the camera still -remains the same residual to it?

    -

    It is quite a good question. But if we look carefully at the function -of , we will find this -situation will never happen. Let's rewrite here:

    -

    -

    This time, we do not constrain the value of , but at last frame, it's positive.

    -

    When gets smaller but still -positive, we observe the function gradually shifts leftwards, pushing -the root towards zero. This implies that the area gets -contracted and the probability of remaining the same residual gets -smaller.

    -

    -

    When is zero where the -following target stops, the current residual can be readily calculated -as , which closes the distance gap between the camera -of the following target. The ratio, which is calculated as , would be -devided by zero, outputting an infinite value.

    -

    When is negative, will be negative. The -ratio -now becomes negative, also beyond the range of .

    -

    We can implement this algorithm in less than 100 lines of code. You -should modify three files in the official Cinemachine source code -directory.

    -

    First is Predictor.cs. Add a ImprovedDamp -function:

    -
    public static float ImprovedDamp(float initial, float dampTime, float deltaTime, float bonus)
    {

    if (dampTime < Epsilon || Mathf.Abs(initial) < Epsilon)
    return initial;
    if (deltaTime < Epsilon)
    return 0;

    float tolerance = 0.05f;

    float alpha = Mathf.Log(bonus) * dampTime / kLogNegligibleResidual;
    float ratio = deltaTime / alpha;

    if (ratio <= 1.0f + tolerance && ratio >= 1.0f - tolerance)
    {
    deltaTime = alpha;
    }

    float k = -kLogNegligibleResidual / dampTime; //DecayConstant(dampTime, kNegligibleResidual);

    return initial * (1 - Mathf.Exp(-k * deltaTime));
    }
    -

    The input bonus is . Parameter tolerance is what you should set -as we've introduced -above.

    -

    In file CinemachineVirtualCameraBase.cs, add a new -function ImprovedDetachedFollowTargetDamp:

    -
    public Vector3 ImprovedDetachedFollowTargetDamp(Vector3 initial, Vector3 dampTime, float deltaTime)
    {
    GameObject go = GameObject.Find("Cube"); // Hard find our following target of interest, you should not do like this!
    Vector3 deltaDistance = new Vector3(100, 0, 0) * deltaTime; // Hard set the velocity, you should not do like this!
    Vector3 residual = initial - deltaDistance;
    Vector3 bonus =
    new Vector3(residual.x / (residual.x + deltaDistance.x + 1e-7f),
    residual.y / (residual.y + deltaDistance.y + 1e-7f),
    residual.z / (residual.z + deltaDistance.z + 1e-7f));

    dampTime = Vector3.Lerp(Vector3.Max(Vector3.one, dampTime), dampTime, FollowTargetAttachment);
    deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
    return Damper.ImprovedDamp(initial, dampTime, deltaTime, bonus);
    }
    -

    This piece of code is very informal, and you should never write your -code like this. The purpose of this function is to get and . I reckon the correct -way to do this is to create a new (or two) variable in the -CinemachineVirtualCameraBase class and update it in each -tick. The code presented here is only for demonstration.

    -

    In file CinemachineFramingTransposer.cs, change the -called function for damping:

    -
    cameraOffset = VirtualCamera.ImprovedDetachedFollowTargetDamp(  // Original is DetachedFollowTargetDamp
    cameraOffset, new Vector3(m_XDamping, m_YDamping, m_ZDamping), deltaTime);
    -

    You could also try other components, not just -FramingTransposer here.

    -

    With the default tolerance=0.05, the result is shown -below.

    -

    -

    Camera jitters disappear. Note that the general fps is quite high -(around 400~500). This is because our scene is quite simple, containing -only a cube and a camera. In order to simulate a more real runtime game -situation, I place 20k cubes in the scene and now the fps is around 30, -but still unstable.

    -

    Below is the result when using the raw damping algorithm.

    -

    -

    Camera jitters more severely due to a generally lower FPS. What about -using the improved damping algorithm? Here is result with -tolerance=0.05.

    -

    -

    Just as expected, camera jitters do not show up. Let's try different -tolerances. How will a small tolerance help -alleviate jitters? Below is the result with -tolerance=0.01.

    -

    -

    Camera jitters occur again! This suggests that an excessively small -value cannot fully filter out actions that can lead to camera jitters. -Let's try our final experiment with tolerance=0.1.

    -

    -

    Camera jitters disappear, but the camera motion seems a little stiff. -These experiments show that an appropriate value of -tolerance to ensure the smoothness and robustness of the -camera.

    -

    Solution 2: adding low-pass -filter

    -

    Our improved samping perfectly solves camera jitters under unstable -fps, but it looks very stiff when it reaches the boundary of max damping -distance. Can we make it more realistic so that the object won't just -look stolid? Yes of course, we can add low-pass filter, or moving -average to our improved damping to achieve more smooth results.

    -

    Recall the algorithm of the improved damping: if , we just set to . -Instead of hard setting to , we introduce , the smoothed version -of the original delta residual . If holds, we calculate as an average of - and :

    -

    -

    which can be iterated through a recursive form:

    -

    -

    Note that gets -updated if and only if holds, -i.e., when the camera lies in the unstable area. The -use of is similar to -low-pass filters in the sense that they all filter out high-frequency -signals.

    -

    Below is s sample code implementation in file -Predictor.cs:

    -
    CurrentResidual = initial * Mathf.Exp(-k * deltaTime);
    ResidualDifference = CurrentResidual - PreviousRedisual;

    float result;

    float tolerance = 0.1f;
    float alpha = Mathf.Log(bonus) * dampTime / kLogNegligibleResidual;
    float ratio = deltaTime / alpha;

    if (ratio <= 1.0f + tolerance && ratio >= 1.0f - tolerance)
    {
    float beta = 0.001f;
    CachedDeltaResidual = (1 - beta) * CachedDeltaResidual + beta * ResidualDifference;
    result = initial - (CachedDeltaResidual + PreviousRedisual);
    }
    else
    {
    result = initial - CurrentResidual;
    }
    -

    Let's try it out! With damping time and , we can achieve the -following damping result with low-pass filter:

    -

    -

    Now the camera looks much more smooth and, flexible. What about -trying a smaller damp time, say, ? Here is the result:

    -

    -

    The result is ok but sometimes it's still jittering. It is because a -smaller leads to a larger and thus a larger chance to -cause jitters. To solve this issue, we can set a larger tolerance , or we can have a smaller -. We adopt a of and see how it performs.

    -

    -

    The camera now becomes smooth again.

    -

    We can measure this sort of instability more quantitatively. Below is -a graph plotting -during five seconds of camera trace with damp time . The original curve (in blue) -oscillates over time due to an instability of fps. The improved damping -method eliminates all the oscillation and makes the curve absolutely -plain. Empowered by low-pass filter, the curve becomes smooth without -loss of stability.

    -

    -

    Below is the graph with damp time . As can be seen, even with improved -damping, the camera still has a chance to vibrate, and the original -curve, oscillates much more intensely than with . Employing the low-pass filter -gives a much smoother and stable camera motion curve, as expected.

    -

    -

    Speaking of this, why can't we just soften our -improved damping assignment to where is a function of - parameterized by .

    -

    Assume -and , we first calculate ; -then calculate ; -last, we have . -For , we obtain . is a parameter controlling how fast the -value of grows from - to . The larger is, the larger mass will be -concentrated on the -side.

    -

    Below is the result with -and :

    -

    -

    Not bad! The soft version of improved damping really makes the camere -smoother and less stiff than the vanilla improved damping algorithm. The -follow plot also shows that with soft parameterization, the camera -trajectory is much more natural with neglectable amount of -oscillation.

    -

    -

    We also compare it to different and . Beolow is the result with and .

    -

    -

    A larger makes the camera more -stiff, but is still better than the original improved damping -algorithm.

    -

    Below is the result with -and .

    -

    -

    is less effective as the -magnitude of attenuation it applies to is not enough to compensate -for the osciallation the unstable fps brings about.

    -

    Let's try another damp time. The result with and shows as follows.

    -

    -

    When , the oscillation is -more severe, as we've already stated above. What about ?

    -

    -

    Better, but still not sufficient to mitigate the oscillation. Let's -try .

    -

    -

    Almost perfect. We can conclude that a smaller needs a larger to offset the intense jitters resulted -from unstable fps. Besides, you can combine the soft improved damping -method and low-pass filters to achieve a smoother transition.

    -

    Solution 3: continuous -residual

    -

    Okay, let's forget all aforementioned solutions and revisit our -residual update formula at the very beginning:

    -

    -

    Reformulate thie equation to the following form:

    -

    -

    where is the speed of the -camera's follow target, and is a more generalized form of the damping function . -Theoretically, it can represent any function of interest.

    -

    Now, regarding as a function -with respect to , we can seek to -obtain its derivative:

    -

    -

    We use the equality -because when you plug -into , you will get , implying .

    -

    What about derivatives with higher orders? We can calculate the -second-order derivative as follows:

    -

    -

    It is a nice form which bridges the first-order derivative and the second-order derivative -. In fact, for any --th order derivative, it can be -recursively calculated as:

    -

    -

    Having all these derivatives, we can then expand using Taylor series and -calculate the difference to :

    -

    -

    Note that if we are still choosing as out -damping function , the -derivative of it with respect to will be and the value at zero will be .

    -

    In practice, we first decide how many terms in the coefficient term -should be taken in, and then sum them up and multiply with the velocity -term, the result of which is denoted by . The residual at the current -frame, can be readily computed as . To save -computation, we can first cache -up to a threshold, say , and -then using the formula of geometric series to efficiently compute the -coefficient sum.

    -

    To estimate its error, we use the Lagrange remainder:

    -

    -

    Decompose it:

    -

    -

    where -and as we assumed. We can -see that the error is asymptotically negligible with respect to , especially when is small.

    -

    Recall that -where and - is the damp time. If is large, say 0.5 or even 1.0, the -value of will be -somewhat small so that a decent precision can be reached within few -steps of expansion, i.e., a small -say 2 or 3 could satisfy camera stability. However, if is small, say 0.2 or 0.1 or even -smaller, the value of -would grow larger, and then a larger might be needed to reach our expected -precision. This is in accordance with our observation that a smaller - generally leads to a more -unstable camera trajectory. We will show this soon.

    -

    Let's first try and . Recall that is the maximum order of derivatives we -use to approximate the residual difference. means that we only use in the coefficient term. Here is -the result:

    -

    -

    Looks nice! What about setting ?

    -

    -

    Not much difference, but a little bit smoother. Let's try respectively with and . First comes .

    -

    -

    It's okay but it seems too fast when the cube comes back to -stillness. How about ?

    -

    -

    Now everything gets worked! Next, let's set smaller, which generally won't be used -in actual gameplay but as a test it's worth a try. We set and try different to see how they influence our camera -trajectory.

    -

    Here is the result with :

    -

    -

    Okay... a total mess. Try :

    -

    -

    Unfortunately, the cube always stays behind the camera. Now :

    -

    -

    Forget about it ... Let's try :

    -

    -

    Things are getting better! At least it does not shake anymore and -begins to stay at the right position. I bet is better:

    -

    -

    It's close! Last, we try :

    -

    -

    Finally, the camera disposes everything well. As we can see from the -process, a small requires a large - to reach the minimum acceptable -precision. I hope you never have the chance to use such a small , and if it happens, cache enough orders -of derivatives or it would be prohibitively expensive to compute at -runtime.

    -

    To further understand why this method solves the jittering issue, we -take a deeper look at the expression of derived above. -This is an ODE and we solve it out (proof left to the readers):

    -

    -

    Here I've expanded as . We cannot -directly use this explicit expression to calculate because there is no -correct time stamp when game is running. What we only have -is the previous frame's residual and the elapsed time at this frame -. And as the velocity may change over time, a closed-form of - cannor serve our purpose well. -We can only incrementally calculate camera residuals at each frame based -on what we currently have.

    -

    is a monotonic increasing -function, and of course, it's continuous. The continuity ensures that -the camera trajectory is always smooth and never jitters, if fps is -sufficiently high (over one thousand I suppose?).

    -

    For the original discrete residual, its velocity is:

    -

    -

    where is from -Lagrange's Mean Value Theorem. Note that I add a tilde symbol over to distinguish it from the one from the -continuos version above.

    -

    This is another ODE. We can solve it out (proof left to the -readers):

    -

    -

    Note that we solve the ODE with respect , the increment time rather than -the absolute time . So, we -introduce an initial value to control what the -initial value of residual is at this frame, is now the elapsed time for this frame -satisfying and .

    -

    The following graph shows that how the function changes with -different and . It can be -noticed that this function is very sensitive to the input , the elapsed time at this frame. A -small change of the input would significantly change the sign of , thus causing camera jitters. -We also notice that a smaller , -derived from a smaller , pushes -the function leftwards, which also makes it more vulnerable to -inputs.

    -

    -

    Below is a comparison between five damping algorithms introduced in -this article, including the original damping. Damp time is set to 0.2. We observe significant -stability improvement when using any of the four proposed damping -algorithms. You should be careful when choosing the most appropriate -algorithm because the situation on which you intend to use damping. How -unstable is your fps? What is the damp time ? How is the tracked object moving? You -should experiment with these algorithms and choose the one that best -suits your needs.

    -

    -]]>
    - - 游戏 - 相机 - - - 数学 - 随笔 - 计算机 - 相机 - Unity - Cinemachine - Damping - -
    - - Motion Matching -- 概念与发展 - /2022/03/27/08/38/ - 这是我在组内分享的一次关于Motion -Matching基本知识的介绍,放在此备份。

    - -

    Motion -Matching - 概念与发展

    -]]>
    - - 游戏 - 动画 - - - 数学 - 随笔 - 计算机 - 游戏 - 动画 - 深度学习 - 机器学习 - -
    - - A Brief Note on Version Control and Project Organization - /2022/11/21/16/03/ - This is a brief note about the e-book Version -Control and Project Organization Best Practice Guide present at -Unite 2022. In this book, we can learn fundamental concepts of version -control and some best practices for organizing a Unity project. If you -are new to Unity, or you prepare to set up a larger scale Unity project, -this may be what you need.

    - -

    Foundational concepts

    - -

    Best practices -for organizing a Unity project

    - -

    Version control systems

    - -

    -

    Settings up -Unity to work with version control

    - -

    Best practices for version -control

    -

    Some suggestions you may need to make teamwork more efficient:

    - -

    The biggest takeaway is the importance of clear team communication. -As a team, you need to agree on your guidelines

    -]]>
    - - 随笔 - - - 随笔 - 项目管理 - -
    - - Which Splines Do You Need? A Comprehensive Dive into Common Splines - /2023/05/03/18/22/ - This post introduces some widely used splines in computer games -including Bézier curves, cubic Hermite splines, Catmull-Rom splines, -B-splines, Kochanek–Bartels splines, etc. We show these splines can be -bridged through re-formulation. Then, we focus on the extension and -generalization of Bézier curves and introduce mathematical methods to -create dynamic smooth splines. Last, we develop a simple Editor in -Unreal Engine to enable easy creation of splines under different -constraints and conditions.

    - -

    Common Splines

    -

    Bézier Curve

    -

    The most typical and widely-used spline might be Bézier curves. -Bézier curve leverages a set of control points to define a smooth and -continuous curve generated by interpolation between these control -points. Using the De Casteljau's algorithm,1 we -can easily express a Bézier curve in terms of a sum of Bernstein -polynomials:

    -

    -

    When there are four control points, the generated curve is called -cubic Bézier curve. A cubic Bézier curve can be expanded as:

    -

    -

    The derivative of an -th order -curve is:

    -

    -

    Similarly, we can obtain the second-order derivative:

    -

    -

    We will use these results later soon.

    -

    Degree elevation

    -

    Suppose is an --th order Bézier curve and we want -to elevate its degree to . We -can do this via the following process:

    -

    -

    Note that when , , and when -, . So - and can be arbitrary. We -simply set them to zero.

    -

    Composite Bézier curves

    -

    A composite Bézier curve is a series of Bézier curves joined end to -end where the first point of one curve coincides with the last point of -the previous curve. If a Bézier curve is composite, we say it's continuous.

    -

    However, sometimes we want higher degrees of continuity than at the joint of Bézier -curves (note that individual curves are within their own -inteval, and the discontinuity only happens at the meetings of -consecutive curves).

    -

    Given two Bézier curves -and , -we can define different degrees of continuity at :

    - -

    If a curve is , then -it must be . If a curve -is , then -it must be .

    -

    Rational Bézier curves

    -

    -

    Approximating circular arcs

    -

    A cubic Bézier curve can be used to approximate a circular arc. Let's -first start with a simple case: the arc starts at point and ends at points , placed at equal distances -above and below the -axis in the -first quadrant, spanning an arc of angle . The radius is .

    -

    Assume the additional control points are and , and their indices are -respectively and . Note that , or .

    -

    According to the expanded Bézier curve expression:

    -

    -

    we have , -which gives:

    -

    -

    On the other hand, according to the derivative of a cubic Bézier -curve , -we know the derivative at is -. It -is equal to the tangent at multiplied by some coefficient -:

    -

    -

    Now we've obtained the control points and .

    -

    What about and are not symmetrical? Assume -the angle of is and the angle spanned by the arc -is , where the end point is -. We can first rotate -both and by . This -now becomes the case discussed above. We can calculate the index of - after being -rotated:

    -

    -

    Now we can follow the aforementioned process to calculate the control -points:

    -

    -

    Last, we rotate and back to the -original positions:

    -

    -

    The three-dimension case is more complicated.

    -

    Cubic Hermite splines

    -

    Cubic Hermite splines construct a curve based on two points along -with their respecive tangents.

    -

    Suppose the given starting point is at and ending point at , as well as the starting tangent - and . The fitted cubic polynomial -can be defined by:

    -

    -

    Proof is quite simple. Assume our function is , and given -that , we have:

    -

    -

    Solving it gives us:

    -

    -

    Rearranging gives -the equation proposed at the beginning.

    -

    We can also reformulate in terms of Bézier curves -with respect to the four control points . To show -this, recall that a cubic Bézier curve can be expresses as:

    -

    -

    We can rewrite as -follows:

    -

    -

    This shows that a cubic Bézier curve that patches the control points -in the middle determines the tangents of the interpolation curve at the -respective outer points.2

    -

    B-splines

    -

    Non-uniform rational -B-spline (NURBS)

    -

    Beta-splines

    -

    Catmull-Rom splines

    -

    Connections between Splines

    -
    -
    -
      -
    1. https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm↩︎

    2. -
    3. https://en.wikipedia.org/wiki/Cubic_Hermite_spline↩︎

    4. -
    -
    +

    Camera jitters with +damping in Cinemachine

    +

    Unity's Cinemachine has a notoriously severe problem that may cause +the follow object to seemingly jitter when you are using the +Framing Transposer component with damping enabled.

    +

    To show this, I did a simple experiment. I created a new blank scene +and spawned a new attached with the following script:

    +
    public class CubeMove : MonoBehaviour
    {
    public float speed;
    public int fps;

    public float CurrentSpeed
    {
    get { return currentSpeed; }
    }

    private float elapsedTime = 0.0f;
    private float currentSpeed;

    void Start()
    {
    if (fps != 0)
    {
    Application.targetFrameRate = fps;
    }

    currentSpeed = speed;
    }

    void Update()
    {
    elapsedTime += Time.deltaTime;

    if (elapsedTime >= 5.0f)
    {
    if (currentSpeed > 0.0f)
    {
    currentSpeed = 0.0f;
    }
    else
    {
    currentSpeed = speed;
    }

    elapsedTime = 0.0f;
    }

    transform.position += new Vector3(1, 0, 0) * currentSpeed * Time.deltaTime;

    }
    }
    +

    This script moves the cube for 5 seconds and then keeps it steady for +another 5 seconds and continues moving. The move speed as +well as the fps (frames per second) can be set for test +under different conditions.

    +

    A new virtual camera is then created with a +Framing Transposer component following this cube. A default +damping of 0.2 is used.

    +

    Here is result with speed is 100 and fps is +0 (when set to 0, the real fps is determined by Unity, may but +unstable).

    +

    +

    The jitters are very clear. You can also notice that the frame rate +(presented in the Statistics panel) is very unstable, and we will know +soon it is the unstable fps that results in camera jitters.

    +

    Cinemachine proposes a workaround to alleviate this problem, that is, +to use the revised version of damping where they sub-divide each frame +and simulates damping in the consecutive series of sub-frames. To enable +this functionality, go to Edit -> Project Settings -> Player -> +Script Compilation and add the +CINEMACHINE_EXPERIMENTAL_DAMPING marco to it.

    +

    +

    OKay, now we have enabled the new damping algorithm and let's see how +it will mitigate the jittering issue. Here is result with the same +setting we used in our previous experiment, i.e., speed is +100 and fps is 0.

    +

    +

    It is astonishing to see the jittering issue becomes even more +severe. I conjecture that the variance of fps will significantly amplify +camera jitters when this feature is enabled. In other words, the +experimental damping algorithm responds to the variance of fps in a +NON-linear way: when the variance is small, the experiment damping will +reduce the gaps of camera location between contiguous frames; but when +the variance is large, it will enlarge the gaps, leading to unacceptable +jittering. (Note: I did not validate this conjecture. If you are +interested, just review the code and test it yourself.)

    +

    What about the expected result if fps is stable? Let's take more +experiments!

    +

    Here is result with speed is 100 and fps is +120 (very high fps, which is usually prohibitive in shipped games).

    +

    +

    Very steady camera! What about setting fps to 60? Here +is the result.

    +

    +

    An fps of 60 performs equally well with 120, which is anticipated as +fps is stable. Okay, let's try a final experiment where fps is set at an +extreme value of 20.

    +

    +

    Even a low fps of 20 makes our camera stable, only if fps itself is +stable.

    +

    Now we can conclude that it is the instability of fps that induces +camera jitters, regardless of the exact value of fps. But, why?

    +

    Why camera jitters

    +

    Before answering this question, let us first take a look at the +source of damping implemented in Cinemachine.

    +
    public static float Damp(float initial, float dampTime, float deltaTime)
    {
    if (dampTime < Epsilon || Mathf.Abs(initial) < Epsilon)
    return initial;
    if (deltaTime < Epsilon)
    return 0;

    public const float kNegligibleResidual = 0.01f;
    const float kLogNegligibleResidual = -4.605170186f; // == math.Log(kNegligibleResidual=0.01f);
    float k = -kLogNegligibleResidual / dampTime; //DecayConstant(dampTime, kNegligibleResidual);

    #if CINEMACHINE_EXPERIMENTAL_DAMPING
    // Try to reduce damage caused by frametime variability
    float step = Time.fixedDeltaTime;
    if (deltaTime != step)
    step /= 5;
    int numSteps = Mathf.FloorToInt(deltaTime / step);
    float vel = initial * step / deltaTime;
    float decayConstant = Mathf.Exp(-k * step);
    float r = 0;
    for (int i = 0; i < numSteps; ++i)
    r = (r + vel) * decayConstant;
    float d = deltaTime - (step * numSteps);
    if (d > Epsilon)
    r = Mathf.Lerp(r, (r + vel) * decayConstant, d / step);
    return initial - r;
    #else
    return initial * (1 - Mathf.Exp(-k * deltaTime));
    #endif
    }
    +

    Translating into mathematics, we have:

    +

    +

    where is the damp time +parameter and the elapsed +time in this frame. This equation decays the input , the distance for the +camera to go to the desired position, by an exponential factor . If , the residual will be , meaning that at +this frame, the camera will traverse 99% of the desired distance to go, +only remaining 1% amount for future frames.

    +

    OK, let's assume we've placed a cube in the origin and it moves along +the x-axis at a fixed speed, say, +m/s. A camera is placed to track the cube with damping where damp time +. Let's further denote the +delta time for each frame by , where is the -th +frame.

    +

    Having all variables fully prepared, we can then simulate the object +movement and camera track process.

    +

    In the beginning of 0-th frame, the camera and the cube are both at +the origin, i.e., (0, 0, 0). As the cube only moves along x-axis, we can +emit the y and z dimensions and use a one-dimensional coordiante to +represent cube and camera positions.

    +

    At the 1-th frame, the cube moves to , the +distance the camera traverses is , and the residual is . We set for simplicity.

    +

    At the 2-th frame, the cube moves to , the distance the camera traverses is +, and the residual is .

    +

    At the k-th frame, we have , +, and +.

    +

    Without loss of generality, we can set . The following sections will use this +settings unless otherwise stated.

    +

    For different combinations of , may have different results. Let's dive into and see how it influences +the results.

    +

    Case 1: Stable FPS, +all are equal

    +

    When all are +equal, say , our equations +reduce to:

    +

    +

    apparently has a +limitation of when +since . This +explains why a camera with damping always has a maximum distance to its +following target. There maximum distance, also the supremum, is exactly +. When is larger, will be larger, implying the +maximum distance between the camera and its following target will be +larger.

    +

    What if is +mutable? In this case, we can assume there exists an upper bound such that all satisty . Then we are +able to derive the same conclusion.

    +

    Another question is, why camera does not jitter when FPS is stable? +We turn to examine the sign of :

    +

    +

    Therefore, when FPS is stable, is always larger than , and jitter will never +happen.

    +

    Case 2: Unstable FPS, vary

    +

    When FPS is unstable, where may mutate, how will the camera move in response to its +following target? We can still examine the sign of , but in another +way:

    +

    +

    This equation uncovers why camera jitters happen with unstable FPS. +The residual at the k-th frame is essentially an interpolation +between the following target's current position increment and the last frame's +negative residual , where +the interpolation strength is the decaying factor . +As both and are fixed, a change in will incline the resulting +residual to different ends, +either or .

    +

    In our simplified case in which the target moves at a fixed speed in +the direction of x-axis, will always be positive (though its magnitude can vary) and + will always be negative. +A mutating thus has +a chance to alter the sign of , which further brings +about camera jitters.

    +

    So when will camera jitter? From the above equation, we know that +camera will jitter when the sign of consistently changes +over time, i.e., the value of oscillates around zero. +Let's make it equal to zero and see what we can find then.

    +

    +

    This equation tells us when is near , camera will have a large chance to jitter. This +motivates us to improve damping by filtering out the occasions where + is very close to +.

    +

    What about going deeper? We can treat as variable, and all other +as constants. This abstraction gives us a function of :

    +

    +

    Taking the derivative of , +we know that is monotonically +decreasing when and monotonically increasing when , and . Hence, to make the sign of mutable, must be positive and the +minimum of must be +negative.

    +

    The minimum of can be +easily computed:

    +

    +

    The last inequality holds because .

    +

    +

    This reveals the fact that: when , a variant is likely to cause to change its sign, +thus resulting in camera jitters. Suppose is large enough, so then +the k-th residual gets +smaller than while is positive. A smaller pushes to become smaller for the next frame, +which further pushes the root of the function to become larger. In this +case, even with the same delta time, will have a larger chance wo +fall in the negative area, i.e., is more likely to be less than the root.

    +

    +

    Solutions

    +

    Solution 1: imposing an +invalid range

    +

    Based on what we've discussed so far, we can immediately come up with +a simple solution: enforce to be if they are very close. That is to say, we use a +small value , if , we just set to .

    +

    Note that can be zero or negative. If this is the case, we keep the +original without +doing anything. Besides, you should be aware that here is not the time this +frame actually takes, instead, it is just the duration used to calculate +damping.

    +

    Let us explain it more quantitatively. Suppose , +where . +Then according to our algorithm. We then +plug into the original +expression of :

    +

    +

    This demonstrates that now the camera lags behind its following +target more than the previous frame since the residual is larger. After +substituting +with , would be zero, meaning +that the camera now keeps the same frame as last frame. Camera does not +jitter.

    +

    Here comes the question: what if the following target slows down, or +stops, or even turns back to the opposite direction and the camera still +remains the same residual to it?

    +

    It is quite a good question. But if we look carefully at the function +of , we will find this +situation will never happen. Let's rewrite here:

    +

    +

    This time, we do not constrain the value of , but at last frame, it's positive.

    +

    When gets smaller but still +positive, we observe the function gradually shifts leftwards, pushing +the root towards zero. This implies that the area gets +contracted and the probability of remaining the same residual gets +smaller.

    +

    +

    When is zero where the +following target stops, the current residual can be readily calculated +as , which closes the distance gap between the camera +of the following target. The ratio, which is calculated as , would be +devided by zero, outputting an infinite value.

    +

    When is negative, will be negative. The +ratio +now becomes negative, also beyond the range of .

    +

    We can implement this algorithm in less than 100 lines of code. You +should modify three files in the official Cinemachine source code +directory.

    +

    First is Predictor.cs. Add a ImprovedDamp +function:

    +
    public static float ImprovedDamp(float initial, float dampTime, float deltaTime, float bonus)
    {

    if (dampTime < Epsilon || Mathf.Abs(initial) < Epsilon)
    return initial;
    if (deltaTime < Epsilon)
    return 0;

    float tolerance = 0.05f;

    float alpha = Mathf.Log(bonus) * dampTime / kLogNegligibleResidual;
    float ratio = deltaTime / alpha;

    if (ratio <= 1.0f + tolerance && ratio >= 1.0f - tolerance)
    {
    deltaTime = alpha;
    }

    float k = -kLogNegligibleResidual / dampTime; //DecayConstant(dampTime, kNegligibleResidual);

    return initial * (1 - Mathf.Exp(-k * deltaTime));
    }
    +

    The input bonus is . Parameter tolerance is what you should set +as we've introduced +above.

    +

    In file CinemachineVirtualCameraBase.cs, add a new +function ImprovedDetachedFollowTargetDamp:

    +
    public Vector3 ImprovedDetachedFollowTargetDamp(Vector3 initial, Vector3 dampTime, float deltaTime)
    {
    GameObject go = GameObject.Find("Cube"); // Hard find our following target of interest, you should not do like this!
    Vector3 deltaDistance = new Vector3(100, 0, 0) * deltaTime; // Hard set the velocity, you should not do like this!
    Vector3 residual = initial - deltaDistance;
    Vector3 bonus =
    new Vector3(residual.x / (residual.x + deltaDistance.x + 1e-7f),
    residual.y / (residual.y + deltaDistance.y + 1e-7f),
    residual.z / (residual.z + deltaDistance.z + 1e-7f));

    dampTime = Vector3.Lerp(Vector3.Max(Vector3.one, dampTime), dampTime, FollowTargetAttachment);
    deltaTime = Mathf.Lerp(0, deltaTime, FollowTargetAttachment);
    return Damper.ImprovedDamp(initial, dampTime, deltaTime, bonus);
    }
    +

    This piece of code is very informal, and you should never write your +code like this. The purpose of this function is to get and . I reckon the correct +way to do this is to create a new (or two) variable in the +CinemachineVirtualCameraBase class and update it in each +tick. The code presented here is only for demonstration.

    +

    In file CinemachineFramingTransposer.cs, change the +called function for damping:

    +
    cameraOffset = VirtualCamera.ImprovedDetachedFollowTargetDamp(  // Original is DetachedFollowTargetDamp
    cameraOffset, new Vector3(m_XDamping, m_YDamping, m_ZDamping), deltaTime);
    +

    You could also try other components, not just +FramingTransposer here.

    +

    With the default tolerance=0.05, the result is shown +below.

    +

    +

    Camera jitters disappear. Note that the general fps is quite high +(around 400~500). This is because our scene is quite simple, containing +only a cube and a camera. In order to simulate a more real runtime game +situation, I place 20k cubes in the scene and now the fps is around 30, +but still unstable.

    +

    Below is the result when using the raw damping algorithm.

    +

    +

    Camera jitters more severely due to a generally lower FPS. What about +using the improved damping algorithm? Here is result with +tolerance=0.05.

    +

    +

    Just as expected, camera jitters do not show up. Let's try different +tolerances. How will a small tolerance help +alleviate jitters? Below is the result with +tolerance=0.01.

    +

    +

    Camera jitters occur again! This suggests that an excessively small +value cannot fully filter out actions that can lead to camera jitters. +Let's try our final experiment with tolerance=0.1.

    +

    +

    Camera jitters disappear, but the camera motion seems a little stiff. +These experiments show that an appropriate value of +tolerance to ensure the smoothness and robustness of the +camera.

    +

    Solution 2: adding low-pass +filter

    +

    Our improved samping perfectly solves camera jitters under unstable +fps, but it looks very stiff when it reaches the boundary of max damping +distance. Can we make it more realistic so that the object won't just +look stolid? Yes of course, we can add low-pass filter, or moving +average to our improved damping to achieve more smooth results.

    +

    Recall the algorithm of the improved damping: if , we just set to . +Instead of hard setting to , we introduce , the smoothed version +of the original delta residual . If holds, we calculate as an average of + and :

    +

    +

    which can be iterated through a recursive form:

    +

    +

    Note that gets +updated if and only if holds, +i.e., when the camera lies in the unstable area. The +use of is similar to +low-pass filters in the sense that they all filter out high-frequency +signals.

    +

    Below is s sample code implementation in file +Predictor.cs:

    +
    CurrentResidual = initial * Mathf.Exp(-k * deltaTime);
    ResidualDifference = CurrentResidual - PreviousRedisual;

    float result;

    float tolerance = 0.1f;
    float alpha = Mathf.Log(bonus) * dampTime / kLogNegligibleResidual;
    float ratio = deltaTime / alpha;

    if (ratio <= 1.0f + tolerance && ratio >= 1.0f - tolerance)
    {
    float beta = 0.001f;
    CachedDeltaResidual = (1 - beta) * CachedDeltaResidual + beta * ResidualDifference;
    result = initial - (CachedDeltaResidual + PreviousRedisual);
    }
    else
    {
    result = initial - CurrentResidual;
    }
    +

    Let's try it out! With damping time and , we can achieve the +following damping result with low-pass filter:

    +

    +

    Now the camera looks much more smooth and, flexible. What about +trying a smaller damp time, say, ? Here is the result:

    +

    +

    The result is ok but sometimes it's still jittering. It is because a +smaller leads to a larger and thus a larger chance to +cause jitters. To solve this issue, we can set a larger tolerance , or we can have a smaller +. We adopt a of and see how it performs.

    +

    +

    The camera now becomes smooth again.

    +

    We can measure this sort of instability more quantitatively. Below is +a graph plotting +during five seconds of camera trace with damp time . The original curve (in blue) +oscillates over time due to an instability of fps. The improved damping +method eliminates all the oscillation and makes the curve absolutely +plain. Empowered by low-pass filter, the curve becomes smooth without +loss of stability.

    +

    +

    Below is the graph with damp time . As can be seen, even with improved +damping, the camera still has a chance to vibrate, and the original +curve, oscillates much more intensely than with . Employing the low-pass filter +gives a much smoother and stable camera motion curve, as expected.

    +

    +

    Speaking of this, why can't we just soften our +improved damping assignment to where is a function of + parameterized by .

    +

    Assume +and , we first calculate ; +then calculate ; +last, we have . +For , we obtain . is a parameter controlling how fast the +value of grows from + to . The larger is, the larger mass will be +concentrated on the +side.

    +

    Below is the result with +and :

    +

    +

    Not bad! The soft version of improved damping really makes the camere +smoother and less stiff than the vanilla improved damping algorithm. The +follow plot also shows that with soft parameterization, the camera +trajectory is much more natural with neglectable amount of +oscillation.

    +

    +

    We also compare it to different and . Beolow is the result with and .

    +

    +

    A larger makes the camera more +stiff, but is still better than the original improved damping +algorithm.

    +

    Below is the result with +and .

    +

    +

    is less effective as the +magnitude of attenuation it applies to is not enough to compensate +for the osciallation the unstable fps brings about.

    +

    Let's try another damp time. The result with and shows as follows.

    +

    +

    When , the oscillation is +more severe, as we've already stated above. What about ?

    +

    +

    Better, but still not sufficient to mitigate the oscillation. Let's +try .

    +

    +

    Almost perfect. We can conclude that a smaller needs a larger to offset the intense jitters resulted +from unstable fps. Besides, you can combine the soft improved damping +method and low-pass filters to achieve a smoother transition.

    +

    Solution 3: continuous +residual

    +

    Okay, let's forget all aforementioned solutions and revisit our +residual update formula at the very beginning:

    +

    +

    Reformulate thie equation to the following form:

    +

    +

    where is the speed of the +camera's follow target, and is a more generalized form of the damping function . +Theoretically, it can represent any function of interest.

    +

    Now, regarding as a function +with respect to , we can seek to +obtain its derivative:

    +

    +

    We use the equality +because when you plug +into , you will get , implying .

    +

    What about derivatives with higher orders? We can calculate the +second-order derivative as follows:

    +

    +

    It is a nice form which bridges the first-order derivative and the second-order derivative +. In fact, for any +-th order derivative, it can be +recursively calculated as:

    +

    +

    Having all these derivatives, we can then expand using Taylor series and +calculate the difference to :

    +

    +

    Note that if we are still choosing as out +damping function , the +derivative of it with respect to will be and the value at zero will be .

    +

    In practice, we first decide how many terms in the coefficient term +should be taken in, and then sum them up and multiply with the velocity +term, the result of which is denoted by . The residual at the current +frame, can be readily computed as . To save +computation, we can first cache +up to a threshold, say , and +then using the formula of geometric series to efficiently compute the +coefficient sum.

    +

    To estimate its error, we use the Lagrange remainder:

    +

    +

    Decompose it:

    +

    +

    where +and as we assumed. We can +see that the error is asymptotically negligible with respect to , especially when is small.

    +

    Recall that +where and + is the damp time. If is large, say 0.5 or even 1.0, the +value of will be +somewhat small so that a decent precision can be reached within few +steps of expansion, i.e., a small +say 2 or 3 could satisfy camera stability. However, if is small, say 0.2 or 0.1 or even +smaller, the value of +would grow larger, and then a larger might be needed to reach our expected +precision. This is in accordance with our observation that a smaller + generally leads to a more +unstable camera trajectory. We will show this soon.

    +

    Let's first try and . Recall that is the maximum order of derivatives we +use to approximate the residual difference. means that we only use in the coefficient term. Here is +the result:

    +

    +

    Looks nice! What about setting ?

    +

    +

    Not much difference, but a little bit smoother. Let's try respectively with and . First comes .

    +

    +

    It's okay but it seems too fast when the cube comes back to +stillness. How about ?

    +

    +

    Now everything gets worked! Next, let's set smaller, which generally won't be used +in actual gameplay but as a test it's worth a try. We set and try different to see how they influence our camera +trajectory.

    +

    Here is the result with :

    +

    +

    Okay... a total mess. Try :

    +

    +

    Unfortunately, the cube always stays behind the camera. Now :

    +

    +

    Forget about it ... Let's try :

    +

    +

    Things are getting better! At least it does not shake anymore and +begins to stay at the right position. I bet is better:

    +

    +

    It's close! Last, we try :

    +

    +

    Finally, the camera disposes everything well. As we can see from the +process, a small requires a large + to reach the minimum acceptable +precision. I hope you never have the chance to use such a small , and if it happens, cache enough orders +of derivatives or it would be prohibitively expensive to compute at +runtime.

    +

    To further understand why this method solves the jittering issue, we +take a deeper look at the expression of derived above. +This is an ODE and we solve it out (proof left to the readers):

    +

    +

    Here I've expanded as . We cannot +directly use this explicit expression to calculate because there is no +correct time stamp when game is running. What we only have +is the previous frame's residual and the elapsed time at this frame +. And as the velocity may change over time, a closed-form of + cannor serve our purpose well. +We can only incrementally calculate camera residuals at each frame based +on what we currently have.

    +

    is a monotonic increasing +function, and of course, it's continuous. The continuity ensures that +the camera trajectory is always smooth and never jitters, if fps is +sufficiently high (over one thousand I suppose?).

    +

    For the original discrete residual, its velocity is:

    +

    +

    where is from +Lagrange's Mean Value Theorem. Note that I add a tilde symbol over to distinguish it from the one from the +continuos version above.

    +

    This is another ODE. We can solve it out (proof left to the +readers):

    +

    +

    Note that we solve the ODE with respect , the increment time rather than +the absolute time . So, we +introduce an initial value to control what the +initial value of residual is at this frame, is now the elapsed time for this frame +satisfying and .

    +

    The following graph shows that how the function changes with +different and . It can be +noticed that this function is very sensitive to the input , the elapsed time at this frame. A +small change of the input would significantly change the sign of , thus causing camera jitters. +We also notice that a smaller , +derived from a smaller , pushes +the function leftwards, which also makes it more vulnerable to +inputs.

    +

    +

    Below is a comparison between five damping algorithms introduced in +this article, including the original damping. Damp time is set to 0.2. We observe significant +stability improvement when using any of the four proposed damping +algorithms. You should be careful when choosing the most appropriate +algorithm because the situation on which you intend to use damping. How +unstable is your fps? What is the damp time ? How is the tracked object moving? You +should experiment with these algorithms and choose the one that best +suits your needs.

    +

    ]]>
    - 数学 - 图形学 + 游戏 - 相机 数学 随笔 计算机 - 动画 - Spline - Curve - 曲线 - 插值 + 相机 + Unity + Cinemachine + Damping
    - 《Assassain's Creed Odyssey》玩后感 - /2020/09/08/18/39/ - 115小时,主线+两个DLC通关。奥德赛是一个优秀的游戏,但不是神作,在走向RPG的道路上是系列作品的里程碑。人物塑造方面,奥德赛无疑是成功的,由于我选择的是温情 -路线,所以我看到的马拉卡的内心是无比渴望家庭的温暖的,正如奥德赛音乐集的“Odyssey(Modern -Version)”中的歌词"Travel in path alone, back to the warmth of -home"一般,踏在异乡的每一步无一不通往家。本作两个主要配角Phoibe和Brasidas,都令人印象深刻。在画面上,优良的美工沿袭了育碧式BUG,有可能在欣赏风景的时候会卡到墙里面,有时候还挺扫兴的。值得一提的是,奥德赛对希腊风情的刻画非常优秀,每一个同步点都可以疯狂截图作壁纸。本作比较难受的地方是剧情,三条主线除了家庭线比较完整之外,另外两条主线都虎头蛇尾,过多的无用支线严重稀释了主线的紧凑感,让人在玩到一半之后想去玩巫师三。DLC1的整体剧情我个人比较喜欢,但是一些细节处理尤其不妥,动机不足导致DLC1评分降低。DLC2流程很长,总体来说冥界剧情好于亚特兰蒂斯剧情好于极乐世界,不过对神之领域的描绘总体来说很精彩。如果说我对11.10发售的英灵殿有什么值得期待的话,可以用几句话总结:剧情不要拉跨,任务尽量优化;BUG可以少些,卡墙不动尴尬;风景依旧如画,壮汉赶紧来吧!

    + Midjourney和NovelAI不完全使用指南 + /2022/10/22/17/37/ + 显然,AI绘画已经发展到了一个新的阶段。尽管现在市面上已经有不少AI绘画工具,但要熟练地掌握使用它们也绝非易事。本文从实践出发,为读者讲解如何更好地使用Midjourney和NovelAI这两个时下火热的AI绘画工具,但由于笔者使用时间较短,无法完全驾驭AI绘画工具,因此本文是“不完全指南”。如果本文有任意谬误或缺漏,希望读者能不吝指出。

    -

    剧情:整体精彩,细节拉跨

    -

    自奥德赛发行以来,“剧情”一直是被玩家广为诟病的一点,但是在做完所有任务(包括两个DLC)、体验完所有剧情之后,我倒是觉得奥德赛的剧情整体上非常优秀,但是和大多数玩家一样,我也想吐槽其中非常多的细节,我思考了一下,这大概是出于一种“恨铁不成钢”的心理。明明奥德赛的剧情可以做得非常棒,可以几无瑕疵,可以触及巫师三,但是阿育就是把这么一个差一点点就堪比完美的剧本甩到玩家脸上,香还是香的,但就是不情愿,被迫品尝一桌盛宴中编剧埋下的一坨坨屎。

    -

    世界观

    -

    奥德赛的世界观是建立在希腊伯罗奔尼撒战争期间,但显然,奥德赛不完全是一部纪实游戏,战争只是游戏的大背景,也是游戏开始的一个引子而已,到了后面,游戏的进展其实和战争已经没什么太大关系了。在这个大背景下,著名的时代人物,如伯里克利、苏格拉底、布拉西达斯都会悉数出场并成为推进主线过程中重要的人物,而另一大群体,“神教”,正贯穿了整个主线的发展。主角的冒险由神教展开,也从神教结束,神教作为核心暗线而存在,我们把它称为神教线。而剧情的实际主线则是马拉卡找家人的旅程,在途中,主角会踏遍希腊,经历诸多精彩的故事,最终找到家人,在若干年后再次相聚,我们把它称为家庭线。除此之外,奥德赛中还引入了很多神话元素,比如传奇动物、传奇生物、神之领域(主要在DLC2),它们以“神器”联系起来,游戏进行到中后期会出现一条新的主线,也就是让主角去搜集神器,我们称之为神器线

    -
    -奥德赛的地图很大 - -
    -

    所以,总的来说,奥德赛的世界观就是在希腊伯罗奔尼撒战争的时代大背景下,以家庭线为明线,以神教线为暗线,以神器线为辅线而展开的。在游戏进行过程中,主角会见证真实的历史,会体验各地的风俗,会欣赏希腊的风光,会体验人生的波折。奥德赛的世界观即是如此的宏大,在游戏策划的精心编排下将希腊的大观悉数摆在我们面前,同时又让玩家以小人物的视角代入到如画的场景中,如此结合,让玩家一旦进入到角色里,就很难立刻停下来。

    -

    然而,相比起源把一桌菜一股脑全给你端上来又不介绍菜品让你细细琢磨、品尝,奥德赛更像是古典西餐厅里的一盘盘端上精心调制的菜品并为你介绍菜的制作方式、选用食材、食用步骤,甚至还要告诉你在品尝之前要沐浴更衣精心打扮,这就会产生下面要说的一个问题,大而不精,野心太大但却没有把握住剧情开展的主次,导致剧情上连贯性的断裂,这进而引发一个很严重的问题:游戏进展到后期同质化严重,玩家的游戏热情被大幅度削减。就好比前几道菜都详细介绍,食客会觉得很高端很优秀,但是如果有几十道菜,每个都如此呢?食客就会厌烦。

    -

    任务

    -

    剧情是通过任务推进的。任何一个游戏,都有任务,完成了任务,尤其是主线任务,才能顺利推进到下一个剧情节点。可以说,任务是推进主线的首要手段(并非唯一,比如在奥德赛中,满屏幕的问号“?”也是一个手段)。

    -

    上面我们已经简单说了,奥德赛的主线可以分为三条:家庭线、神教线和神器线。家庭线和神教线是从头贯穿到尾的,二者并行,一明一暗互为依托,这样的设计是很好的:它既不会让游戏快速陷入单线游戏的乏味,也能营造剧情上汹波暗涌的气氛,很快抓住玩家让玩家进入角色。这里值得表扬的是本作家庭线和神教线的融合是非常到位的,二者不但是并行关系,而且是交叉关系,如同螺旋前进的两条线一样,共同推动了游戏剧情的发展。但是,第三条线神器线的出现大大打破了这一节奏,甚至是原本剧情的美感。在家庭线达到关键节点找到母亲后,本来以来父亲的出现会解释玩家所有的疑问,但是没想到,老父亲一出场就让玩家莫名其妙地搜集神器,没有半点前因后果的交代;在找到神器之后,又莫名其妙出现了古代与现代的时空错乱和穿越,我们的主角马拉卡又莫名其妙地活到了现代穿上了西服最终溘然长逝。说实话,我当时玩到这一段的时候几乎是快进过的,没有丝毫欣赏剧情的欲望。这一条线从一开始,到最后,只能用四个字去总结:说的是啥?尽管这一主线流程很短,但它的出现极大割裂了另外两条主线的连续感,也造成了马拉卡精分的错觉,让玩家搞不明白奥德赛的时间线究竟是如何排布的。

    -

    当然,家庭线和神教线不是没有问题,而且在很多细节之处都有槽点。比如家庭线的一大槽点就是,如果你走的是大团圆路线,你就会发现马拉卡过于圣母(没错,就是我)。诚然马拉卡是一个呆萌渴望家庭温暖外表冷漠内心火热的失足少年,但是当自己的妹妹残忍地杀害基友Brasidas,造了无数的孽后,马拉卡依然选择了原谅她,最后还能和继父、表弟在一个桌子上吃饭,我的内心无疑是充满了问号。你可以说,这是你自己选择的剧情啊!对,但是当玩家选择了这个剧情之后,我们会明显感觉到这个剧情是不尽合理的,也就是说,制作人在设计这一剧情路线的时候就没有仔细推敲其合理性,所以这个锅还要阿育来背。神教线的槽点就更多了,各种奇葩的神教成员(包括那个自爆身份好像老子不怕你的那个)一个接一个,最后鬼魅那段单口相声真的是漏洞百出,竟然还可以选择相信她,而且无论你选择什么,神教线都会到此为止,那又何必再做选项呢。

    -
    - -
    鬼魅的最后一个线索才是“女性”,不然很好猜
    -
    -

    除了主线之外,奥德赛的一大尤为突出的问题是,支线任务过多,而且过于无聊。在奥德赛中,除了标有黄色感叹号的关键支线之外,其他大部分支线都是在端茶倒水、洞穴找人、团灭兵营,基本上可以概括为:“我丈夫/妻子/兄弟/孩子不听我话跑出去不见了/被强盗抓住了,他可能在某某树林/洞穴/兵营里,你能帮我找到他吗”。刚开始玩用来点亮地图确实还不错,而且可以熟悉技能,提高操作,但是当游戏进行到中后期时,满屏幕的感叹号让你没有丝毫欲望去清空,因为你知道打不打都无所谓,对主线毫无影响,给的物品也毫无吸引力。也许制作者的初衷就是让玩家在打完主线之后再慢慢清支线,但实际上,对于一部分强迫症玩家来说,满屏幕没清又强行按捺自己去清欲望的想法的确是非常痛苦的,最终的归宿可能只有隐藏地图标记才能解救他们。尽管对总的剧情没有太大影响,然而过多的冗余支线就好比蒙娜丽莎嘴角沾了米粒,赫拉脸上长满痘痘,人还是那个人,但味道总觉得变了。

    -

    但另一方面,也不得不表扬一些支线的确做得很有意思。比如“失落的希腊神话”系列任务就很有意思(尤其是“倒霉的一天”),此外,雅典区的一系列支线也很有特色(苏格拉底与雅典炮王的任务),还有一开始瘟疫的支线,这些支线要么本来在内容上非常丰富、有趣,要么会影响后续的剧情,这就回到了支线的作用:需要给予玩家一定的反馈。如果做完一个支线,玩家什么都没有得到,什么反馈都没有,那做这个支线干什么呢?看风景吗?所以,我认为如果把神器线做成一个系列支线,那效果可能就会好很多。如果删掉其中80%的无用的没有任何反馈的支线,说不定奥德赛的IGN评分又会更高。

    -

    可以看得出来,奥德赛在任务系统上有浓重的借鉴巫师三的痕迹,主要体现在剧情选项和支线系统。支线系统我们已经上面已经说了,和巫师三一样都有很多支线,但是巫师三的支线是它被称为神作的原因,奥德赛的支线只有东施效颦的副作用,究其原因,还是二者对支线作用的理解不同。

    -

    剧情可选是奥德赛在整个刺客细条系列中的一大突破,也是效仿巫师三最典型的一个要素。为什么我们需要可选剧情?因为这可以给玩家更多的自由度,让玩家能够更好地带入剧情,玩家需要为每一个决定负责,从而就要深思熟虑,剧情选择引发的蝴蝶效应足以在游戏结局的时候升华玩家对整个游戏的评价和感悟。巫师三做到了,奥德赛没做到。这有几点:

    -
      -
    • 奥德赛大部分选项不会对后面的游戏剧情有所影响;
    • -
    • 可选项非常少,玩家可能面对哪个都不想选但又不得不选的尴尬境地;
    • -
    • 选择之后的剧情推进和想象的不一样。
    • -
    -

    从我个人的游戏体验来说,上面三点是奥德赛在“剧情开放”尝试中最为突出的问题,我相信也是大部分玩家承认的问题。奥德赛的最终结局只有几种,而决定这几种结局的选项在几十个小时的游戏中只有寥寥几个地方,那其他的无数选项的作用是什么呢?第二,奥德赛每次可选的大概在3~5个选项之间,而给出的所有选项有时候又都非常智障,明明哪个都不想选却偏要选一个,这对玩家非常不友好,有种强行喂食的感觉。第三,剧情总是朝着意料之外的发展。比如有个任务是关于贩夫的未婚妻,这个时候就不能骗她说贩夫被干掉了,否则直接导致任务失败;而有的时候又需要你假惺惺地欺骗一下NPC才能完成任务,这种任务设定毫无规律可循,遇到了大概率就是一脸懵逼然后呵呵一笑。综上,剧情上的自由可选,就奥德赛的表现来看,反而是禁锢了玩家的自由度,看似让玩家有更多决定剧情走向的权利,但实际上是画地为牢,无论怎么选,都圈定在了编剧预先定义好的条条框框里了。显然,这是一种非常不成熟、宁可没有的设计。当然了,作为向巫师三学习并处于刺客信条系列发展史的一部过渡作品,奥德赛牛刀小试也无可厚非,只是希望英灵殿能够在这上面进行改进。

    -

    最后来说一下两个DLC。网上普遍对DLC1的剧情诟病颇深,对DLC2倒是赞誉更多,不过我个人倒是觉得,DLC1的剧情高度比DLC2更高,但是下限也比DLC2低,而DLC2发挥整体非常平稳。但从剧情上讲,我个人更喜欢DLC1,尽管它有非常突出的硬伤。

    -

    DLC1的剧情整体上非常棒,前提你玩的是Alexios(据说Cassandra体验非常不好)。游戏流程不长,十个小时以内可以打完,但是任务节奏很紧凑,内容相对丰富,关键是剧本很给力,讲述了马拉卡遇到真爱但是又被命运无情摧毁的故事。在这个DLC里,我看到了马拉卡内心的脆弱,尤其是他对家庭温暖的渴望与期盼。其实,在玩游戏本体的时候,我们会经常听到马拉卡感慨自己的命运,我印象中比较深刻的是“要是我不离开凯法隆尼亚岛就好了”,再回忆片头马拉卡独自坐在房上抚摸着断矛,他一定非常渴望再见到亲人吧。虽然在凯法隆尼亚岛上,他可能永远也见不到亲人,但是,有Markos,有Phoibe,还有岛上其他的伙伴,这样的小日子,不也很美好吗,正如他与DLC1的女主相遇相知相爱后,与岳父大流士、自己的孩子四人一起生活在村里,平淡而温馨,甜蜜又幸福,不也正是马拉卡一直想要的生活吗。做一个漂流在外四海为家的佣兵并不可怕,可怕的是这样的人却时刻想要有一个稳定幸福的小家庭,这简直是一种无法企及的奢望。当上古维序者干掉女主,马拉卡在火海中呼唤着她的名字时,当马拉卡来到家门口的她的坟墓前时,当马拉卡之后到他们相知的三个地方寻找纪念物时,当最后马拉卡把孩子托付给岳父大流士看着他乘帆远去时,当最后的最后马拉卡仍旧时孤身一人时,我心中的确是被深深触动了。这是我非常喜欢DLC1的点。

    -

    但是也正如上面所说,DLC1的上限很高,下限也很低,主要仍然体现在细节不到位。比如火海救岳父的情节,作为一个久经沙场的佣兵,他应该是完全能够意识到将妻子儿子丢在船边会有什么后果,就算不能两边兼顾,也应该知道孰轻孰重。再有最后送走儿子的桥段结束得过于仓促,上古维序者这个组织的行为动机也不够充分,在很多地方,玩家是没有办法选择剧情的走向的,也就不得不被迫喂屎,这也是DLC1被广大玩家吐槽的原因所在。但我个人认为,DLC1仍然是瑕不掩瑜的,对于部分玩家而言依旧有非常高的可玩性。

    -
    - -
    这一段还是非常感人的,我流下了130滴眼泪
    -
    -

    相比之下,DLC2的流程就非常非常长了,目前需要30个小时左右才能全部通关。DLC2分为三个章节,每个章节的流程都很长,相互独立但又通过“神话”这一线索串联起来,大概是寻找亚特兰蒂斯并探索神杖的用法。这个DLC把正作的神器线联系在了一起,在希腊和现代两个时间点之间不停穿越,目的就是要给玩家解释这个神器是怎么一回事儿。说实话,我也不知道他解没解释清楚,反正我基本都是快进过了,因为实在是过于无聊。

    -

    在剧情上来看这个DLC没啥有意思的,我总结一下,第一个章节是神秘四角恋上演姐妹撕逼大战,第二个章节是冥王海王打赌以虐待死者为乐,第三个章节是主角化身正义使者最终颠覆亚特兰蒂斯政权。总之就是云里雾里、莫名其妙。不过值得表扬的是,每个章节的特色地图都非常不错,极乐世界的花花草草,冥界的幽暗阴森感,亚特兰蒂斯的宏伟高科技,给人耳目一新的感觉。我印象最深的还是冥界的Phoibe剧情和Brasidas基友剧情,还是有点感人的,到了最后也特别想痛扁冥王。极乐世界充当双面间谍的感觉也不错,只是亚特兰蒂斯过于平平无奇,除了最后的BOSS有点恶心之外,也没有什么比较让人能够记住的点了。

    -

    这里特别吐槽一下冥界Brasidas的剧情,实在非常无语和狗血,把编剧的圣母心态体现得淋漓尽致。作为一个从小接受战士教育的将军,在战场杀敌是本分;当敌人杀向你,举起武器反击是本能;只是推开挡路的女人而没有将其杀死,是本心;无论从哪个角度讲,Brasidas都没有做错,战争也好,斯巴达的荣耀也好,还是出于自己的意志也好,Brasidas的做法都是无可非议的。但是,编剧强行要通过这个故事去虐Brasidas,本来都死得那么惨了,还要让他做出痛苦的抉择,实在是非常过分。在这里,我心疼基友三秒钟。

    -
    -基友太惨了 - -
    -
    -我恨这个女人 - -
    -

    画面:时代顶尖,BUG难掩

    -

    奥德赛延续了起源优秀的画面,在刻画希腊风光上做到了无出其右,以至于获得了“旅游模拟器”的美称。画面其实是一个比较笼统的概念,当我们在说一个游戏的画面的时候,我们一般是在说这个游戏带给我们的所有视觉体验,包括光影效果、水和火的模拟、各种材质的清晰度真实度、整个画面的比例、画面的色彩等等等等,只要是我们能直观感受到的,都可以归入画面里。

    -

    从画面整体来看,奥德赛做到了时代的顶尖。优秀的光影、逼真的水波、温暖的色调、协调的比例、真实的场景,包括人物的建模等,都非常优秀。最难能可贵的是,奥德赛给我们生动地呈现出了波澜壮阔、风光迤逦、特色鲜明的古希腊景象,尽管可能不是最真实的历史,但是当我们置身其中时,仍然可以感到非常的震撼,仿佛自己就是那个时代的人,经历着相同的事。所以,奥德赛的画面不仅是技术上的时代顶尖,而且他还能带给我们一种沉浸式的体验,这对一个优秀的3A游戏来说,是必不可少的。

    -
    -光影效果非常不错 - -
    -

    当然,对奥德赛来说,他还是沿袭了“育碧特色”——各种神奇的BUG,虽然已经比起源好很多了(起源的BUG可以看这里)。比如,你会卡到一个地方无法动弹然后“失去同步”,会在地上皆若空游无所依,会有各种各种严重不严重的穿模。其中最为蛋疼的,其实不算BUG的地方就是,自动寻路。这个简直是噩梦,很多时候系统会绕很大一圈,甚至是本来已经绕了很大一圈了,结果来了个“无法跟随道路”,这是坠痛苦的。不过好在可能是阿育经历了起源雪崩式的BUG,在奥德赛里BUG已经不是一个很严重的问题了,至少可以完成任务不是。

    -
    - - -
    -

    人物:形象丰满,行为骨感

    -

    谈到剧情就不得不稍微说一下人物了。奥德赛对人物的刻画是非常到位的,作为一部史诗大作,奥德赛不仅对主角马拉卡和一些主要人物进行了细致入微的刻画,并且对一些关键配角也有非常到位的描写!

    -

    首先说一下主要人物:马拉卡、妈和妹妹。马拉卡无疑是最核心的人物了,玩家在关键剧情上的不同选择会呈现出多面的马拉卡形象,由于我选择的是真情圣母路线,所以就按照这个形象说。马拉卡给人的最大印象,在上面已经说了,作为一个铁血真汉子、无情雇佣兵,他的内心其实是非常渴望亲情的,无论是一直心心念念想要找到妈,想要挽回失足妹妹,还是对Phoibe如待女儿一般的呵护与关爱,抑或是对Markos的帮助,都体现了一个流浪在外无家可归的人向往亲情、渴望家庭的内心最真切的期盼。马拉卡不滥杀无辜,同情战争下家破人亡的底层百姓,路见不平也能拔刀相助,时而放荡不羁,时而收敛拘束,就好似武侠小说里的绝世大侠,执剑走江湖,四海皆为家。在游戏的时候,左下角的提示会出现“xx号是你的家,记得常回来看看”(大意如此),不禁让人唏嘘,马拉卡总是在外漂泊,以船为家,在注定不平凡的寻亲之路上经历这么多人生的坎坷,着实让人心疼!另外,马拉卡这个角色还透露着呆萌的气质,一方面是来自配音+动补演员本身的气质,另一方面就是在游戏中,马拉卡的确也很幽默,经常开一些黄腔,引发一些笑话。这些对丰富和塑造人物形象都非常有帮助。

    -
    -性感吗?我可以 - -
    -

    然后再说说一些关键配角,这里说几个人:妈、后爸、Phoibe、基友Brasidas、炮王阿尔西比亚迪斯、苏格拉底。这几个人应该是除了主角之外给我留下印象最深刻的几个人了。

    -

    奥德赛对妈的刻画是非常到位的:坚强独立、能力突出,同时也和马拉卡一样渴望完整幸福的家庭。在找妈的路上,我们已经通过几个支线知道了妈是如何去找妹妹,如何带着她逃跑,又是如何在失去她之后绝望,到她最后重新振作成为一岛的领袖的。在这个过程中,妈的形象跃然纸上,后来和马拉卡一起挽救妹妹更是突出了她追寻亲情的一面。

    -

    对后爸的笔墨虽然不多,但是也能大致勾勒出一个教子严厉但关怀备至、有些教条但也饱含感情的一个将军形象。作为一个将军,他当初在悬崖边没有办法与神教抗衡,但是他也在一直懊悔。在几个CG里,我们都看出来,尽管他是继父,但是他仍然对马拉卡和妹妹视如己出,教导和关爱也都无微不至。

    -

    Phoibe和Brasidas应该是马拉卡人生中非常关键的两个人了。一个在他的生活中和他超越了朋友的关系,一个在他的斗争中给予了莫大的帮助。可以说,Phoibe与Brasidas是马拉卡少年时和成年时的两个缩影,一个象征着无邪的天真烂漫,一个象征着成熟的稳重冷静。站在马拉卡的视角,他想要紧紧地把握住他们,不但是对朋友的珍惜,更是对自己这两面的珍视,在他的心里,永远有一个小孩子,愿意陪着Phoibe一起长大,也永远有一个大人,能够和Brasidas并肩作战。

    -
    - -
    马拉卡对Phoibe非常关心,因为她是最亲密的人
    -
    -

    其实说实话,我对Phoibe是又爱又恨的,爱的是她的善良机智,恨的是她的自作聪明,无视马拉卡警告对自己的能力没有清晰的判断,导致自己身死他手,实在让人惋惜。显然,既然作为一个玩家,我已经能够对她产生这样的情感了,那么无疑,奥德赛对Phoibe的塑造也是相当成功的,虽然不那么讨喜,但是至少她是真实的。

    -

    基友的镜头没有Phoibe那么多,但是当他在贩夫仓库第一次出场时,就注定他有一个悲剧式英雄的解决了。在熊熊燃烧的大火中单挑对方几个好汉,与马拉卡多次在战场上默契配合,在斯巴达时多次帮助主角一家恢复名誉,以至于最后也是战死在战场上的,这样一个人物,实在令人肃然起敬。而且,基友不但是一个优秀的将军战士,他其实也很善良,他在能不杀人的时候是尽量不杀人的,从贩夫,到后来的斯巴达剧情,乃至到DLC的冥界,都体现了基友刚毅且善良的一面。然而,在DLC冥界那里,只要选错一个选项Brasidas就会留在冥界,这个行为这个剧情无非就是编剧强行喂屎表达泛滥圣母心的一面,实在是为这个角色抹黑!

    -
    -基友真的太帅了 - -
    -

    最后,炮王阿尔西比亚迪斯和苏格拉底的刻画也是相当有意思。在游戏后半段这两个人都会有很多任务,炮王会不断地让你去帮他约炮,或者和他约炮,而苏格拉底就是不断和你强行抬杠探讨哲学,总的来说,这两个人物的刻画也非常鲜明。其他的包括船长、鬼魅、斯巴达领袖、表弟,甚至是那个性欲很强的老女人,奥德赛对他们的刻画也都有所突出,所谓众生各相,让玩家在走剧情、赏风景的同时还是感受古希腊多姿多彩的人文特色。

    -

    但是,正如这一节的标题所说的,很多人物的形象是很丰满,但是在一些细节方面,人物的行为动机是严重匮乏的,以至于玩家会觉得“为什么非要这么做”,这样的设计对人物的刻画是有害的。举个典型的例子,亲爸毕达哥拉斯,莫名其妙找到一个神器,然后莫名其妙又觉得自己无敌了,最后又莫名其妙地挂了,过完剧情玩家只会觉得这个人脑子有点不正常,至于其他的性格、形象、心理活动?不不不,脑子有问题就是了。人物行为骨感集中体现在DLC1,这也是DLC1被大家广为诟病之所在。上面已经说过这个问题了,这里不再赘述。

    -

    最后的最后,在游戏结局时马拉卡与苏格拉底在墓园的对话让人感慨万千,在此摘录如下:

    -
    -

    Alexios:Phoibe,她从没有过小女孩的时光,我总是以成人的方式与她对话。 -苏格拉底:这是因为你尊重她。你可以问问自己为何这么选择,Alexios,但千万不要质疑自己的决定。 -Alexios:谢谢你给了她该有的葬礼。 -苏格拉底:在极乐世界中还有无数的人,这些受到祝福的人已经获得了永恒的喜乐,其中一个就是我们伟大的伯里克利。 -Alexios:基于他的一切作为,全雅典都欠他一份情。 -苏格拉底:我们会称他为“雅典第一公民”不是没有道理的。他是个有很多贡献的人,但也是个孤僻的人。 -Alexios:要是他肯让我们分担他的重担就好了…… -苏格拉底:我们只能从他表现出来的部分来了解他,但谁敢说那就不是他真正的自我呢? -Alexios:这场战争牺牲太多人了,就连布拉西达斯都陨落了。 -苏格拉底:或许如此。但身为一个斯巴达人,他已经尽了自己的义务并战死沙场了。 -Alexios:我当时也有尽全力帮助他。他是我的朋友。 -苏格拉底:你还活着就是他最好的复仇,人们会将他作为英雄来尊敬的。 -Alexios:人们会记得我们是如何打垮克勒翁的。

    -
    -

    类型:转型成功,平衡欠佳

    -

    起源之前的刺客信条属于传统意义上的ACT游戏,从起源开始,逐渐向RPG转型,到了奥德赛,已经形成了ARPG的初步格局。尽管现代游戏ACT、RPG、ARPG的界限已经趋于模糊化,但是我认为我们还是有必要对游戏进行一个粗略的分类,以更好地对游戏整体的类型风格进行评价。

    -

    如果用ACT的视角审视奥德赛,那么奥德赛显然是不合格的。这体现在以下几点:

    -
      -
    • 正如剧情一节所述,奥德赛非常侧重剧情的讲述,大量的CG、对话、支线任务就是为了铺垫剧情、描绘人物形象,这和传统的ACT游戏淡化剧情是相悖的;
    • -
    • 奥德赛的养成元素非常多,这体现在等级压制、等级上限、装备体系、技能体系上,尽管游戏默认的是等级跟随,但是等级提高带来的技能点收益是非常重要的,尤其在打传奇动物和传奇生物的时候更为显著;
    • -
    • 奥德赛的装备体系决定了它不是一个纯粹的ACT游戏,游戏的蓝装、紫装、黄装品类非常多,并且,极品装备是满属性的紫装,这就意味着玩家可以追求极致一刀99999,尽管奥德赛没有刻意去引导玩家这么做,但是显然,很多玩家已经开始爆肝了。
    • -
    -

    但是另一方面,我们也不能纯粹从RPG的视角去看待奥德赛,因为游戏尽管整体上非常看重技能,但是如果你没有极品装备而只有黄色套装,那在很多时候,你还是要通过射箭、刺杀或开启无双模型与敌人硬刚,这对你的手法还是有所要求,比如闪避、防反、换装、流派,如果你不想“失去同步”,在高难度下还是需要一定的熟练程度才能手起刀落斩敌人于马下。尽管和起源的防反、马战比起来这都是小儿科,但手残玩家挑战奥德赛的噩梦难度也还是颇有难度的。从这个意义上讲,奥德赛还是保留了一些ACT的元素。

    -

    其实,当前纯粹的ACT游戏已经是难以走下去了,这是因为游戏作为一种艺术作品,随着时代的发展玩家越发看重它的精神内核。一个游戏可以不要高难度的战斗操作,只要它有足够优秀的剧本,那么它依然可以是神作;但是,一个游戏如果只要求高难度的操作,以及精心设计的关卡,而没有剧情或者足够有说服力的剧情,那么今天的大部分玩家是不会买账的。ACT游戏的RPG化是时代下游戏发展的一个趋势,但对刺客信条这个具有ACT传统的系列游戏来说,如何在这样的趋势下顺利转型是一大难题。

    -

    就我的体验来说,如果说起源是刺客信条转型的初步尝试,那么奥德赛就是转型的成功探索,它是一次探索,并且整体上成功了。如果你玩过起源和奥德赛,你会发现它们之间有莫名的相似性,但是给你的游戏体验又是完全不同的。上面讲到,起源的剧情是比较破碎的,而在很多地方,你不得不进行战斗,又加之战斗本身的难度,你会觉得剧情反而不那么重要,干掉敌人完成任务这个过程反而才是重点;同时,起源较少支线为主线让路的这个做法本身也是突出战斗的一大考量。如果把起源当成一个ARPG游戏,那么它“A”的成分还是更多一些。但是反观奥德赛,它的战斗就进一步简化了,没有马战,防反简单,刺客的飞雷神简直开挂,后期技能及其变态,甚至凑齐极品紫装后就是一刀一个小朋友,战斗本身就成了服务剧情的工具,玩家玩得爽就完事了。但是,仍然作为刺客信条系列游戏的奥德赛,总不能全是过剧情吧,那怎么办,疯狂增加要塞、兵营、洞穴就好了!再给你设计无穷多的支线,每个支线都让你去打怪,难度不够,数量来凑,这不动作的成分一下子就高上来了。

    -

    这是一个简单且聪明的想法,但对于奥德赛的定位来说,不够明智。我们可以体会到制作人想要保留APRG的动作成分和角色扮演成分,并且都要做大做强。这当然是可能的,如果做的时间足够久。但是,对于奥德赛来说却不可能,理由如下:

    +

    Midjourney不完全使用指南

    +

    太长不看版:使用规范

    +
      +
    1. 首先根据公式 Prompt = 构图说明 + 画面内容 + 美术风格 + +光影设置 + 其他描述 + 参数列表 按照下面的模板写Prompt:
        -
      • 开发时间短。尽管实际的开发时间我们不能精确得知,但是奥德赛发行于2018年10月,它的上一作发行于2017年10月,两作中间仅间隔一年,是标准的年货游戏。虽然奥德赛是魁北克工作室开发的,而起源是蒙特利尔工作室开发的,但是二者在整个系列的表现形式上具体显著的承接关系,故姑且认为奥德赛的实际开发周期约为2年,这个时间对3A游戏来说不算长;
      • -
      • 奥德赛的定位。奥德赛位于刺客信条系列从ACT向PRG转型的过渡阶段,是比起源更具标志性的一部作品。我个人认为,奥德赛的定位就是一部不成熟的ARPG过渡作品;
      • -
      • 经验的缺乏。显然,阿育对如何结合刺客信条系列传统的ACT元素与RPG元素的经验还有所缺乏,在短时间内要做一部顶级APRG游戏是非常困难的。记得是谁说过,“奥德赛就是想让你玩两年,直到下一部作品问世”,于是,他们把奥德赛的内容强行用问号、感叹号去填充,让玩家去爆肝刷装备,然后体验一刀99999的快感,但实际上,这种大而空的填鸭式内容对大部分骨灰级单机游戏玩家都没有吸引力,有的只是机械重复式的屠杀敌人,毫无乐趣。
      • -
      -

      所以说,在奥德赛的游戏类型上(ARPG),平衡性是不够优秀的。大到动作成分与角色扮演成分的平衡,小到装备的平衡、技能的平衡、数值的平衡等多方面,奥德赛的“全都要”战略俨然对大部分玩家来说只是一个噱头。如果只把奥德赛玩成体验剧情、模拟旅游,那奥德赛是再好不过的,可是一旦要玩操作、玩养成,奥德赛好像就走向了低配版的国产网游之路。游戏类型的平衡,是奥德赛的一大不足。

      -

      总结:育碧特色,系列之巅

      -

      总的来说,和以往的刺客信条年货作品不同,奥德赛算得上是一部精心打磨的作品,无论是剧情、画面,还是人物、音乐,抑或是育碧特色BUG,都看得出来是经过仔细调教了的。我个人认为奥德赛是综合看来刺客信条系列的巅峰之作,IGN评分9.2也算是比较中肯的评价了(对比起源9.0和巫师三9.3的评分)。如果要我来打分的话,我会打一个9.0分,要是阿育能够在剧情上再多打磨打磨,就可以给到9.5分。如果要说和巫师三差在哪儿,就差在剧情上。

      -

      另外,在本文中我没有谈到奥德赛的音乐,但这并不意味着它不出色,相反,我非常喜欢奥德赛的配乐,对比起源阴间的配乐,奥德赛的整体音乐风格就显得非常阳光和带感。OST可以在B站或者QQ音乐搜到,我已经循环很多天了,强烈推荐大家也去听一听。

      -

      对于11.10号即将发售的英灵殿来说,我个人还是非常期待的,一是可以亲手操作猛男,二是从试玩片段来看,它革除了奥德赛中饱受诟病的一些要素(比如剧情、满屏幕的问号、又臭又多的支线,过于强调等级和装备等),同时还保留了优良的画面。从这两点来看,英灵殿无疑是让人期待的。不管你预卜预购,我反正是已经预购了(还是等打骨折更划算一些/(ㄒoㄒ)/~~)

      -]]> - - 游戏 - 玩后感 - - - 随笔 - 游戏 - 生活 - 刺客信条 - - - - 《Assassain's Creed Valhalla》玩后感 - /2020/11/12/23/23/ - 刺客信条:英灵殿(Assassin's Creed -Valhalla,下称英灵殿)无疑是刺客信条“神话三部曲”中最成功的一部,无论是从游戏的质量上,还是从销售成绩上。在80个小时的主线与10多个小时的“内置DLC”游玩后,我个人对英灵殿的评价可以总结为“自我突破,承前启后”。说它自我突破是因为它革除了起源和奥德赛中的绝大部分缺点,在自我的改进中完成了里程碑式的跨越;说它承前启后式因为它标志着刺客信条系列一次华丽而成功的转型与过渡,是游戏特色与市场充分交合后的最佳发展方向,是游戏缺点自我祓除与优点渐进式凸显的结果。本文将重点从游戏的任务系统、剧情节奏和人物刻画这三个方面介绍英灵殿的蜕变,至于游戏画面和风景,还有育碧特色BUG,都是刺客信条系列经典的历史特征了,在本文不再赘述。

      - -

      任务系统:众星捧月映空青,稀光散落满夜明

      -

      剧情节奏:一马平川驰此间,峰峦叠嶂牛羊见

      -

      人物刻画:穷极千里观百态,瓦泥滂沱照众生。

      -

      总结:长路漫漫终将至,共邀朝阳行远方。

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -

      -]]>
      - - 游戏 - 玩后感 - - - 随笔 - 游戏 - 生活 - 刺客信条 - -
      - - 《电脑游戏:文本、叙事与游戏》纪要 - /2021/08/14/18/08/ - 本文是《电脑游戏:文本、叙事与游戏》的简单纪要,在此备份。

      - -

      游戏与叙事

      -

      叙事理论

      +
    2. 人物特写:a {headshot | closeup} portrait of [content], [art style], [lighting], [other keywords], [MJ parameters]
    3. +
    4. 人物半身照:a {medium shot | over the shoulder shot | head and shoulder shot} portrait of [content], [art style], [lighting], [other keywords], [MJ parameters]
    5. +
    6. 人物全身照:a full body portrait of [content], [art style], [lighting], [other keywords], [MJ parameters]
    7. +
    8. 风景/建筑照:[content], [art style], [lighting], [other keywords], [MJ parameters] +上面用大括号{}括起来且用竖线|分割的内容是多选一,即从所有可选的关键词中选一个即可。用中括号[]括起来的是我们需要根据画面内容填写的。下面介绍中括号填写的基本规范:
    9. +
    10. [content]:是我们要填写的画面内容。如果是人物,主要填下面的内容(不一定都需要,也不一定完整,根据你的需求):
        -
      • 每一个叙事都有两个部分:一个是故事,指事件的内容或串联(动作、发生的事),再加上所谓的存在物(角色、场景中的事物等);二是话语,即内容赖以传达的方法。
      • -
      • 故事的事件在时间和空间上都是按照一定的顺序排列的,这就是所谓的情节设计
      • -
      • 叙事事实的三个方面:故事(内容)、叙事(话语)、叙述。 +
      • 什么人:{boy | girl | woman | old lady | warrior | witch | anthropomorphic white tiger | ...}
      • +
      • 脸部特征:{beautiful face | dedicate facial features | colorful tattoos on her face | ...}
      • +
      • 表情:{smile | crying | moaning | angry | ...}
      • +
      • 眼睛:{beautiful blue eyes | shining diamond eyes | ...}
      • +
      • 头发:{long curly black hair | flowing hair | braided hair | ... }
      • +
      • 装饰:{exquisite garland | opal decorations | wearing feather headdress | ...}
      • +
      • 穿着:{wearing tall black high heel boots | in purple and white kimono | ...}
      • +
      • 其他细节:{made of flower | rain on her face | ...} +如果是非人物,则一般不需要写这么细,只要描述大概是什么物体就好了。比如magnificent mountain, +interior of a cyber punk city等等。
      • +
    11. +
    12. [art style]:指定艺术风格,可以通过三种方式指定:
        -
      • 童话《灰姑娘》中包含了一系列故事的事件,可以通过很多种不同的方式被呈现出来。
      • -
      • 叙事的关键要素:对事件加以安排,使之在话语当中凸显出来,对它们的时间长度、发生频率和次序予以控制。
      • +
      • 直接指定主题/绘画风格:比如cyber punk, +steam punk, japanese anime, +oil painting, realistic painting, +ink painting, ukiyo-e, +bookstory illustration等等;
      • +
      • 直接指定相关风格的艺术家:比如吉卜力风格可以说art by {ghibili | koji hoshino | hayao miyazaki},皮克斯/迪士尼风格可以说art by {pixar | disney},等等;
      • +
      • 直接指定作品:比如breath of the wild, +dark souls, world of warcraft, +lord of the rings等等。 这里推荐使用第二种方式。
    13. -
    14. 隐含作者与隐含读者。
    15. - -

      叙事理论与《博德之门》

      +
    16. [lighting]:画面的光影效果,一般来说使用{cinematic lighting | volumetric lighting}比较通用。但对人物,你偶尔还需要用{back lighting | rembrandt lighting | spotlight};对非人物,你可能还要{morning lighting | flare}等等。
    17. +
    18. [other keywords]:其他关键词包括:
        -
      • 游戏包含了一系列由玩家所触发的新事件,允许玩家实时行动;也包含了过去的事件,已经被安排好的。
      • -
      • 事件被提前预制好,玩家是做出情节安排的人。
      • -
      • 同步叙事:向玩家传达屏幕上的行动、事件、得分和对话。
      • -
      -

      叙事的限度

      +
    19. 材质:{cubic | bronze | wood | liquid | glass | prism | smoke | plume | milky way | ...}
    20. +
    21. 色彩:{dark pink | rainbow | vibrant | warm color | black and white | monochrome | ...}
    22. +
    23. 形状:{star | torus | polygonal | low poly | interior | stellation | stellation | ...}
    24. +
    25. 其他一般默认加上用来叠BUFF的词:{intricate details | 8K | enchanting | masterpiece | octane render | unreal engine 5 | well composed | award winning | high resolution | ...}
    26. + +
    27. [MJ parameters]:Midjourney要填写的参数,一般使用下面的参数组合(但也要有意识地灵活运用):
        -
      • 叙事理论追问的是:故事情节是从何种角度被描述的,我们是通过谁的眼睛了解叙事当中的事件的,又是谁的声音在传递信息,是谁在策动事件,谁来决定事件的持续时间、发生频率和次序。
      • -
      • 《博德之门》以一种玩家无法操纵的形式讲述事件,以过场动画、NPC的对白和角色简介的方式被编织在一起,并与玩家发生联系。
      • -
      • 已然事件实时事件
      • -
      -

      游戏与快感

      +
    28. 人物特写照:{--ar 1:1 | --ar 3:4} --q 1.5
    29. +
    30. 人物半身照:{--ar 3:4 | --ar 9:16} --q 1.5
    31. +
    32. 人物全身照:{--ar 2:3 | --ar 9:16} --q 1.5
    33. +
    34. 非人物照:根据你的画面内容选择宽高比,如果是横板,则用--ar 16:9 --q 1.5;如果是竖版,则用--ar 9:16 --q 1.5;如果是加长竖版,则用--ar 9:32 --q 1.5
    35. + + +
    36. 写好之后,多次出图,你也可以尝试几次参数--test --creative--testp,一般来说效果会更好些,但注意风景图不要用--testp
    37. +
    38. 从所有的图中找到让你比较满意的图,使用UpscaleVariantRemaster功能对它们增强,反复出图;也可以继续在Prompt中增删细节,直到满意为止。
    39. +
    +

    关键词参考工具
    +更完整的关键词参考
    +艺术家参考
    +风格参考 +其他人的作品参考1 其他人的作品参考2

    +

    概述

    +

    Midjourney是当前最流行的AI绘画工具之一,它部署在Discord上,因此你需要注册一个Discord账号才能使用。

    +

    所有的AI绘画工具最重要的就是如何写Prompts,也就是文本描述。在开始之前,你需要知道写Prompts的几个基本准则:

      -
    • 电脑游戏究竟要驱使玩家去做什么。
    • +
    • 详略得当:描述越详细,图片越有可能接近你想的画面,但是也有更大的概率生成的图片质量更低;描述越简略,图片越多样化,质量也可能更高。但注意不要加太多细节,否则会图片会很低。一般来说,我们只需要写”意象“,而不要写得过于具体。
    • +
    • 以短代长:少用超过10个词的句子,而用多个短语,每个短语描述画面的一个细节/部分/风格。即使要用长句,也不要太长,保持在20词以内。
    • +
    • 反复润色:不可能第一次生成的图片就完全符合你的想象,需要不断给Prompts润色修改,这不是一个简单的活,因此请保持耐心。
    • +
    • 具象描述:尽量用一些具象的名词、形容词,比如river, +rockstar, Zeus, landscape, +happy, +dark等等,不要用一些难以在现实中找到对应实体的词,比如knowledge, +notion, type等等。
    • +
    • 指定量词:显式指定对象的数量,如果是一个就用a,如果是多个就指定具体数量。
    • +
    • 描述风格:在多数情况下都需要增加风格关键词,比如cyberpunk, +surreal, abstract, +realistic,也可以指定一个或多个艺术家,比如hiroshi yoshida, +Max Ernst, MC Escher, +Yoji Shinkawa等。此外,你还可以指定具体的绘画形式,比如sketch, +woodblock print, oil painting, +watercolor painting等等。
    • +
    • 描述构图:可以显式指定构图,比如a portrait of, +an ultrawide shot of, a headshot of, +a closeup of等。
    -

    角色的生成

    +

    MJ官方文档:https://midjourney.gitbook.io/docs/

    +

    注册账号

    +

    Midjourney当前作为Discord的内置服务,你可以按照下面的步骤注册账号开始使用:

    +
      +
    1. 登陆官网,点击Join the beta: +
    2. +
    3. 进入后输入昵称,加入Discord,如果你没有discord,可能需要根据提示注册一个,之后进入服务器: +
    4. +
    5. 进入一个以#newbies开头的频道,比如#newbies-117:
    6. +
    7. 在下方的输入框中输入/imagine,此时就能在弹出来的prompt框中输入你想要生成图片的文本描述了,比如我这里输入的是a +white flower is crying,稍等片刻,就能在聊天框中看到生成的4张图像了: +
    8. +
    9. 除了生成的4张图像外,下方还有两行按钮,分别是U1/U2/U3/U4和V1/V2/V3/V4,分别表示增大每张图的分辨率,以及为每张图重新随机生成。在点击增大分辨率之后,对应大图会重新发送在频道中,下方也会随之出现几个新按钮,见字如义: +
    10. +
    11. 如果你不想在公共频道,你也可以自己创建一个频道,然后邀请Midjourney +Bot到你的频道中。首先在左侧点击添加服务器;然后创建一个私有服务器;最后回到Midjourney的官方服务器,找到Bot,点击后把它添加至服务器即可。 +
    12. +
    +

    然后你就可以在你自己的服务器里愉快地玩耍了!

    +

    使用教学

    +

    首先记住下面的公式:

    +

    Prompt = 构图说明 + 画面内容 + 美术风格 + 光影设置 + +其他描述 + 参数列表

    +

    其中,“构图说明”也可以放在“美术风格”后面,但一般来说直接通过a portrait/closeup/wide angle shot of ...指定了。除了“画面内容”是必须的之外,其他的都可以省略。

    +

    建议初学者在这个网站这个网站找对应的关键词,多做尝试。

    +

    构图说明

    +

    构图说明指定是怎样的构图,比如特写、近景、远景等等。有下面基本的构图: +- 特写: closeup, portrait - +全身照:full body, full body portrait - +风景:wide angle, epic composition, +low angle, high angle

    +

    Prompt一般直接用a [composition] of ...开头,其中[composition]就是你选择的构图,比如你想要一个特写,你就可以说a closeup shot of ...或者a headshot portrait of ...;如果你想要一个全身照,你就可以说a full body portrait of ...

    +

    对于风景图,一般不用上述格式,而是直接以内容开头,把构图放在后面,比如vast grassland, wide angle, epic composition,首先说明内容是草原,然后再说用广角镜头和宏大构图。

    +

    下图分别是特写/中景/远景的例子,Prompt为a [composition] of an old asian lady --ar 3:4 --q 1.5,其中[composition]分别替换为closeup shot, +medium shotfull body portrait,同时把宽高比分别设置为3:4, +2:39:16。最后一张图是风景图,Prompt是vast grassland, wide angle, epic composition --q 1.5 --ar 32:9

    +

    +

    你可以看到几种构图之间的差别,至于为什么要更改宽高比,详见下面的参数列表。

    +

    画面内容

    +

    画面内容指定画面内容。该部分根据需求可详可略,但一般都以多个短语组成,比如下面我想以凤凰为原型设计一个角色,全身照,有红色和黄色的花,穿着彩色华丽的装饰,因此输入的Prompt为a full body portrait of a phonix goddess, red and yellow blossoms, wearing rainbow opal accessories, exquisite decorations --ar 9:16

    +

    +

    第一张图加了参数--test,因此细节更加丰富。

    +

    对于非人物也是相同的,比如我现在想设计一个亚特兰蒂斯城,它矗立在悬崖边,有着豪华的建筑,我就可以用the city of Atlantis on steep cliff, enormous beautiful palace, exquisit architecture --aspect 9:32 --q 1.5,得到下面的图:

    +

    +

    前两张图用了--test

    +

    再次强调:描述内容的详略会极大影响生成的结果,越详细,生成的图片会越接近你想象中的画面,但有更大概率质量更低;越简略,越有可能生成非常酷的图片。因此,是否详略取决于你在脑海中是否已经有一个大致的画面,如果你完全没有想法,请尽量保持简略!

    +

    比如对我想要的凤凰角色,我不知道她具体是什么样子的,就只需要输入a full body portrait of a phonix goddess --ar 9:16就可以了,然后再不断添加细节(前两张图是原始Prompt,第三、四张图增加了red and yellow blossoms):

    +

    +

    美术风格

    +

    美术风格指定图片的美术风格是怎样的。美术风格非常重要,它直接决定了图片内容是否与你想象中的相符。我们可以通过三种方法指定美术风格:(1)绘画风格,如realism, +realistic, abstraction, +impressionism, oil painting, +cover art, +comic book等等;(2)艺术家名字,如Rolf Armstrong, +Lois van Baarle, +Aubrey Beardsley等等;(3)与该风格有关的作品/游戏,如breath of the wild, +genshin impact

      -
    • 选择外观、种族、职业、阵营、声音、名字。通过这些选择,让玩家了解游戏玩法与背景,同时限定了一系列数值。
    • +
    • 指定绘画风格:比如现在我想对上面的凤凰角色风格化,我可以指定不同的绘画风格,比如下图是依次指定为realism, +abstraction, watercolor painting, +oil paintingcartoon, anime的结果:
    -

    角色、特征和游戏

    +

      -
    • 角色既包含了审美层面和故事层面的偏好,也涉及战略方面的考虑。人物的特征会影响(约束)其行为。
    • -
    • 但是玩家的风格和喜好决定了角色内在的可能性以怎样的形式表达出来,或怎样被压抑。【如果想要增强角色自身的特征,应该限制玩家的可操作性,如从数值、剧情、环境、探索度等层面。】
    • -
    • 在电脑游戏中,玩家的input和游戏所提供的特征描述之间的互动可能引发不可预测的行为,与某个角色表面的扁平性发生矛盾。因此,仅仅按照设定的属性和特征去描述一个游戏化身或角色是错误的。【可以通过“如果不这么做,游戏就难以进行下去”的思路引导玩家进行特定的操作。】
    • +
    • 指定艺术家:相比指定风格,一个更好的方法是直接指定艺术家,比如我依次指定了下述艺术家Alphonse Mucha, +Alyssa Monks, Andreas Rocha, +Miyazaki HayaoEric Lacombe,所生成的图片是:
    -

    沉浸、卷入与“心流”体验

    +

    +

    你也可以指定多个艺术家,但最好它们风格相似。你可以在这个表里找到一些参考艺术家。

      -
    • 玩家将游戏系统看做一个整体,但是在这一游戏系统中,玩家还必须关注一系列次级系统,那就是角色的行动、武器、物品和技能。
    • -
    • 在文学研究中,沉浸感是指读者所享受到的放弃批判思考的全神贯注。认知心理学的图式理论使我们能够感知周遭的事物并进行有效的处理,这一能力有赖于此前通过阅读、个人经验和别人的建议而建立起来的对类似事件的已有知识储备。【也就是说,沉浸感实际上是一种记忆唤醒机制?】
    • -
    • 只要故事、背景和界面保持统一的图式,玩家的审美体验就能在很大程度上保持沉浸感。
    • -
    • 卷入,是一种经过更多思考的批判式的参与方式。 +
    • 指定相关作品:你还可以显式指定作品,下面的图依次显式指定了作品naruto, +breath of the wild, dark soul, +genshin impactminecraft
    • +
    +

    +

    一般来说,推荐直接指定艺术家,辅之以绘画风格和相关作品,注意这三者之间的风格要尽量保持一致。当混用的时候,艺术家放在前面。

    +

    光影设置

    +

    图片的光影也是重要的一部分,我们可以直接指定光影的类型。比如我们以vast grassland with a lake in the center, a giant tree growing by the lake, --ar 16:9 --q 1.5为基础Prompt,分别考虑下述光影moody lighting, +morning lighting, cinematic lighting, +soft lighting, volumetric lighting, +rembrandt lighting, +godrayschiaroscuro

    +

    +

    除了风景图之外,人物也可以应用不同的光影。下面以a full body portrait of a phoenix goddess, red and yellow blossoms, wearing rainbow opal accessories, exquisite decorations --ar 9:16 --q 1.5为基础Prompt,同样依次加入上面的光影设置:

    +

    +

    可以看到,光影能够影响画面的整体风格,因此,根据内容选择一个合适的光影至关重要。

    +

    其他描述

    +

    除了上面的构成要素外,你也可以增加其他你想要的关键词,大致可分为下面几类。

    +

    材质

    +

    材质(Material/Texture)也可以用来描述画面的整体风格和细节,比如cubic就可能会使画面出现方块状物体。

    +

    下面以a beautiful moon above the desert, the moon is in intricate details, marvel cosmic, Cory Loftis, Conrad Roset, epic composition, low angle, dramatic lighting, spotlight, greyscale, cubic, [material], psychedelic, 8k --ar 2:3 --q 1.5为基础Prompt,分别使用材质cubic, +bronze, carbon fiber, foil, +glass, wood, +liquidsmoke, plume

    +

    +

    可以看到,加入不同的材质会整体或局部地影响画面。carbon fiber使画面增加了颗粒感,glass让月亮出现了玻璃状物体,smoke, plume使得画面出现烟雾。当然这里由于Prompt前面的内容足够丰富了,导致部分材质的影响较小,所以区别不是很明显。

    +

    如果用简单的描述,再搭配材质关键词,效果会更明显些(Prompt为a tree, [material] --ar 9:16):

    +

    +

    颜色

    +

    在Prompt增加一些与颜色有关的关键词有助于生成你想象中的画面。最简单的就是直接添加颜色词,比如red, +black, +blue等等,但这样效果不一定好。一般来说,我们可以增加带有色彩意向的词,比如rainbow, +vibrant, warm color, prismatic, +black and white, monochrome, +high contrast等等。

    +

    下面以a medium shot portrait of a beautiful women in dark green kimono, beautiful face, smile, blue eyes, long black hair, painted by Anne Stokes, rembrandt lighting, [color], ultra detailed, plume --ar 2:3 --s 5000为基础Prompt,分别以vibrant color, +prismatic, black and white, +monochrome, +colorful, rainbow为颜色关键词:

    +

    +

    形状

    +

    你还可以添加形状关键词。这个形状不一定是常见的三角形、正方形,也可以是跟形状有关的物体,比如金字塔pyramid, +星星star,心形heart等等。

    +

    比如以a mountain, [shape] --ar 9:16为基础Prompt,考察下述形状star trapezohedron, +star prism, torus, polygonal, +polyhedron, interior, stellation, +square, heart, gear

    +

    +

    polygon(多边形)是一种常见的风格,interior则会绘制物体的内部。

    +

    其他

    +

    一些其他对画面有帮助的词包括: - +细节程度:very detailed, spectacular details, +ultra detailed, intricate details - +清晰度:4k, 8k, high definition - +景深:depth of field, Canon 50mm - +情绪:enchanting, impressive - +气氛/环境:vintage, retro, +cosmic, celestial, seaside, +lucid dream, plume, Gossamer - +绘法:spatter, drips

    +

    你也可以增加其他的意象词。

    +

    参数列表

    +

    你可以在Prompt的最后添加一些参数,用于生成你想要的图片风格和质量。下面列出所有参数,其中加粗的是最常用的。

    + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数功能
    /imagine呼出prompt,根据文本描述生成四张图片
    /info查看当前正在运行的任务
    /fast(/relax)切换为使用Fast/Relax GPU时间
    /private切换为private模式,其他人不可见你的图片
    /public切换为public模式,其他人可见你的图片
    --hd使用旧算法,适用于抽象和风景图,图片分辨率更高
    --ar 显式指定图片的宽高比,比如 --ar 16:9
    --w 显式指定图片的宽度,比如 --w 320
    --h 显式指定图片的高度,比如 --h 256
    --seed 显式指定种子数
    --no 生成的排除该关键词,比如--no +plants为去掉文本中的”plants”
    --iw 设置prompt中的图片/文本权重比,默认0.25
    --s 指定生成图片的风格化程度,值越大,图片越“抽象”,默认为2500
    --q 指定图片质量,默认为1,值越大,细节越多,但耗时越长
    --chaos 指定图片的随机性,值越大,生成图片越多样,范围[0,100]
    --fast更快地生成图片,但质量会更低,近似于--q +0.5或--q 0.25
    --stop 在n%的时候停止终止生成
    --uplight在Upscale的时候用light版本,增加更少的细节,与原图更接近
    --testp生成更接近现实的图片
    --test生成更多样化、风格化的图片
    +

    指定宽高比:--ar

    +

    --ar指定了生成图片的宽高比,默认为1:1。宽高比会极大影响所生成的图片,比如下面的例子(基础Prompt为Utah teapot, wood --seed 1,从上到下、从左到右分别是宽高比为1:1,2:3,4:9,4:16,3:2,16:9,9:4,16:4): +

    +

    可以看到,对于同样的内容描述,宽高比直接影响所生成的内容,这是因为AI默认会“填满”整个图,所以在设定宽高比时,要注意你要生成的内容是怎样布局的。

    +

    指定风格化程度:--s

    +

    -s指定了图片的风格化程度,或者"天马行空度"。默认值为2500;20000会让你的图片看起来比较抽象,但也没有完全偏离你的prompt;但是60000会让图片完全无视prompt自由发挥。

    +

    下面举几个例子说明(基础Prompt为Utah teapot, wood --ar 16:9 --seed 1,左边是2500,中间是20000,右边是60000):

    +

    +

    可以看到,--s 20000时图片的某些部分已经不符合输入的Prompt里,比如这里丢失了木头材质的信息;--s 60000时就开始放飞自我了。

    +

    对于这个参数,一般来说保持默认即可,如果你想要更多样化的结果,可以用5000~10000之间的值。

    +

    指定细节度:--q

    +

    -q指定了图片的质量,也就是细节的丰富度。默认值为1;2会让图片细节更加丰富,但生成速度也是原来的一半;5会让图片细节爆表,但也有可能导致图片整体效果很差。

    +

    下面举几个例子说明(基础Prompt为Utah teapot, wood --ar 16:9 --seed 1,左边是0.25,中间是1,右边是2):

    +

    +

    可以看到,图片的细节度是递增的。当然这个例子过于简单了,导致细节度高的茶壶反而有点奇怪。

    +

    这个参数我比较喜欢用--q 1.5,谁不喜欢更多细节呢?

    +

    生成更逼真/风格化的图片:--testp, +--test

    +

    --testp让生成的图片更加逼真,而--test会让图片更加风格化。注意这二者都会只输入一张图片而不是通常的四张图。

    +

    下面有个例子(基础Prompt为Japanese house with pink roof --ar 16:9 --seed 1,左边为--testp,右边为--test):

    +

    +

    左侧的房子很逼真,右侧则不完整。当然这个例子可能不够好,但足以说明这两个参数的区别。

    +

    值得注意的是,并不是增加了--testp生成的图片就一定是更现实的,但一般而言是更逼真的。比如你想生成一张二次元萌妹,加了--testp之后反而可能会让萌妹更加仿真,虽然我们都知道她不是现实中存在的。

    +

    加入参考图片

    +

    除了纯文字内容外,Prompt还支持插入图片,让生成的图片在内容和风格上参考给定的图片。

    +

    要插入图片,只需要把图片的链接放在Prompt开头就可以了,比如: +https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Utah_teapot_(solid).stl/1200px-Utah_teapot_(solid).stl.png Utah Teapot --ar 16:9 --seed 1 +这个Prompt最开始的链接就是图片地址,然后就是常规的文本内容,把原图和生成的图片做个对比:

    +

    +

    再对比一下没有参考图生成的图片Utah Teapot --ar 16:9 --seed 1

    +

    +

    显然,有参考图生成的图片在风格和形状上都更接近所提供的图,而没有参考图所生成的图片差异较大。

    +

    此外,你还可以通过参数--iw控制参考图的权重,默认是0.25。下面再分别给出权重为0.5和1时所生成的图:

    +

    +

    可以看到,AI在很努力地模仿参考图的颜色、形状,但仍然颇有难度。一般来说,用默认的数值就可以了,如果你想要参考图的权重更大些,设置为0.5也足够了。

    +

    实战操作

    +

    我们把上面说的综合起来使用给几个例子。

    +

    吉卜力风格的风景

    +

    第一个例子,我想生成一只小船在水村中航行的图,村落有着丰富的细节,吉卜力的风格,同时增加一些晨光。我可以用这个Prompt:A boat ride through a flooded seaside village, beautiful elaborate architecture, painted by Miyazaki, Nausicaa Ghibli, morning lighting, high saturation, spectacular details, epic composition, wide angle, low angle --ar 9:32 --q 1.5,经过几轮比较随意的迭代,我找到下面几张还不错的图:

    +

    +

    黑暗系风格的怪物

    +

    在第二个例子中,我想设计一个黑暗系风格的怪物。女神似乎在一般的作品中是一个正面的形象,那如果是一个腹黑女神呢?从这个出发,我试着尝试让AI画出一个黑暗系的腹黑女神,有白色裙子、邪恶笑容、黑色翅膀和金色花饰,绘画风格偏现实主义,艺术家选定为Dorothea +Tanning。

    +

    最后我把Prompt设定为a full body portrait of a wicked goddness, beautiful white dress, evil smile, red eyes, black wings, shining gold flowers on her hair, concept art, photo realistic, painted by Dorothea Tanning, back lighting, dramatic lighting, greyscale, intricate details, bold brushstrokes, mystical --ar 2:3,给出了下面的几张图(最后两张图使用了--testp):

    +

    +

    上面的图比较明显的不足是人物脸部,尤其是眼睛都没有得到很好的处理,这是当前MJ画全身照的缺点。当我们画半身照人物特写的时候一般没有这个问题。

    +

    蒸汽朋克风格的建筑

    +

    第三个例子,我们想画一个蒸汽朋克风格的建筑,细节越多越好。坐落在水边,有丰富的光影,整体基调呈现暖色。

    +

    因此,我们选用Prompta beautiful magnificent steampuck building by the seaside, view from the sea, rigorous architecture, ultra realistic, epic composition, wide angle, close up, morning lighting, volumetric lighting, warm colors, intricate details, 8K, hd, unreal engine, enchanting --ar 9:32 --test --creative,生成了下面几幅图:

    +

    +

    加入一点艺术家得到下面的图(图一二painted by Earl Norem, Edwin Lord Weeks,图三painted by Elizabeth Shippen Green,图四Ford Madox Brown,图五Farel Dalrymple,图六François Schuiten,图七Franz Marc,图八Georges Rouault):

    +

    +

    在实验的过程中发现:不要将--testp用于风景图,否则会有奇怪的东西;相反,在人物图上用--testp效果很好。

    +

    使用建议

    +

    基于上面的使用方法和我自己的实验,初步建议大家在使用的时候遵循下述规范:

      -
    • 当读者面临不熟悉的题材,或者文本很难左右其反应时,他们被驱使着一再重读或反复斟酌其中的信息。
    • -
    -
  • 沉浸的快感来源于我们伴随某种熟悉图式的退潮和涌动而完全专注其中。卷入的快感则来自我们从文本之外的视点去识别一件作品如何将互相矛盾的图式翻转、连接。【“相互矛盾”可以是新的情节、新的人物、新的动作,总之与既有的图式产生了区别之处。】 +
  • 重视参数--ar!很有时候宽高比会严重影响生成的图片,即使输入的其他内容完全一致。比如你想画个人物肖像,如果你的宽度太小无法容纳一张脸,那么AI就完全不会生成正确的肖像画;而如果宽度太大,则可能会出现多个人或者其他不必要的元素。一般来说,宽高比和画面内容的关系如下:
      -
    • 当屏幕上的场景要求即时的、固定的反应时——比如思考、凝视、阅读、击打、探索、行走——就促使玩家进入沉浸状态。
    • -
    • 当玩家不得不与屏幕上的行为逐渐拉开距离时,就进入卷入的状态。可能是由于角色的特性、一条迷失的小路、一个强大的敌人等。这时候就要寻求解决之道:重复行为——>重新经历——>查找攻略。
    • -
    • 沉浸和卷入相互依赖,玩家在流动性和安逸心情之间切换,游戏世界由此塑造体验。【战神的战斗、探索、叙事是一种沉浸,而其中的解密、情节、道具、新的敌人又是卷入。不断创造卷入,然后将卷入转化为沉浸,再创造新的卷入。
    • +
    • 人物特写/Headshot:使用--ar 1:1或者--ar 3:4,并搭配headshot, +closeup, portrait等关键词
    • +
    • 人物半身照/全身照/角色设计:使用--ar 3:4--ar 9:16,搭配full body, +head and shoulder shot, over the shoulder, +medium shot等关键词
    • +
    • 风景图/远景:使用--ar 16:9,搭配landscape, +establishing shot, epic composition等关键词 +宽高比的选择完全取决于你想要生成怎样的内容,如果你想生成一个竖版的风景图,也完全可以使用--ar 9:16,总的原则就是!!#e06666 +画面内容与宽高比保持一致!!
  • -
  • 随着游戏难度的提高,玩家的应对能力也在进步,游戏需要与玩家的水准相匹配。这时候玩家总说自己“处于巅峰状态”。【战神。】
  • - -

    空间、导航与情绪反应

    -

    《异域镇魂曲》与《寂静岭》

    -
      -
    • 《寂静岭》的音效使之恐怖感上升。
    • -
    • 《寂静岭》的线性结构能让游戏始终保持一定的节奏和紧张感
    • +
    • 重视艺术风格!一个合适的艺术风格可以给你的画面带来极大的改变。当你需要偏现实的风格时,可以尝试realistic, +photo realistic, +ultra realistic等关键词,然后去找合适的现实主义风格的艺术家。当你需要特定的风格时,请精准描述艺术风格,比如浮世绘ukiyo-e,油画oil painting,流行艺术pop art,赛博朋克cyber punk,封面画cover art, +吉卜力Ghibli等等,这需要你对现有的艺术风格有比较丰富的了解!很多时候并不是你画不出来,而是你找不到对应的风格。你可以使用同一风格的多个艺术家作为关键词让画面更加倾向该风格。
    • +
    • 重视参数--test--testp!有时候仅用普通的2*2图片不能得到比较好的结果,尤其是Prompt较长的时候。此时,可以多用一下参数--test--testp,也许会带来意想不到的结果。注意,--testp不要用于风景图。
    • +
    • 重视参考图!尽管本教程没有过多阐述参考图的效果,但是当你手头有很多参考图时,不妨直接使用它们。记得调整参考图的权重--iw
    • +
    • 重视”魔法“关键词!有一些比较通用的关键词,比如intricate details, +unreal engine 5, enchanting, +ornate, after effect, +well composed, elaborate, +Sony Alpha等等,可能会提升画面的细节效果,不妨多试试它们。
    • +
    • 多尝试,出一张效果好的图需要运气,也需要认真地调试。
    -

    导航:迷阵、根茎与迷宫

    -
      -
    • 空间导航有两种模式:迷阵与根茎。 -
        -
      • 迷阵意味着在向唯一的出口有条件地前进,缺点是玩家只能被引导到预先设定的唯一出口。
      • -
      • 根茎并没有特定的方向比其他方向更有利,缺点是结构的缺失。
      • -
      • 游戏当中的迷宫应当处于二者之间:要实现的目标应足够强大,引导玩家前进;同时设定开放式结局,令玩家可自由探索。【巫师三和BOTW的一大共性(实际上Sekiro也是):主线分支化,鼓励玩家自主选择、探索。核心要点是:自由地引导。】
      • -
    • -
    • 恐怖效果地生成总是基于“一个简单而明显地基本公式:怪物使常态遭到威胁。” +

      最后奉上几张AI绘制的浮世绘风格的图片,希望大家使用愉快 ;p

      +

      +

      参考资料

      +

      MJ官方文档
      +关键词参考工具
      +更完整的关键词参考
      +艺术家参考
      +风格参考
      +其他人的作品参考1
      +其他人的作品参考2

      +

      NovelAI不完全使用指南

      +

      太长不看版:使用规范

      +
        +
      1. 首先按照公式 Prompt = 起手叠BUFF + 构图说明 + +画面内容 + 画面风格 + 光影设置 + 颜色设置 + 其他意象 +去写Prompt,具体来说:

          -
        • 《寂静岭》中,常态被怪异之物威胁并摧毁。
        • -
        • 《异域镇魂曲》中,怪物本身就是常态。
        • +
        • 起手叠BUFF:把下面的内容放到你要写的Prompt最前面,起手BUFF还是比较重要的: +{masterpiece}, {best quality}, {ultra-detailed}, illustration, beautiful, 8K, small breasts +最后的small breasts可以换成madium breasts或者其他(你懂的)。
        • +
        • 构图说明:人物在画面中的位置、大小、角度等等,常用的有portrait(特写)、medium shot(半身照)、full bodyupper body(全身照)、dutch angle(倾斜镜头)、wide angle(广角镜头)、side view(从侧面看)、back view(从后面看)等等。
        • +
        • 画面内容:画面里需要包含的各种内容,可以从人物本身和背景两个角度分别描述。人物内容包括头发、脸部、眼睛、肩膀、耳朵、配饰、手、服装、手套、鞋子等等,但首先需要指定包含几个人,比如1 girl, +solo;背景就根据自己的需求增加内容即可,比如dragon background, +forest background, beautiful milkyway, +burning bettlefield等等。此外,你还可以使用关键词reference sheet生成三视图、设计图。
        • +
        • 画面风格:画面的美术风格,常用的包括realistic, +outline, sketch, flat color, +watercolor (medium), grey scale, +ukiyo-e, cover art, poster, +comic, art nouveau, cyberpunk, +sci-fi, wildstyle, 等等。
        • +
        • 光影设置:和MJ一样,设置画面的光影,主要包括:背光backlight, +电影打光cinematic lighting, 圣光holy light, +日光sunlight, 月光moonlight, +波光粼粼glistening light of waves, +金色光golden light等等,你也可以根据需求创造属于你的光影。
        • +
        • 颜色设置:使用颜色关键词让画面整体更偏向某种颜色。
        • +
        • 其他意象:你可以加入任意多的其他意象词为画面添加细节和内容,比如:阳光sunlight, +河流river, 水晶crystal, +棱镜prism, 冰ice, 浮动floating, +照射shine, 影子shadow, +装饰ornament/decoration/frills, 火焰flames, +火花sparks, 光晕flares, +核爆nuclear explosion, +飞溅的血splashing blood, +飞舞的花瓣flying petals, 等等。
      2. -
    -

    游戏文本与遍历函数

    -
      -
    • 呈现于受众面前的称为“脚本单元”:是不同玩家将游戏中的信息“玩出来”的。
    • -
    • 存在于文本之中的称为“文本单元”:是游戏提供的所有潜在信息。
    • -
    • 使脚本单元自文本单元中显露或生成并呈现于玩家面前的机制,叫做“遍历函数”。
    • -
    • 遍历函数的几种变体:活跃性、可确定性、可访性、连接性。 +
    • 把下面的内容写到Undesired +Content中,然后再加入你想屏蔽的其他关键词: +{{{ugly}}},{{{duplicate}}},{{morbid}},{{mutilated}},{{{tranny}}},{breast},mutated hands,{{{poorly drawn hands}}},{{bad anatomy}},{{{bad proportions}}},extra limbs,cloned face,{{{disfigured}}},{{{more than 2 nipples}}},{{{{missing arms}}}},{{{extra legs}}},{{{{{fused fingers}}}}},{{{{{too many fingers}}}}},{{{unclear eyes}}},{{{fused hands}}},{{{fused leg}}},{{{bad feet}}},nsfw,lowers,bad anatomy,bad hands,text,error,missing fingers,extra digit,fewer digits,cropped,worst quality,low quality,normal quality,jpeg artifacts,signature,watermark,username,blurry,bad

    • +
    • Steps默认28,Scale默认为7,当然你可以根据实际需求调整这两个值。Samping使用默认的k_euler_ancestral即可;

    • +
    • 对你比较满意的图使用VariationEnhance,反复迭代,直到满意为止。

    • + +

      概述

      +

      NovelAI是基于Stable +Diffusion模型改进的AI绘画工具,它擅长绘制二次元人物图,虽然也可以把它当作综合性的绘画工具,但是生成的图片偏写实,质量不如Midjourney。

      +

      写NovelAI +Prompt的基本准则是:用关键词(或者称为Tag)描述,而不要用短语甚至句子。关键词包括画面内容(人物头发、眼睛、表情、服饰、姿势、手部、胸部、肩部,等等)、画面风格、构图设置、光影设置、颜色设置、意象词和叠BUFF词等等。

      +

      总的来说,写NovelAI +Prompt相比MJ更容易些,但要实现精准调教仍然难度很大。下面会详细介绍。

      +

      NovelAI官方文档
      +关键词参考

      +

      注册账号(官方)

      +
        +
      1. 登陆官网,注册并登陆账号。

      2. +
      3. 之后在打开的页面上点击“Generate Images”,或者直接通过网页进入:

      4. +
      5. 最后输入Prompt并调整右侧参数开始使用:

      6. +
      +

      本地版本

      +

      To do

      +

      使用教学

      +

      NovelAI的Prompt跟MJ差不多,主要遵循下述公式: Prompt = +起手叠BUFF + 构图说明 + 画面内容 + 画面风格 + 光影设置 + 颜色设置 + +其他意象

      +

      在介绍每个部分之前,需要先讲解下NovelAI各个参数的作用。

      +

      NovelAI的参数

      +

      +

      从上到下,从左到右:

        -
      • 活跃性(与文本单元和脚本单元的数量与稳定性有关):《异域镇魂曲》比《寂静岭》更加活跃少停滞,因为前者任务更多,且一部分是强制性的,而且文本单元更丰富,玩家选择和组建的脚本单元的可能性也都更多。
      • -
      • 可确定性(给定状况相同反应是否总是导致相同的结果):《异域镇魂曲》比《寂静岭》更加不确定。
      • -
      • 可访性(玩家是否能在游戏中任意一点进入游戏文本):《异域镇魂曲》比《寂静岭》可访性更强。
      • -
      • 连接性(文本单元间时空的连接):《异域镇魂曲》比《寂静岭》连接性更强。
      • -
      -
    • 《寂静岭》更加稳定、有节制、更具确定性的特点塑造了它迷阵般的结构。《异域镇魂曲》较富于开放性的遍历模式则表现出如根茎般的扩张趋势。
    • +
    • Prompt:在这个地方输入你的Prompt,使用大括号{}增加一个关键词的权重,使用中括号[]去减少关键词的权重,支持嵌套,比如{{magical}}就表示生成图像的时候会特别关注magical的内容,而[[[green]]]则表示生成时尽量避免生成绿色的内容;
    • +
    • 分辨率:在这里设置你图像的分辨率,可以使用预设,也可以手动输入,这个参数非常重要,同MJ,要和你生成的内容相匹配
    • +
    • Number of images:生成图像的数量;
    • +
    • Undesired +Content:输入不想要AI生成的内容的关键词;
    • +
    • Add Quality Tags:默认勾上就行;
    • +
    • Steps:生成一张图需要的步数,步数越大,生成的时间越长,而且效果也不一定好,一般使用默认值28就好了,除非你已经找到一个很好的Prompt想要增加更多的细节;
    • +
    • Scale:控制所生成图像匹配你输入Prompt的程度,值越小,画面越风格化和柔和,值越大,画面越细节和尖锐,但设置过大可能导致效果变差,一般来说使用小于10的值;
    • +
    • Sampling:生成时的采样方法,一般而言使用默认的即可。
    -

    替身

    -
      -
    • 沉浸分为感知层面的沉浸和心理层面的沉浸。 +

      +

      在生成图像后,会多出来一排选项,其中比较重要的是后面两个:

        -
      • 感知层面:游戏体验垄断了玩家的感觉,如听觉、视觉。
      • -
      • 心理层面:玩家全神贯注地投入到想象中的游戏世界去。
      • -
    • -
    • 《异域镇魂曲》的等距视角和游戏主角本质上的复合性在感知和行为两方面都大大消解了玩家与化身的同一感(削弱了感知层面的沉浸)。但游戏以另一种方式令玩家沉浸其中:大量描述性文本的阅读,以及关于玩家对游戏主角、其作战团队及其物品的巧妙运用的细节信息的缓慢积累。【古剑三】
    • -
    • 《寂静岭》是感知层面的沉浸,各种即时状态。
    • -
    • 《异域镇魂曲》拒绝被匆忙对待,而《寂静岭》催促着玩家从一个地方到另一个地方,抵达终点。
    • +
    • Variations:生成当前图片的变体,在细节上会有不同,但大体都是一样的;
    • +
    • Enhance:对当前图像进行增强,会较显著地增加细节。但注意不要把Noise调太高。
    -

    (更多细节,侧重代入感,带来感知沉浸)小<---------视距--------->大(更多信息,侧重策略性)

    -

    角色扮演

    -

    社会符号学视角

    +

    起手叠BUFF

    +

    NovelAI要把关键信息放在Prompt的前面,因此我们一开始就要叠BUFF,可以先无脑加入下面的BUFF,然后再根据你的需求自行添加: +{masterpiece}, {best quality}, {ultra-detailed}, illustration, beautiful, 8K, small breasts

    +

    注意上面的最后一个BUFFsmall breasts限制了生成角色胸的大小,对于女性角色必须要有(否则全是涩图)!你如果不喜欢平胸,可以用medium breasts,或者你生成的不是女性,就把这个去掉即可。

    +

    构图说明

    +

    和MJ一样,可以用portrait表示特写,用medium shot/upper body表示上半身构图,用full body shot表示全身照。

    +

    除此之外,还可以用dutch angle表示倾斜镜头,用wide angle表示广角镜头,用low angle表示低角镜头,用depth of field增加景深,用side view表示从侧面看,等等。你可以根据自己想象中的内容选择合适的组合。

    +

    !!#3d85c6 这个网站有一些主要的关键词:https://aitag.top/ +。下面的所有内容都可以去参考这个网站,不再赘述。!!

    +

    比如下面我用了一些不同的构图关键词去生成a beautiful girl(关键词分别是portrait, +medium shot, full body shot, +full body shot, dutch angle, +portrait, dutch angle, depth of field, +portrait, side view, +full body shot, back view, +full body shot, from above):

    +

    +

    画面内容

    +

    你首先需要明确图片中包含几个角色,一般来说是一个,那么你只需要加入solo1 girl/1 boy即可。如果是两个,就是two girls,以此类推。

    +

    然后,你需要描述这个角色的各种细节,可以从下面角度考虑(不一定都要,看你需求):

      -
    • 图像语法:再现性(再现这个世界)、互动性(允许文本的作者和读者之间的沟通,以及文本中虚构人物与读者之间的沟通)、组织性(使文本各要素连贯一致,由此组合起来以进一步实现它们承载的含义)。
    • -
    • 多模态理论:文本如何将不同的符号模态——如讲话、书写、声音和图像——组合在一起,游戏是多模态的文本,因此应该思考,动画、视觉设计、音乐、文字文本和声效等多种沟通模态的联合是如何实现前述三个主要功能。
    • +
    • 头发:disheveled hair, floating hair, +azure hair, long hair, +short hair, beautiful hair, +white hair, curly hair, bob hair, +polytails, updo, +twintailsside blunt bangs,等等
    • +
    • 脸部:tears, cold attitude, +smile, sad, annoyed, +delicate beautiful face, +detailed face,等等
    • +
    • 眼睛:Lavender eyes, crystal eyes, +bright eyes, beautiful detailed eyes, +half closed eyes, hollow eyes, +blank stare, rainbow eyes, +gradient eyes, sparking eyes,等等
    • +
    • 肩膀:bare shoulder, off shoulder
    • +
    • 耳朵:pointy ears
    • +
    • 手:outstretched arms, arms behind back, +hands on hips, hand on own face, +hugging own legs, hand in own hair, +holding flowers,等等
    • +
    • 配饰:gold accessories, white lightsaber, +tail, scarf, armor headdress, +ribbon, neck ribbon, hair ribbon, +halo, necklace, wings, +tassel, earrings, wizard hat, +headphone, +red swordfloral print, 等等
    • +
    • 服装:detailed mechanical armor, +detailed organdie dress, skyblue dress, +princess dress with delicate gold metal decorations, +witch dress, white thin detailed cloak, +summer long skirt, angel suit, +very long dress, +translucent fluttering dress with lacekimonotrench coat, +cheongsampettiskirt, +lolita gothicpleated skirt, 等等
    • +
    • 手套/袖子:detailed white gloves, +elbow gloves, sleeveless, +wide sleeves, large top sleeves, 等等
    • +
    • 鞋子:barefoot, thigh boots, +getauwabaki, 等等
    -

    克劳德——大英雄

    +

    建议平时可以多看别人的关键词然后记录下来。

    +

    使用不同的组合并加入不同的权重可以产生你想要的效果,比如下面的例子:

    +

    +

    除了角色本身的细节之外,你还可以指定背景,比如没有背景no background, +以龙为背景dragon background/loong background,以森林为背景forest background,大火为背景fire background/burning background,如下(不同的背景需要不同的权重):

    +

    +

    特别说明:如果你想要生成人物设计图(即三视图),你可以用reference sheet,并同时修改分辨率

    +

    +

    画面风格

    +

    顾名思义,就是需要选择图片的美术风格,下面有一些供参考的风格及其关键词选择:

      -
    • 克劳德这样的角色在相当大的程度上利用了民间文化、口头叙事和罗曼司等传统形式,通过精心构建的寓言故事,为日常生活中的过渡仪式和苦难提供了情感慰藉、道德争论和心灵拷问。
    • -
    • 电脑游戏是被翁称为高科技社会“次级口述”的案例之一,它是口述文化这种思维模式的进化,基础是文学和以技术为媒介的文化。
    • +
    • 写实:realistic, photorealistic
    • +
    • 素描:sketch, rough sketch, +pencil sketch
    • +
    • 描边:outline
    • +
    • 线稿:lineart
    • +
    • 像素:pixel art
    • +
    • 平涂:flat color
    • +
    • 平面着色:flat shading(注意和平涂不一样,下有例子)
    • +
    • 水彩:watercolor (medium), +watercolor pencil (medium)
    • +
    • 单色:monochrome, spot color, +greyscale
    • +
    • 浮世绘:ukiyo-e
    • +
    • 苏维埃海报:soviet poster
    • +
    • 封面:cover art
    • +
    • 漫画书:comic book
    • +
    • 动漫:comic
    • +
    • Q版:chibi
    • +
    • 复古艺术:retro artstyle
    • +
    • 新艺术派:art nouveau
    • +
    • 年代:1970s, 1980s, +1990s
    • +
    • 赛博朋克:cyberpunk
    • +
    • 狂野风:wildstyle
    • +
    • 科幻:sci-fi
    • +
    • 奇幻:fantasy
    • +
    • 传统日本风格:traditional Japanese art
    -

    克劳德——数码傀儡?

    +

    建议把风格使用至少三个大括号{{{}}}甚至更多包裹起来进行强调,确保可以生成正确的风格图。

    +

    你可以选择同一个风格里的多个关键词,或者结合不同的风格。比如你可以融合像素风pixel art和奇幻风fantasy形成像素奇幻风。但最好不要融合超过两种风格,否则生成结果未知。

    +

    下面是一些例子(依次是{{{flat color}}}, +{{{flat shading}}}, +{{{soviet poster}}}, {{{flat color}}}, +{{{outline}}}, {{{sketch}}}, +{{{{{traditional media}}}}}, +{{{ukiyo-e}}}, {{{outline}}}, +art nouveau, +{{{pixel art}}}, {{fantasy}}, +{{{black and white}}}, {outline}, {flat shading}, {flat color}, {concept art}, {lines}, +{{{{wildstyle}}}}, {flat color}, +{{{{{{{{wildstyle}}}}}}}}, {cyberpunk}, {{{outline}}}, +{traditional japanese art}, {anime}, {fantasy}):

    +

    除了显式指定美术风格之外,你还可以指定艺术家和作品让画面偏向某种特定的风格。但是和MJ不同的是,NovelAI并不像MJ那样非常依赖艺术家,一般不加,或者最多只加一个艺术家或作品即可。比如下面我分别指定了ghibili, +Hayao Miyazaki, +breath of the wilddark soul

    +

    +

    可以看到,加入艺术家和作品并没有想象中的那样有效,所以推荐不加。

    +

    注:当然如果你非常熟悉某个艺术家,那加入艺术家也是可以的,但一般来说需要给艺术家比较强的权重模型才会生成比较相似的风格,而且也不是所有艺术家都支持的,还是建议多做尝试。这个表是已记录的一些艺术家,可以根据风格先在谷歌上搜索,然后自行尝试。

    +

    光影设置

    +

    这里的光影设置和MJ是一样的,比如下面的光影: +背光backlight, 电影打光cinematic lighting, +柔和光soft lighting, +体积光volumetric lighting, +点光(聚光灯)spotlight, 圣光holy light, +日光sunlight, 月光moonlight, +波光粼粼glistening light of waves, +金色光golden light

    +

    +

    颜色设置

    +

    颜色没太多好说的,如果你想要画面整体偏某种颜色,直接加入颜色关键词即可。 +但更好的方法是直接指定某个物体的颜色,比如red eyes, +cyan hair,以实现精准控制。有时候需要加大物体的权重,避免这个颜色控制了其他部件。

    +

    其他意象

    +

    其他意象词一般用来增加前景和背景的丰富度,以及人物身上的细节,比如下面的一些关键词: +羽毛feather, 自然nature, +叶子leaves, 阳光sunlight, +河流river, 水晶crystal, +棱镜prism, 冰ice, 齿轮gear, +流动flowing, 浮动floating, +照射shine, 影子shadow, 时钟clock, +装饰ornament/decoration/frills, 火焰flames, +火花sparks, 光晕flares, +核爆nuclear explosion, 闪电lightning, +飞溅的血splashing blood, +飞舞的花瓣flying petals, 微风breeze, +风wind, 雨rain, 云clouds, +烟smoke, 雾mist, 纱yarn, +沙sand, 星尘stardust, +银河milkyway, 旋转swirling, +头骨skull, 骨骼skeleton, +几何geometric, 立方体cubic, +多边形polygon

    +

    总之你可以添加任何你想要在图片中出现的意象词,但要注意和整体画面内容的搭配。你可以通过调整词的权重控制意象出现的频率。

    +

    还是建议找一些相关的参考图和别人给的关键词,多做尝试。

    +

    负面关键词

    +

    负面关键词是你不想让它出现在图片中的内容,填入Undesired +Content中即可。虽然是根据你不想要的内容去选择负面关键词,但是也要一些通用的负面关键词。下面是默认添加的关键词,其他关键词根据需求自行添加: +{{{ugly}}},{{{duplicate}}},{{morbid}},{{mutilated}},{{{tranny}}},{breast},mutated hands,{{{poorly drawn hands}}},{{bad anatomy}},{{{bad proportions}}},extra limbs,cloned face,{{{disfigured}}},{{{more than 2 nipples}}},{{{{missing arms}}}},{{{extra legs}}},{{{{{fused fingers}}}}},{{{{{too many fingers}}}}},{{{unclear eyes}}},{{{fused hands}}},{{{fused leg}}},{{{bad feet}}},nsfw,lowers,bad anatomy,bad hands,text,error,missing fingers,extra digit,fewer digits,cropped,worst quality,low quality,normal quality,jpeg artifacts,signature,watermark,username,blurry,bad

    +

    实战操作

    +

    下面还是给几个实战操作的例子。

    +

    和服风的设计稿

    +

    第一个例子,我们想要一个三视图设计稿,主角是一个穿着和服的传统日本女孩,盘发、头上有红色的花、化妆、精致的手镯、漂亮的印花。因为是设计图,所以要调整下分辨率,用默认的Landscape就好了。因此,我用的Prompt是:{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, beautiful, 8K, small breasts, full body, solo, a japanese girl, {{{{{reference sheet}}}}}, flat color, concept art, brown hair, red flower in hair, {updo}, smile, beautiful face, beautiful makeup, delicate bracelet, {beautiful kimono with intricate floral print}

    +

    下面是生成的一些图(尝试了不同的Steps和Scale,Steps大则细节更丰富,Scale越小则多样性越强,但建议Steps<=40, +Scale>=6。最后一张图给和服加了blue):

    +

    可以看到,人物的手和脚是重灾区,但其他地方还是可以的。另外,活用Enhance能够极大地修复手的问题,关键在于Strength的参数不要太大(0.3左右),Noise设置为0或者非常小。

    +

    机甲少女全身照

    +

    第二个例子,我想要画一个机甲少女的全身照,有着冷酷的表情、红色的眼睛、脸上有纹身、拿着一把红色的刀,我并不太想指定其他过多的元素,但是想要图片的背景是弥漫着硝烟的战场,空中也飞舞着火星。因此,我使用的Prompt是{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, beautiful, 8K, small breasts, full body, depth of field, solo, a mechanical girl, detailed mechanical armor, detailed mechanical body} {holding a red sword}, disheveled hair, short hair, cold stares, half-closed eyes, {{dark red eyes}}, gradient eyes, ruined battlefield background, {detailed background}, burning buildings, splashing sparks, flames, holy light

    +

    下面是生成的图(使用了不同的Steps和Scale,最后四幅图修改了机甲的颜色): +

    +

    狂野赛博艺术图

    +

    作为我们的第三个例子,我们将探索wildstyle这个风格与其他关键词的组合会得到怎样的效果。wildstyle意味着丰富的色彩,尤其是大面积深色的应用。我们将融入赛博朋克的元素,并搭配不同的关键词看AI会给出我们怎样的结果。我使用的基础Prompt是{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, {{{{wildstyle}}}}, beautiful, small breasts, solo, {{a girl}}, cyberpunk

    +

    下面是生成的图(每张图都调整了wildstyle的权重,附加Prompt依次是, +{flat color}, +{{flat color}}, {colorful}, +{{flat color}}, {{outline}}, +sci-fi, +{flat color}, beautiful kimono with cherry floral print, +{flat color}, watercolor (medium), +{{{pixel art}}}):

    +

    结果发现,wildstyleflat color, +outline等关键词搭配效果很好。

    +

    华丽高贵女神范

    +

    第四个例子,我想要得到一个华丽高贵的女神,被白色的花簇拥着,穿着华丽的白色礼服,点缀金色丝边,戴着项链、手镯、花环,蓝色的发光的眼睛。分别尝试不同的构图,即特写、半身、全身,和不同的风格,对背景不做要求。采用的Prompt是{{masterpiece}}, {{best quality}}, {{ultra-detailed}}, illustration, beautiful, 8K, very detailed, small breasts, [composition], [style], solo, a royal goddess, disheveled hair, detailed blue eyes, gradient eyes, glowing eyes, vibrant colorful garland, gorgeous princess dress with delicate gold metal decorations, {{white flower decorations}}, {{surrounded by flowers}}, exquisite bracelet, exquisite necklace, bare foot, {{flowing flowers}}, {{liquid}}。其中,[composition]填写构图,[style]填写风格。

    +

    下面是生成的一些图片(前两张是portrait, +第三四张是head and shoulder shot, +最后四张是full body;风格第一张是cartoon, anime, +第二张realistic, 第三张cartoon, anime, +第四张fantasy, flat shading, +第五张flat color, geometric, cubic, +第六张cartoon, anime, +第七张flat color, flowing,第八张dark magic, Cthulhu): +

    +

    使用建议

      -
    • 将克劳德这样的文本建构视为一种固定的对象却可能导致我们忽视玩家—化身这一重联系,甚至是忽略普遍意义上的文本的含义。
    • -
    • 玩家同时也是一种文化资源,是阐释者,也是粉丝艺术和粉丝写作当中对游戏资源进行改编的人。
    • +
    • 重视分辨率!道理和MJ一样,即图片的分辨率要和想要生成的内容匹配,不再赘述,详细请看MJ页面。
    • +
    • 尝试权重!NovelAI对关键词加权是非常重要的一个操作,有时候你写的关键词没有生效极有可能就是关键词的权重不够导致的,这时候多尝试嵌套几层大括号{{{}}}。一般来说,对
    • +
    • 叠通用BUFF!上面给出了最基础的通用BUFF,但是对某些类型的图来说,还有一些额外的BUFF可以叠,建议多看看对不同的美术风格、画面内容,别人怎么叠BUFF的,总结一套属于自己的BUFF表。之后有时间我也会帮大家总结。
    • +
    • 加入风格!加入风格(包括与风格有关的关键词)会有助于生成你想要的内容,但注意与MJ不同,NovelAI对艺术家的支持并不好,所以尽量不要用艺术家。加入flat shadingflat color偶尔会有奇效,其他的一些意向词比如flowing, +geometric也能创造很好的风格。
    • +
    • 多尝试参数!NovelAI的参数虽然没有MJ多,但是调试更加困难。一般来说用Steps=28, +Scale=7的默认参数能够得到还不错的效果,如果你发现怎么改关键词都不生效的话,果断尝试修改参数吧(当然也有可能是NovelAI的训练集中没有你输入的内容,弃疗吧)!
    -

    化身的操纵

    +

    参考资料

    +

    NovelAI官方文档
    +NovelAI图像生成注意事项
    +关键词参考
    +元素法典——Novel AI +元素魔法全收录(第一卷)

    +]]>
    + + 随笔 + + + 随笔 + 计算机 + 游戏 + 工具 + 绘画 + 深度学习 + +
    + + A Brief Note on Version Control and Project Organization + /2022/11/21/16/03/ + This is a brief note about the e-book Version +Control and Project Organization Best Practice Guide present at +Unite 2022. In this book, we can learn fundamental concepts of version +control and some best practices for organizing a Unity project. If you +are new to Unity, or you prepare to set up a larger scale Unity project, +this may be what you need.

    + +

    Foundational concepts

    -

    多模态的给予与需求

    - -

    文本再创作:网络上的粉丝文化

    - -

    游戏攻略作者

    - -

    虚构文学写作者

    - -

    诗人

    - -

    “三无”漫画家

    -

    结论

    - -

    动机与网络游戏

    -

    再现动机:欢迎来到鲁比卡世界

    - -

    娱乐动机:游戏、目标与策略

    - -

    公共动机:共享鲁比卡世界

    - -

    结论

    - -

    社交性的游戏与学习

    -

    探究游戏的社交性

    - -

    观察玩家

    - -

    游戏

    - -

    玩游戏

    - -

    叙事与游戏

    - -

    结论

    - -

    游戏内外的能动性

    - -

    进入奇异世界

    - -

    对玩家能动性的研究

    - -

    个人能动性

    +

    Best practices +for organizing a Unity project

    -

    代理能动性

    +
  • Folder structure
      -
    • 代理能动性:人们努力以某种手段争取那些拥有资源或技能的人按照他们的意图行动,,以协助他们获得期望的结果。 +
    • Recommendations:
        -
      • 游戏攻略。
      • -
      • 论坛讨论。
      • +
      • Document your naming conventions and folder structure.
      • +
      • Be consistent with your naming convention.
      • +
      • Don't use spaces in file and folder names.
      • +
      • Separate testing or sandbox areas.
      • +
      • Avoid extra folders at the root level.
      • +
      • Keep your internal assets from third-party ones.
    • -
    -

    集体能动性:粉丝作品

    -
      -
    • 文本在粉丝中被认为式一个可以被集体改变、改编和重写的过程,一个未竟的事业,而非静态对象。
    • -
    • 在粉丝艺术家的创作过程中,我们能够看到所有的能动性形式。在某种层次上,帖子表现出个人发挥其能动性和培养个人能力时所带有的焦虑、压力和挑战。粉丝们在对彼此的反馈、建议和专业技能表示支持和学习的过程中,利用了代理能动性。
    • -
    -

    结论

    -
      -
    • 游戏在某种程度上要求甚至依赖玩家能动性的积极发挥。对玩家能动性的关注将引导我们重新评估对以下问题的常规臆断:游戏是什么?谁在生产它?怎样生产?
    • -
    -

    电影、改编与电脑游戏

    -

    恐怖类型——从电影到游戏

    -
      -
    • 恐怖类型携带者“所有口头叙事的印记:主题和母题的自由转换、原型人物和背景设置,以及不断累积的续集、翻拍和模仿。某种意义上,在这个领域当中,没有原创,没有真实的或正确的文本,而只有变体。”
    • -
    -

    改编与《突变怪物》

    -
      -
    • 不可预知的威胁乃至有时无法辨识的敌人及其带来的焦虑,正是为玩家提供的挑战,玩过经过训练即可将之战胜。在从电影到游戏的移植中,其功能和意义均发生了改变。
    • -
    • 游戏设计中最为重要的,是对空间和空间当中物品的设置与安排。
    • -
    • 为已经开发出来的游戏增加一个额外关卡是一回事,而尝试去想象一个尚不存在的游戏的某个关卡是另一回事,后者要困难得多。
    • -
    -

    人物塑造与过场动画

    -
      -
    • 一款好的游戏需要为玩家提供有意义的选择,以及相应可觉察的成果。《突变怪物》的叙事性元素给游戏的目标、任务和障碍提供了背景。
    • -
    • 恐怖游戏的操作应当足够简单,因为这会在相当程度上将玩家限制在其所处的环境中,增加游戏的悬念。
    • -
    • 过场动画分为两种:预制的和实时的。必须对带有预制过场动画的游戏进行周密计划,以避免其对游戏世界的真实感造成破坏。
    • -
    -

    改编——从游戏到游戏

    -
      -
    • 目标是开发一个具有足够普适性的游戏引擎。
    • -
    -

    游戏与性别

    -

    作为再现的游戏

    -
      -
    • 有研究者认为,女性对电脑游戏的疏离主要是因为其再现性因素——游戏中女性化身的外形。
    • -
    • 在很多游戏中,被特别标志的或被边缘化以至于缺席的性别,都是女性。
    • -
    • 如果将电脑游戏视为一种文本,那么将玩家定义为一种性别主体并不可行。
    • -
    -

    娱乐性与再现性

    -
      -
    • 一些游戏强调视觉呈现和故事讲述方式——它们在引人入胜的细节中呈现游戏的场景和角色,我们将之称为游戏的再现层面。
    • -
    -

    性别、游戏与语境

    -
      -
    • 游戏开发商或其发行商如果要争取更多的女性玩家,就要面临失去现有男性玩家的危险。
    • -
    • 那种认为女性对电脑游戏不感兴趣的想法和剥夺女性玩游戏权利的做法已经过时了,尽管某些社会因素和文化因素还将因用户的性别而持续对其产生影响。
    • -
    -

    游戏分析的实践

    -

    定义游戏

    +
  • +
  • The .meta file: it holds information about the file +which it is associated with, e.g., Textures, meshes, audio clips that +have particular import settings.
  • +
  • Naming standards:
      -
    • 目标、障碍、资源、奖赏和惩罚等是电脑游戏的一些重要元素,同时还有一些可获得的不同种类的信息——不管是对于所有玩家,还是对于个别玩家,抑或对于游戏本身——以及这些信息逐渐显露的诸多方式。
    • -
    • 我们也关注到其他有助于探索游戏要素多样性的理论研究方法, +
    • Use descriptive names, not abbreviate.
    • +
    • Use Camel case/Pascal case.
    • +
    • Use underscore sparingly.
    • +
    • Use number suffixes to denote a sequence.
    • +
    • Follow document naming.
    • +
  • +
  • Workflow optimization:
      -
    • 例如,可以探究游戏当中的奖赏与惩罚(游戏的“经济体系”)或游戏当中玩家可控因素与不可控因素之间的制衡关系。
    • -
    • 同样,也可以探索游戏中不同类型的障碍物
    • -
    • 还可以分析不同类型的游戏规则
    • -
    • 它们为我们发现一款游戏的与众不同之处,并促使我们继续思考这种差异是有意义的创新还是对规范的偏离。
    • +
    • Split up your assets: break levels into smaller scenes, using +SceneManager.LoadSceneAsync; break work up into Prefabs +where possible.
    • +
    • Use Preset to save asset settings.
  • -
  • 所有的定义都聚焦于被我们所称的游戏的娱乐层面或“游戏系统”,是它们决定一款游戏是不是可玩,以及游戏活动所遵循的限制。【游戏系统决定了游戏的定义。】
  • -
  • 对电脑游戏的分析既要关注“娱乐性”,也要关注“再现性”,以及二者之间的关系。
  • - -

    游戏类型

    +
  • Code standards
      -
    • 在一个典型的动作冒险游戏中,我们通过扮演游戏内设定的化身来进行游戏,该化身通常会依循特定的游戏顺序克服已被设定的的重重困难。游戏目标通常相当明确,其经济体系一般与可量化的特征相关,比如生命值和弹药。游戏玩法中最核心的是速度和精确性。玩家会在游戏过程中学习一些技巧,但化身却不会成长。【游戏路线是既定的,游戏目标是明确的,游戏玩法是速度和精确度。】
    • -
    • 与之相反,RPG游戏的主角可能是玩家通过一系列选择构建出来的,而且围绕该角色通常会有一个具有特定技能的辅助性团队。玩家可以自由地在游戏中探险,展开各种探索,并且可以不用遵照预设地步骤战胜游戏中的各种障碍。虽然游戏最终目标可能非常明确,但通常会有一些与最终目标未必相关的支线目标。以经验值和物品清单呈现出来的经济体系十分重要,但它更倾向于随玩家的表现而浮动。玩游戏的关键在于策略而非速度,而游戏体验往往具有更多反思性。【游戏路线是未定的,游戏目标是多样的,游戏玩法核心是策略。】
    • -
    • 这两者之间的关键性差异与游戏系统有关,而非在再现层面。
    • +
    • Decide a code standard and stick with it.
    • +
    • When using namespace, break your folder structure up by the +namespace for better organization.
    • +
    • Using a standard header.
    • +
    • Using script templates by creating an +Assets/ScriptTemplates folder.
    • +
    • You can also use your own keywords and replace them with an Editor +script implementing the OnWillCreateAsset method. +
      // /*-------------------------------------------
      // ---------------------------------------------
      // Creation Date: #DATETIME#
      // Author: #DEVELOPER#
      // Description: #PROJECTNAME#
      // ---------------------------------------------
      // -------------------------------------------*/
      using UnityEngine;
      using UnityEditor;
      public class KeywordReplace : UnityEditor .AssetModificationProcessor {

      public static void OnWillCreateAsset (string path)
      {
      path = path.Replace(".meta", "");
      int index = path.LastIndexOf(".");
      if (index < 0)
      return;

      string file = path.Substring(index);
      if (file != ".cs" && file != ".js" && file != ".boo")
      return;

      index = Application.dataPath.LastIndexOf("Assets");
      path = Application.dataPath.Substring(0, index) + path;
      if (!System.IO.File.Exists(path))
      return;

      string fileContent = System.IO.File.ReadAllText(path);

      fileContent = fileContent.Replace("#CREATIONDATE#", System.DateTime.Today.ToString("dd/MM/yy") + "");
      fileContent = fileContent.Replace("#PROJECTNAME#", PlayerSettings.product-Name);
      fileContent = fileContent.Replace("#DEVELOPER#", System.Environment.User-Name);

      System.IO.File.WriteAllText(path, fileContent);
      AssetDatabase.Refresh();
      }
      }
    • +
  • -

    叙事与游戏

    +

    Version control systems

    -

    穿越游戏空间

    +

    +

    Settings up +Unity to work with version control

    -

    游戏动力学

    +
  • Editor project settings
      -
    • 为什么游戏攻略大多采用第二人称祈使语气?因为游戏攻略大都紧密围绕游戏系统撰写,几乎不会注意再现层面,攻略是冷静的和技术性的。粉丝撰写的小说和诗歌都着墨于游戏的再现层面,倾向于借鉴游戏的过场动画,而非游戏本身的互动性元素。
    • +
    • Perforce: Edit -> Project Settings -> Version Control -> +Mode.
    • +
    • Plastic SCM: click the Plastic SCM icon in the toolbar on the top +right in Unity Editor.
    • +
  • +
  • What to ignore: Do not commit the Library folder, as +well as the .exe or .apk files.
  • +
  • Work with large files: teams prefer a centralized workflow where +large binary files would only on a central server with individual users +only accessing the latest version on their machines, rather than a +distributed one where many copies of historical files are stored on +local machines. If using Git, be sure to include Git LFS.
  • -

    走向线上

    +

    Best practices for version +control

    +

    Some suggestions you may need to make teamwork more efficient:

    -

    游戏中的社会生活

    - -

    生产游戏、生产意义

    +
  • Know your toolset
      -
    • 游戏设计者最为关心的问题,正是游戏的娱乐性和再现性之间的相关性和互联性。比如,角色具有再现性和娱乐性,过场动画也有娱乐性从(提供了战略上必不可少的信息)。
    • +
    • Git: UI client
    • +
    • Plastic SCM: Gluon
    • +
    • Perforce Helix Core: built-in Unity Editor tools
    • +
  • +
  • Feature branches and Git Flow: main, hotfix, release, develop, etc. +Both Plastic SCM and Perforce have automated tools to help manage +merging branches back into mainline. Plastic SCM does this with the help +of MergeBot, +and Perforce uses Helix Swarm for +managing code reviews that can also be set up with automated +testing.
  • +

    The biggest takeaway is the importance of clear team communication. +As a team, you need to agree on your guidelines

    ]]>
    - 游戏 - 游戏理论 + 随笔 随笔 - 游戏 + 项目管理
    - ComponentCameraSystem - A Simplified Camera System for You to Create Plentiful Gameplay Camera Movements and Effects - /2023/02/09/23/21/ - ComponentCameraSystem is a simplified, extensible -and designer-friendly camera system for Unreal Engine. It enhances the -built-in spring arm and camera components in native Unreal editor across -a wide variety of common gameplay camera behaviours such as keeping a -target at a fixed screen position, moving on rail, and resolving -occulusion in complex occasions, enabling you to easily create plentiful -smooth camera movements and effects within only few minutes. Go to the -Documentation -for more details.

    -

    Currently ComponentCameraSystem supports Unreal -Engine versions >= 5.0. So before using this plugin, please upgrade -your project to Unreal Engine 5.0 at its minimum version -requirement.

    -

    You can buy this plugin at Unreal Marketplace. -Persistent upgrade will be made to make it more stable and support more -features.

    + Motion Matching -- 概念与发展 + /2022/03/27/08/38/ + 这是我在组内分享的一次关于Motion +Matching基本知识的介绍,放在此备份。

    + +

    Motion +Matching - 概念与发展

    ]]>
    - 游戏 - 相机 + 游戏 - 动画 + 数学 + 随笔 计算机 - UE - 相机 游戏 - 插件 + 动画 + 深度学习 + 机器学习
    - 无穷连根式求极限的充要条件 - /2020/09/09/18/52/ - 在刷习题集或者考试的时候我们经常会遇到诸如或者的极限求解或极限存在性证明。解决此类问题的方法有很多,但都可以归结为一点:缩放。要么是两端缩放然后夹逼定理,要么是证明有界然后两边取极限。本文记录此类问题极限存在的一个充要条件,以供参阅。

    + Which Splines Do You Need? A Comprehensive Dive into Common Splines + /2023/05/03/18/22/ + This post introduces some widely used splines in computer games +including Bézier curves, cubic Hermite splines, Catmull-Rom splines, +B-splines, Kochanek–Bartels splines, etc. We show these splines can be +bridged through re-formulation. Then, we focus on the extension and +generalization of Bézier curves and introduce mathematical methods to +create dynamic smooth splines. Last, we develop a simple Editor in +Unreal Engine to enable easy creation of splines under different +constraints and conditions.

    -

    Ramanujan's Problem

    -

    这类问题最著名的是拉马努金(Ramanujan)所提出的恒等式:

    -
    -

    证明:

    -
    -

    这个等式的证明是简单而有趣的:

    -

    -

    同时,Ramanujan还断言下面的结论:

    -

    -

    这个的证明也是容易的。首先把上式和(1)式比较,就发现上式以3为上界,并且由单调性可知,其极限是存在的。为了证明的极限就是3,我们证明:对任意的,都存在,使得所有的都有

    -

    现在任取,令,故,故有:

    -

    -

    乘进去,就有:

    -

    -

    由于,且存在,当时,有

    -

    -

    把这些全部带入(2)式,就可以证明:

    -

    -

    从而完成证明。

    -

    Polya's Criterion(Polya准则)

    -

    在考虑普遍情况下首先来观察一些特例,一个典型的特例就是形如的无穷根式,每个根号的次数都是,或者幂次都是。对于来看,控制它的幂次是,对于来说,控制它的幂次是,对于来说,控制它的幂次是。假设这个无穷根式极限存在,那么我们关心的肯定是足够大时,它被什么控制,显然是及控制它的的幂次。所以,一个合理的猜测是,如果极限存在,那么该根式就收敛。下面我们将看到,这个猜测已经非常接近“真相”,甚至是真相的一部分。

    -

    Description

    -

    设序列,则可以用下述条件判定:

    -

    -

    上述准则还可以进一步推广为:

    -
    -

    序列收敛的充要条件是: -

    -
    -

    注意到,这个极限可以取有限数或者负无穷。我们将在陈述下面的定理一之后进行证明。

    -
    -

    (定理一) 序列收敛当且仅当存在有限上极限 -

    -
    -

    首先证明必要性,即假定收敛。因为,故一定是有限的,得证。

    -

    再来证明充分性。假定,则存在使得对所有,有,因此。从而有:

    -

    -

    同时又因为

    -

    -

    从而有,又由的单调性知收敛。

    -

    到此为止,我们发现定理一和开始我们的猜测是非常相似的,只是定理一只需要上极限,这比我们的猜测更加宽松。下面我们利用此定理证明Polya's -Criterion.

    -

    Proof of Polya's Criterion

    -

    时,存在,当,也即,由定理一收敛。

    -

    时,存在某个,对某些无限的,使得,也即。因此,对这些而言:

    -

    -

    因此.

    -

    最后考虑

    -

    收敛,则有限,即存在对所有成立,因而。此时若,则

    -

    -

    而当时,按照约定有,则综上公式(3)的必要性得证。

    -

    同时公式(3)也是充分的。假定条件成立但不收敛,则由定理一,则对任意的,有充分大的使得,从而,于是有

    -

    -

    这说明上极限是无穷大,与假设矛盾。充分性得证。

    -

    Examples

    -

    例一

    -

    现在我们考虑一个序列,当的时候,它的上界是,而后者我们上面已经证明了它的上界是2。现在我们考虑的情景。此时有:

    -

    -

    所以我们证明了,对,序列都是收敛的,并且没有使用定理一

    -

    例二

    -

    现在考虑下述恒等式:

    -

    -

    于是可以立即得到:

    -

    -

    现在令,就有:

    -

    -

    替换,有:

    -

    -

    两边约去2,就有:

    -

    -

    例三

    -

    由余弦二倍角公式可知:

    -

    -

    此时令,就有:

    -

    -

    所以可以立刻得到下式的极限:

    -

    -

    Herschfeld’s -Convergence Theorem (Herschfeld收敛定理)

    -

    Polya's Criterion只考虑了指数为的情况,对于更加普遍的情况,即形如的序列,Herschfeld’s Convergence -Theorem给出了一个其收敛的充要条件。

    -

    Herschfeld’s -Convergence Theorem 告诉我们了一个无穷根式收敛的充要条件:

    -
    -

    设序列且级数收敛,则序列收敛的充分必要条件是:

    -
    -

    这个定理的证明之后有空了补充。

    -

    后记

    -

    实际上无穷根式分为右无穷根式(Right Infinite -Radicals)和左无穷根式(Left Infinite -Radicals)两种,这里重点讨论的是右无穷根式的情况,左无穷根式可以仿照进行推导。

    +

    Common Splines

    +

    Bézier Curve

    +

    The most typical and widely-used spline might be Bézier curves. +Bézier curve leverages a set of control points to define a smooth and +continuous curve generated by interpolation between these control +points. Using the De Casteljau's algorithm,1 we +can easily express a Bézier curve in terms of a sum of Bernstein +polynomials:

    +

    +

    When there are four control points, the generated curve is called +cubic Bézier curve. A cubic Bézier curve can be expanded as:

    +

    +

    The derivative of an -th order +curve is:

    +

    +

    Similarly, we can obtain the second-order derivative:

    +

    +

    We will use these results later soon.

    +

    Degree elevation

    +

    Suppose is an +-th order Bézier curve and we want +to elevate its degree to . We +can do this via the following process:

    +

    +

    Note that when , , and when +, . So + and can be arbitrary. We +simply set them to zero.

    +

    Composite Bézier curves

    +

    A composite Bézier curve is a series of Bézier curves joined end to +end where the first point of one curve coincides with the last point of +the previous curve. If a Bézier curve is composite, we say it's continuous.

    +

    However, sometimes we want higher degrees of continuity than at the joint of Bézier +curves (note that individual curves are within their own +inteval, and the discontinuity only happens at the meetings of +consecutive curves).

    +

    Given two Bézier curves +and , +we can define different degrees of continuity at :

    +
      +
    • +(positional continuity): consecutive Bézier curves meet at the same +point. This holds by definition. In this case, it's .

    • +
    • (velocity +continuity): the incoming and outgoing derivatives of are the same, vouching for a +smooth transition from the first curve to the second. To show this, we +let , +and the solution is . +This gives us . +This equation tells us that and are not only colinear with +respect to , but their +vector lengths are also the same. Rewriting this equation to +suggests is fully +determined by and + if we want continuity.

    • +
    • (tangent +continuity): and are colinear but not +requiring their vector lengths to be equal. Thus, we say is less strict than . If a composite curve is +, then it must be . To guarantee , we just add an extra degree +of freedom to the vector length: . + means the two curves +share a common tangent direction at the join point.

    • +
    • (acceleration +continuity): following a similar process to continuity, the continuity can be defined by +. +That is to say, is +fully determined by and . You should be very careful +of using continuity: +the continuity causes +a loss of two control points and , leaving only one free +control point . You +perhaps cannot get the curve shape you expect. If you do not want to +loss control over these points, you can use uniform B-splines, which +will be introduced later.

    • +
    • (curvature +continuity): this type of continuity requires +except requiring , +i.e., satisfying . +To obtain this result, first expand +and then plug +in. Last, substitute for with + and with , and you will get the +right formula. Curvature continuity implies that the curves share a +common center of curvature at the join point.

    • +
    • (jolt +continuity): if a composite Bézier curve is , it satisfies . +In this case, the fist curve full determines the second curve and thus +the third, forth curve, etc. Now we say the generated composite Bézier +curve is as there +is indeed no joins.

    • +
    +

    If a curve is , then +it must be . If a curve +is , then +it must be .

    +

    Rational Bézier curves

    +

    +

    Approximating circular arcs

    +

    A cubic Bézier curve can be used to approximate a circular arc. Let's +first start with a simple case: the arc starts at point and ends at points , placed at equal distances +above and below the -axis in the +first quadrant, spanning an arc of angle . The radius is .

    +

    Assume the additional control points are and , and their indices are +respectively and . Note that , or .

    +

    According to the expanded Bézier curve expression:

    +

    +

    we have , +which gives:

    +

    +

    On the other hand, according to the derivative of a cubic Bézier +curve , +we know the derivative at is +. It +is equal to the tangent at multiplied by some coefficient +:

    +

    +

    Now we've obtained the control points and .

    +

    What about and are not symmetrical? Assume +the angle of is and the angle spanned by the arc +is , where the end point is +. We can first rotate +both and by . This +now becomes the case discussed above. We can calculate the index of + after being +rotated:

    +

    +

    Now we can follow the aforementioned process to calculate the control +points:

    +

    +

    Last, we rotate and back to the +original positions:

    +

    +

    The three-dimension case is more complicated.

    +

    Cubic Hermite splines

    +

    Cubic Hermite splines construct a curve based on two points along +with their respecive tangents.

    +

    Suppose the given starting point is at and ending point at , as well as the starting tangent + and . The fitted cubic polynomial +can be defined by:

    +

    +

    Proof is quite simple. Assume our function is , and given +that , we have:

    +

    +

    Solving it gives us:

    +

    +

    Rearranging gives +the equation proposed at the beginning.

    +

    We can also reformulate in terms of Bézier curves +with respect to the four control points . To show +this, recall that a cubic Bézier curve can be expresses as:

    +

    +

    We can rewrite as +follows:

    +

    +

    This shows that a cubic Bézier curve that patches the control points +in the middle determines the tangents of the interpolation curve at the +respective outer points.2

    +

    B-splines

    +

    Non-uniform rational +B-spline (NURBS)

    +

    Beta-splines

    +

    Catmull-Rom splines

    +

    Connections between Splines

    +
    +
    +
      +
    1. https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm↩︎

    2. +
    3. https://en.wikipedia.org/wiki/Cubic_Hermite_spline↩︎

    4. +
    +
    ]]>
    - 数学 - 数学分析 + 数学 - 图形学 数学 随笔 + 计算机 + 动画 + Spline + Curve + 曲线 + 插值
    - 巫师三:一个告诉你原来游戏可以是艺术品的神作 - /2020/10/09/19/34/ - 巫师三是一款已经被时间证明的,当之无愧的神作。巫师三没有波澜壮阔气势浩天的景致,却有风格迥异人文色彩浓厚的地区特色。威伦的破败荒凉贫穷凄苦,为了一双鞋可以连父母都能出卖;诺威格瑞的大城风范,有日进斗金的土豪乡绅,也有困守城中的穷困百姓,女巫猎人穿梭其中,种族矛盾暗流涌动;史凯利杰群岛的剽悍民风,对外来者的敌视,对入侵者的抵御,捍卫土地的决心让诸多岛屿团结在一起;凯尔莫罕的静谧安详,森林环抱狼堡,猎魔人镇守故乡,仿佛出世的仙境,危机四伏但又简单质朴;陶森特的梦幻美丽,人们自得其乐,生活在这宛若仙境的城都中。不仅仅是景色,巫师三更是以它的剧情和对人物的刻画出名,抛开难以入流的战斗系统,单凭巫师三对剧情的把控、对人物的描写和对画面的雕琢,就足以令这部游戏称为艺术品。在经历了完整的主线和DLC流程后,几乎没有玩家会给巫师三一个低分,尽管它有瑕疵,但是它在剧情、人物和画面上已经到达巅峰造极的水平了,更难能可贵的是,这三者完美融合,在体验游戏的同时,给予玩家美的享受、身心的震撼。这是奥德赛无法比拟的,也是大多数游戏难以企及的高度。

    + 《Assassain's Creed Odyssey》玩后感 + /2020/09/08/18/39/ + 115小时,主线+两个DLC通关。奥德赛是一个优秀的游戏,但不是神作,在走向RPG的道路上是系列作品的里程碑。人物塑造方面,奥德赛无疑是成功的,由于我选择的是温情 +路线,所以我看到的马拉卡的内心是无比渴望家庭的温暖的,正如奥德赛音乐集的“Odyssey(Modern +Version)”中的歌词"Travel in path alone, back to the warmth of +home"一般,踏在异乡的每一步无一不通往家。本作两个主要配角Phoibe和Brasidas,都令人印象深刻。在画面上,优良的美工沿袭了育碧式BUG,有可能在欣赏风景的时候会卡到墙里面,有时候还挺扫兴的。值得一提的是,奥德赛对希腊风情的刻画非常优秀,每一个同步点都可以疯狂截图作壁纸。本作比较难受的地方是剧情,三条主线除了家庭线比较完整之外,另外两条主线都虎头蛇尾,过多的无用支线严重稀释了主线的紧凑感,让人在玩到一半之后想去玩巫师三。DLC1的整体剧情我个人比较喜欢,但是一些细节处理尤其不妥,动机不足导致DLC1评分降低。DLC2流程很长,总体来说冥界剧情好于亚特兰蒂斯剧情好于极乐世界,不过对神之领域的描绘总体来说很精彩。如果说我对11.10发售的英灵殿有什么值得期待的话,可以用几句话总结:剧情不要拉跨,任务尽量优化;BUG可以少些,卡墙不动尴尬;风景依旧如画,壮汉赶紧来吧!

    -

    前言

    -

    由于巫师三的世界观过于宏大,一篇未经雕琢的读后感不能道尽巫师三的所有优点,故本文旨在从宏观上呈现巫师三是如何完美统一任务、节奏与剧情这三者的。至于其他的,我们有机会留在以后再说。我相信,通关巫师三的玩家,一定会承认巫师三在任务的组织和剧情的展开上非常连贯丝滑,而且剧情上的节奏递进、叙述上的跌宕起伏都让人回味无穷。游戏本质是在讲故事,但是巫师三成功地给予了玩家沉浸式的体验,也就是,我们从观众的角色深入到了主角的角色,从游戏外的世界走进了游戏内的世界,仿佛每个人都是真实可及的,都是有血有肉的,都是有情有义的。那么,如何讲好这个故事,把观众代入到游戏中,就是巫师三不同于其他游戏的关键所在,这也是这篇玩后感的主要内容。

    -
    -被附身的Geralt帅中泄露出一丝痞气 - -
    -

    主线为林,支线为溪

    -

    巫师三的一大特色就是它的任务系统非常丰富,从表层看,巫师三的主线只有一个——寻找女儿,但是,在每个地区,都会有非常多的支线为主线提供背景。就好比一个建筑,主线是骨架,支撑起整个游戏的大致轮廓,而支线是钢筋水泥,垒起了整个建筑的最终格局。当然玩家可以只做主线不做支线,但我相信如果不做支线,这个游戏的乐趣就会少一半。

    +

    剧情:整体精彩,细节拉跨

    +

    自奥德赛发行以来,“剧情”一直是被玩家广为诟病的一点,但是在做完所有任务(包括两个DLC)、体验完所有剧情之后,我倒是觉得奥德赛的剧情整体上非常优秀,但是和大多数玩家一样,我也想吐槽其中非常多的细节,我思考了一下,这大概是出于一种“恨铁不成钢”的心理。明明奥德赛的剧情可以做得非常棒,可以几无瑕疵,可以触及巫师三,但是阿育就是把这么一个差一点点就堪比完美的剧本甩到玩家脸上,香还是香的,但就是不情愿,被迫品尝一桌盛宴中编剧埋下的一坨坨屎。

    +

    世界观

    +

    奥德赛的世界观是建立在希腊伯罗奔尼撒战争期间,但显然,奥德赛不完全是一部纪实游戏,战争只是游戏的大背景,也是游戏开始的一个引子而已,到了后面,游戏的进展其实和战争已经没什么太大关系了。在这个大背景下,著名的时代人物,如伯里克利、苏格拉底、布拉西达斯都会悉数出场并成为推进主线过程中重要的人物,而另一大群体,“神教”,正贯穿了整个主线的发展。主角的冒险由神教展开,也从神教结束,神教作为核心暗线而存在,我们把它称为神教线。而剧情的实际主线则是马拉卡找家人的旅程,在途中,主角会踏遍希腊,经历诸多精彩的故事,最终找到家人,在若干年后再次相聚,我们把它称为家庭线。除此之外,奥德赛中还引入了很多神话元素,比如传奇动物、传奇生物、神之领域(主要在DLC2),它们以“神器”联系起来,游戏进行到中后期会出现一条新的主线,也就是让主角去搜集神器,我们称之为神器线

    -父女之间的亲昵 - +奥德赛的地图很大 +
    -

    说到支线繁多,一个典型的对比就是刺客信条奥德赛。同样有非常多的支线,但是从我个人的游玩体验来说,我宁愿无视奥德赛的90%的支线,直接一条路走完主线,但是巫师三的支线不然,玩家会有强烈的意愿去做大部分支线,在做支线的过程中解锁问号,发掘游戏中隐藏的剧情,是巫师三最为亮眼的一大特色。如果要对比巫师三和奥德赛的任务系统,可以从下面几个方面评价:

    -
      -
    • 支线多样化:巫师三的支线是多样的,支线之间没有重复,猎魔人委托可能会更无聊一点,但生意人的事情嘛,不寒碜。除了猎魔人委托之外,寻宝任务有解密探险要素,区域日常支线有搞笑奇葩要素,重要支线甚至会改变整个巫师三世界格局。然而,奥德赛的支线是单调的,支线的选择不会影响主线的进程,支线品类非常单一,并且缺乏逻辑。巫师三支线给玩家的动力是充分的:委托赚钱,寻宝得装备,日常支线放松一下,重要支线扣人心弦;而奥德赛不是的,除了几个从头到尾都有的支线之外(类似于巫师三的寻宝任务),其他的支线毫无意义,既对主线没有补益,而且也缺乏特色。
    • -
    • 支线重要化:当然,支线多样丰富是一方面,更重要的是,支线是需要起到作用的,有时候甚至是决定性的作用。巫师三的主线和支线的分工相当明确:主线用来推进整个游戏进程,而支线则负责主线缺失的娱乐性与严肃性。这大大补充了单主线的贫乏,让玩家在游戏的时候不会觉得推进主线是无聊的,因为在同时还有大量丰富有趣的支线在支撑游戏的饱满度。而且,巫师三的支线并不是其他游戏中如过往云烟般的支线,而是不同的支线会在主线的不同时间点产生决定性的影响。比如,迪胖的支线会决定整个游戏最终的政治格局,这是从大了讲。从小了讲,如果细心留意,就会发现很多很多支线都涉及到游戏中不同人物的命运,即使是路人,我们也能够感到他们是真实的,而不仅仅是一堆数据。这些都是支线带来的重要积极影响。巫师三赋予了支线游戏的精神内核,并令其成为承载游戏厚度的“实力担当”。
    • -
    +

    所以,总的来说,奥德赛的世界观就是在希腊伯罗奔尼撒战争的时代大背景下,以家庭线为明线,以神教线为暗线,以神器线为辅线而展开的。在游戏进行过程中,主角会见证真实的历史,会体验各地的风俗,会欣赏希腊的风光,会体验人生的波折。奥德赛的世界观即是如此的宏大,在游戏策划的精心编排下将希腊的大观悉数摆在我们面前,同时又让玩家以小人物的视角代入到如画的场景中,如此结合,让玩家一旦进入到角色里,就很难立刻停下来。

    +

    然而,相比起源把一桌菜一股脑全给你端上来又不介绍菜品让你细细琢磨、品尝,奥德赛更像是古典西餐厅里的一盘盘端上精心调制的菜品并为你介绍菜的制作方式、选用食材、食用步骤,甚至还要告诉你在品尝之前要沐浴更衣精心打扮,这就会产生下面要说的一个问题,大而不精,野心太大但却没有把握住剧情开展的主次,导致剧情上连贯性的断裂,这进而引发一个很严重的问题:游戏进展到后期同质化严重,玩家的游戏热情被大幅度削减。就好比前几道菜都详细介绍,食客会觉得很高端很优秀,但是如果有几十道菜,每个都如此呢?食客就会厌烦。

    +

    任务

    +

    剧情是通过任务推进的。任何一个游戏,都有任务,完成了任务,尤其是主线任务,才能顺利推进到下一个剧情节点。可以说,任务是推进主线的首要手段(并非唯一,比如在奥德赛中,满屏幕的问号“?”也是一个手段)。

    +

    上面我们已经简单说了,奥德赛的主线可以分为三条:家庭线、神教线和神器线。家庭线和神教线是从头贯穿到尾的,二者并行,一明一暗互为依托,这样的设计是很好的:它既不会让游戏快速陷入单线游戏的乏味,也能营造剧情上汹波暗涌的气氛,很快抓住玩家让玩家进入角色。这里值得表扬的是本作家庭线和神教线的融合是非常到位的,二者不但是并行关系,而且是交叉关系,如同螺旋前进的两条线一样,共同推动了游戏剧情的发展。但是,第三条线神器线的出现大大打破了这一节奏,甚至是原本剧情的美感。在家庭线达到关键节点找到母亲后,本来以来父亲的出现会解释玩家所有的疑问,但是没想到,老父亲一出场就让玩家莫名其妙地搜集神器,没有半点前因后果的交代;在找到神器之后,又莫名其妙出现了古代与现代的时空错乱和穿越,我们的主角马拉卡又莫名其妙地活到了现代穿上了西服最终溘然长逝。说实话,我当时玩到这一段的时候几乎是快进过的,没有丝毫欣赏剧情的欲望。这一条线从一开始,到最后,只能用四个字去总结:说的是啥?尽管这一主线流程很短,但它的出现极大割裂了另外两条主线的连续感,也造成了马拉卡精分的错觉,让玩家搞不明白奥德赛的时间线究竟是如何排布的。

    +

    当然,家庭线和神教线不是没有问题,而且在很多细节之处都有槽点。比如家庭线的一大槽点就是,如果你走的是大团圆路线,你就会发现马拉卡过于圣母(没错,就是我)。诚然马拉卡是一个呆萌渴望家庭温暖外表冷漠内心火热的失足少年,但是当自己的妹妹残忍地杀害基友Brasidas,造了无数的孽后,马拉卡依然选择了原谅她,最后还能和继父、表弟在一个桌子上吃饭,我的内心无疑是充满了问号。你可以说,这是你自己选择的剧情啊!对,但是当玩家选择了这个剧情之后,我们会明显感觉到这个剧情是不尽合理的,也就是说,制作人在设计这一剧情路线的时候就没有仔细推敲其合理性,所以这个锅还要阿育来背。神教线的槽点就更多了,各种奇葩的神教成员(包括那个自爆身份好像老子不怕你的那个)一个接一个,最后鬼魅那段单口相声真的是漏洞百出,竟然还可以选择相信她,而且无论你选择什么,神教线都会到此为止,那又何必再做选项呢。

    -这样有趣的小支线在巫师三里不胜枚举 - + +
    鬼魅的最后一个线索才是“女性”,不然很好猜
    +

    除了主线之外,奥德赛的一大尤为突出的问题是,支线任务过多,而且过于无聊。在奥德赛中,除了标有黄色感叹号的关键支线之外,其他大部分支线都是在端茶倒水、洞穴找人、团灭兵营,基本上可以概括为:“我丈夫/妻子/兄弟/孩子不听我话跑出去不见了/被强盗抓住了,他可能在某某树林/洞穴/兵营里,你能帮我找到他吗”。刚开始玩用来点亮地图确实还不错,而且可以熟悉技能,提高操作,但是当游戏进行到中后期时,满屏幕的感叹号让你没有丝毫欲望去清空,因为你知道打不打都无所谓,对主线毫无影响,给的物品也毫无吸引力。也许制作者的初衷就是让玩家在打完主线之后再慢慢清支线,但实际上,对于一部分强迫症玩家来说,满屏幕没清又强行按捺自己去清欲望的想法的确是非常痛苦的,最终的归宿可能只有隐藏地图标记才能解救他们。尽管对总的剧情没有太大影响,然而过多的冗余支线就好比蒙娜丽莎嘴角沾了米粒,赫拉脸上长满痘痘,人还是那个人,但味道总觉得变了。

    +

    但另一方面,也不得不表扬一些支线的确做得很有意思。比如“失落的希腊神话”系列任务就很有意思(尤其是“倒霉的一天”),此外,雅典区的一系列支线也很有特色(苏格拉底与雅典炮王的任务),还有一开始瘟疫的支线,这些支线要么本来在内容上非常丰富、有趣,要么会影响后续的剧情,这就回到了支线的作用:需要给予玩家一定的反馈。如果做完一个支线,玩家什么都没有得到,什么反馈都没有,那做这个支线干什么呢?看风景吗?所以,我认为如果把神器线做成一个系列支线,那效果可能就会好很多。如果删掉其中80%的无用的没有任何反馈的支线,说不定奥德赛的IGN评分又会更高。

    +

    可以看得出来,奥德赛在任务系统上有浓重的借鉴巫师三的痕迹,主要体现在剧情选项和支线系统。支线系统我们已经上面已经说了,和巫师三一样都有很多支线,但是巫师三的支线是它被称为神作的原因,奥德赛的支线只有东施效颦的副作用,究其原因,还是二者对支线作用的理解不同。

    +

    剧情可选是奥德赛在整个刺客细条系列中的一大突破,也是效仿巫师三最典型的一个要素。为什么我们需要可选剧情?因为这可以给玩家更多的自由度,让玩家能够更好地带入剧情,玩家需要为每一个决定负责,从而就要深思熟虑,剧情选择引发的蝴蝶效应足以在游戏结局的时候升华玩家对整个游戏的评价和感悟。巫师三做到了,奥德赛没做到。这有几点:

      -
    • 支线惊奇化。巫师三的支线时常给人一种惊奇的感觉,无论是之前无意之中做的支线会在后来的某一天发现原来会产生这样的影响,还是后来做到的支线会发现是之前剧情的关键结果,这种突如其来的“因果”呈现都带给玩家游戏体验上的冲击。重点是,正所谓大音希声,这样的惊奇化支线完全不需要漫长的铺垫,而只需要一个小小的“接口”,把因果串联起来就可以达到这样震撼的效果。一个典型的例子就是在DLC石之心里,拍卖行里的一个小支线展现了维瑟米尔的不为人知的一面,不但极大丰富了人物形象,而且还带给玩家无尽的唏嘘。此类四两拨千斤的支线在巫师三里比比皆是,
    • +
    • 奥德赛大部分选项不会对后面的游戏剧情有所影响;
    • +
    • 可选项非常少,玩家可能面对哪个都不想选但又不得不选的尴尬境地;
    • +
    • 选择之后的剧情推进和想象的不一样。
    +

    从我个人的游戏体验来说,上面三点是奥德赛在“剧情开放”尝试中最为突出的问题,我相信也是大部分玩家承认的问题。奥德赛的最终结局只有几种,而决定这几种结局的选项在几十个小时的游戏中只有寥寥几个地方,那其他的无数选项的作用是什么呢?第二,奥德赛每次可选的大概在3~5个选项之间,而给出的所有选项有时候又都非常智障,明明哪个都不想选却偏要选一个,这对玩家非常不友好,有种强行喂食的感觉。第三,剧情总是朝着意料之外的发展。比如有个任务是关于贩夫的未婚妻,这个时候就不能骗她说贩夫被干掉了,否则直接导致任务失败;而有的时候又需要你假惺惺地欺骗一下NPC才能完成任务,这种任务设定毫无规律可循,遇到了大概率就是一脸懵逼然后呵呵一笑。综上,剧情上的自由可选,就奥德赛的表现来看,反而是禁锢了玩家的自由度,看似让玩家有更多决定剧情走向的权利,但实际上是画地为牢,无论怎么选,都圈定在了编剧预先定义好的条条框框里了。显然,这是一种非常不成熟、宁可没有的设计。当然了,作为向巫师三学习并处于刺客信条系列发展史的一部过渡作品,奥德赛牛刀小试也无可厚非,只是希望英灵殿能够在这上面进行改进。

    +

    最后来说一下两个DLC。网上普遍对DLC1的剧情诟病颇深,对DLC2倒是赞誉更多,不过我个人倒是觉得,DLC1的剧情高度比DLC2更高,但是下限也比DLC2低,而DLC2发挥整体非常平稳。但从剧情上讲,我个人更喜欢DLC1,尽管它有非常突出的硬伤。

    +

    DLC1的剧情整体上非常棒,前提你玩的是Alexios(据说Cassandra体验非常不好)。游戏流程不长,十个小时以内可以打完,但是任务节奏很紧凑,内容相对丰富,关键是剧本很给力,讲述了马拉卡遇到真爱但是又被命运无情摧毁的故事。在这个DLC里,我看到了马拉卡内心的脆弱,尤其是他对家庭温暖的渴望与期盼。其实,在玩游戏本体的时候,我们会经常听到马拉卡感慨自己的命运,我印象中比较深刻的是“要是我不离开凯法隆尼亚岛就好了”,再回忆片头马拉卡独自坐在房上抚摸着断矛,他一定非常渴望再见到亲人吧。虽然在凯法隆尼亚岛上,他可能永远也见不到亲人,但是,有Markos,有Phoibe,还有岛上其他的伙伴,这样的小日子,不也很美好吗,正如他与DLC1的女主相遇相知相爱后,与岳父大流士、自己的孩子四人一起生活在村里,平淡而温馨,甜蜜又幸福,不也正是马拉卡一直想要的生活吗。做一个漂流在外四海为家的佣兵并不可怕,可怕的是这样的人却时刻想要有一个稳定幸福的小家庭,这简直是一种无法企及的奢望。当上古维序者干掉女主,马拉卡在火海中呼唤着她的名字时,当马拉卡来到家门口的她的坟墓前时,当马拉卡之后到他们相知的三个地方寻找纪念物时,当最后马拉卡把孩子托付给岳父大流士看着他乘帆远去时,当最后的最后马拉卡仍旧时孤身一人时,我心中的确是被深深触动了。这是我非常喜欢DLC1的点。

    +

    但是也正如上面所说,DLC1的上限很高,下限也很低,主要仍然体现在细节不到位。比如火海救岳父的情节,作为一个久经沙场的佣兵,他应该是完全能够意识到将妻子儿子丢在船边会有什么后果,就算不能两边兼顾,也应该知道孰轻孰重。再有最后送走儿子的桥段结束得过于仓促,上古维序者这个组织的行为动机也不够充分,在很多地方,玩家是没有办法选择剧情的走向的,也就不得不被迫喂屎,这也是DLC1被广大玩家吐槽的原因所在。但我个人认为,DLC1仍然是瑕不掩瑜的,对于部分玩家而言依旧有非常高的可玩性。

    -一个非常小的细节,但是却折射出了两个饱满的人物形象 - -
    -
    -一个非常小的细节,但是却折射出了两个饱满的人物形象 - -
    -

    所以,巫师三成功的一大关键因素就在于他巧思的任务系统,尤以支线为代表,主线与支线的交织,主线推动整个剧情的发展。支线却承载了多样化、重要化和惊奇化的具体内容,让人家流连忘返,深陷其中。

    -

    选择困境,人生模拟

    -

    当然,除了巫师三之外,还有很多游戏的支线也很丰富,主线支线的组织也很巧妙,那凭什么巫师三这么牛逼呢?这就是巫师三的第二个牛逼之处:通过合逻辑的选择带给你极尽真实的人生体验。

    -

    巫师三的任务绝大多数都是需要玩家做出选择的,无论主线还是支线,这在从威伦到诺威格瑞之后尤为突出。不同于很多游戏可有可无的“可选项”,巫师三的每一个选项都是经过反复斟酌的,不存在无意义的选项。威伦雷索的选择直接决定了他之后会不会在凯尔莫罕的时候来帮你;凯拉的连续选项直接决定了她的命运,也决定了兰伯特的命运(这个有些小伙伴可能还不知道);威伦有个狼人的支线直接决定了这个悲惨爱情故事的结局;诺威格瑞迪胖的支线决定了游戏最终的政治格局。对主线来说,这样的决定性选项无处不在:血腥男爵的选项,特莉丝和椰奶的选项,Ciri的一系列选项等等。在巫师三中,选项的重要性直接以前后的因果关系体现出来,也许你的不经意的一个选择,就很有可能在未来决定了不同的世界线,其中的很多选项,你甚至都意识不到是由自己的决定造成的,这是不是有《命运石之门》的感觉了。

    -
    -Ciri猎魔人结局片段 - -
    -
    -Ciri猎魔人结局 - + +
    这一段还是非常感人的,我流下了130滴眼泪
    -

    我们之前说了,巫师三带给玩家的是沉浸式的体验,那实现这一点的关键就在“真实”。这里的真实,大部分是成年人的部分:我们会遇到各种各样的决策,尽管有句话是说“小孩子才做选择,成年人全都要”,但实际上,只有小孩子才能全都要,成年人的世界不能兼得鱼和熊掌。有些选择比较简单,但也有很多选择,可以说是直接决定了往后人生的整个发展方向。世界上没有后悔药,所以我们常常看到成年人的无奈与悔恨。但是游戏不一样,我们可以回档,可以重来,可以把现实中无法完成的夙愿转移到游戏中,体味人生抉择的无奈,尝尽人生起伏的精彩,但最爽的,还是能够重来,再走一遭。

    -

    巫师三是在真正意义上模拟了人生: - -首先,它的选项逻辑是合理的。很多游戏,包括奥德赛在内,它们所谓给出的选项很多都是不合理的。我为什么要这么做?为什么只有这几个选择?策划是不是脑子有坑?正常人会这么做?在选择的时候,不合理、不充分的选项不但不能产生真实的沉浸感,而且还会极大破坏游戏剧情推进的合理性。巫师三不然,它给出的每一个选项都是合理的,都是玩家真的可能在现实生活中面对的两难困境,从而不会让玩家产生“这个选项好弱智”的疑惑。真实的选项才能获得真实的体验,为选择而选择的设置只能适得其反。 -- -其次,它的选项是有反馈的。所谓反馈,就是无论你选了什么选项,都能在游戏的过程中获得该选择的结果,而且在看到这个结果的时候,玩家是可以或多或少发现它的起源就是那个选项。巫师三的选项就是有始有终的,它可能在有意无意间唤起你的决定,或最近,或久远,那个时候,玩家就会惊叹:原来如此!这是很重要的,因为在现实中,人们会感到“后悔”或者“幸好”,就是这样的“记忆唤醒”在作祟。人是健忘的,但这不是说记忆会消失,而是会被暂时隐藏,所以必须要有一个触发点(Trigger)才能重新唤醒这段记忆,而记忆一旦唤醒,就会有首尾呼应的触动,进而给玩家带来震撼感。这也是巫师三能带来真实体验的一个重要因素。

    +

    相比之下,DLC2的流程就非常非常长了,目前需要30个小时左右才能全部通关。DLC2分为三个章节,每个章节的流程都很长,相互独立但又通过“神话”这一线索串联起来,大概是寻找亚特兰蒂斯并探索神杖的用法。这个DLC把正作的神器线联系在了一起,在希腊和现代两个时间点之间不停穿越,目的就是要给玩家解释这个神器是怎么一回事儿。说实话,我也不知道他解没解释清楚,反正我基本都是快进过了,因为实在是过于无聊。

    +

    在剧情上来看这个DLC没啥有意思的,我总结一下,第一个章节是神秘四角恋上演姐妹撕逼大战,第二个章节是冥王海王打赌以虐待死者为乐,第三个章节是主角化身正义使者最终颠覆亚特兰蒂斯政权。总之就是云里雾里、莫名其妙。不过值得表扬的是,每个章节的特色地图都非常不错,极乐世界的花花草草,冥界的幽暗阴森感,亚特兰蒂斯的宏伟高科技,给人耳目一新的感觉。我印象最深的还是冥界的Phoibe剧情和Brasidas基友剧情,还是有点感人的,到了最后也特别想痛扁冥王。极乐世界充当双面间谍的感觉也不错,只是亚特兰蒂斯过于平平无奇,除了最后的BOSS有点恶心之外,也没有什么比较让人能够记住的点了。

    +

    这里特别吐槽一下冥界Brasidas的剧情,实在非常无语和狗血,把编剧的圣母心态体现得淋漓尽致。作为一个从小接受战士教育的将军,在战场杀敌是本分;当敌人杀向你,举起武器反击是本能;只是推开挡路的女人而没有将其杀死,是本心;无论从哪个角度讲,Brasidas都没有做错,战争也好,斯巴达的荣耀也好,还是出于自己的意志也好,Brasidas的做法都是无可非议的。但是,编剧强行要通过这个故事去虐Brasidas,本来都死得那么惨了,还要让他做出痛苦的抉择,实在是非常过分。在这里,我心疼基友三秒钟。

    -Geralt和夏妮 - +基友太惨了 +
    -
      -
    • 最后,它的选项是关键的。所谓关键,就是一些选项会产生极其重大的影响,此类选项在主线中最多,但也不乏一些支线。为什么说一些选项需要具备关键性?其实这就像欣赏任何一个文学作品一样,无论是小说,还是电影,剧情总是需要跌宕起伏。一平到底,或者过于波折,都会给观众造成审美疲劳。这在游戏里也是一样的。如果所有的支线都是做了就做了的那种,那么就不会给人留下深刻印象,反之,只有平淡与冲突交错的支线才会充分勾起玩家的兴趣。上面我们说了巫师三的支线都是有反馈,那么反馈对后续游戏造成的影响就可以定义为该支线的“关键度”。一个比较合理的关键度分布,应该需要满足5:3:2或者6:3:1的比例的,也就是大部分任务都是比较平淡的,立马能得到反馈的,而且对主要剧情没有影响的;少部分任务会在游戏后续呈现出比较重要的影响;而极少的任务会产生决定性的影响。举例来说,委托任务,城中任务,基本上都可以归为第一类,像凯拉、雷索这样的任务可以归为第二类,最后像迪胖、希里这样的就可以归为第三类。可以看到,巫师三的选项是非常有层次的,这样的层次感不会让玩家感到枯燥疲倦,从而更好地代入到游戏中。这也是巫师三让人停不下来的一个原因之一。
    • -
    -Geralt的回忆 - +我恨这个女人 +
    -

    有条不紊,循序渐进

    -

    在前面的两节中,我们说了很多支线的内容,包括支线的特性、选项的特性,但是在游戏里,决定玩家游戏体验是否“丝滑”的决定因素是主线的推进节奏。巫师三的主线的推进非常顺滑,玩家不会感到节奏上的拖沓或者赶工,从百草园,到威伦,到诺威格瑞,再到Skellig、凯尔莫罕,每个地方的风土人情都在剧情中得以充分展开,每个地方,从开始到结尾,都有明显的渐变,不会造成突兀感。这就是主线承接上的无缝性。

    -

    从整体上来看,巫师三的剧情推进呈现出前期平缓,后期陡峭上升,在最后达到高潮之后迅速下降收尾的趋势,尤其是在最后经过高潮后的突然结束,让玩家回味无穷。从百草园到是Skellig是整个游戏的平缓期,在这个时期,玩家更多地是在品味一个新地点的独有风格,所以游戏没有安排太波折的剧情,只是一点一点让玩家代入到整个游戏的剧情中。之后从凯尔莫罕开始,剧情开始迅速推进,寻找Ciri——>找到Ciri——>凯尔莫罕保卫战——>决战狂猎——>真相浮出——>Ciri献身,这一系列重要剧情节点被安排地非常紧凑,这是因为经过前中期长时间的铺垫,玩家已经全然进入到角色,当前最期待的是一波快节奏的剧情轰炸。笔者在出Skellig之后,就有预感剧情一定会出现巨大转折,从乌马开始,到狂猎结束,整个线非常完整,发展也非常迅速。但在这样的快节奏下,游戏不是混乱的,而是始终围绕着一个线索在有序地推进(找Ciri——>干狂猎),这样一来,即使游戏的节奏突然加快,玩家也没有不适感。

    +

    画面:时代顶尖,BUG难掩

    +

    奥德赛延续了起源优秀的画面,在刻画希腊风光上做到了无出其右,以至于获得了“旅游模拟器”的美称。画面其实是一个比较笼统的概念,当我们在说一个游戏的画面的时候,我们一般是在说这个游戏带给我们的所有视觉体验,包括光影效果、水和火的模拟、各种材质的清晰度真实度、整个画面的比例、画面的色彩等等等等,只要是我们能直观感受到的,都可以归入画面里。

    +

    从画面整体来看,奥德赛做到了时代的顶尖。优秀的光影、逼真的水波、温暖的色调、协调的比例、真实的场景,包括人物的建模等,都非常优秀。最难能可贵的是,奥德赛给我们生动地呈现出了波澜壮阔、风光迤逦、特色鲜明的古希腊景象,尽管可能不是最真实的历史,但是当我们置身其中时,仍然可以感到非常的震撼,仿佛自己就是那个时代的人,经历着相同的事。所以,奥德赛的画面不仅是技术上的时代顶尖,而且他还能带给我们一种沉浸式的体验,这对一个优秀的3A游戏来说,是必不可少的。

    -老爷子战逝 - +光影效果非常不错 +
    +

    当然,对奥德赛来说,他还是沿袭了“育碧特色”——各种神奇的BUG,虽然已经比起源好很多了(起源的BUG可以看这里)。比如,你会卡到一个地方无法动弹然后“失去同步”,会在地上皆若空游无所依,会有各种各种严重不严重的穿模。其中最为蛋疼的,其实不算BUG的地方就是,自动寻路。这个简直是噩梦,很多时候系统会绕很大一圈,甚至是本来已经绕了很大一圈了,结果来了个“无法跟随道路”,这是坠痛苦的。不过好在可能是阿育经历了起源雪崩式的BUG,在奥德赛里BUG已经不是一个很严重的问题了,至少可以完成任务不是。

    -老爷子死去Ciri流泪 - + +
    -

    巫师三的三个时期“平缓——上升——下降”是处理得很好的。平缓期大概占了整个游戏进度的50%左右,在这个期间,游戏的主要内容缓慢推进。注意,不是没有推进,而是以叙述的方式娓娓道来,逐渐营造引人入胜的氛围。上升期大概占了45%的内容,在这个阶段内,游戏的剧情迅速发展,剧情节点迅速变化,游戏状态迅速切换,然而玩家没有任何的不适应,反而更加乐在其中,停不下来。这是因为前50%的铺垫已经将玩家去完全代入到游戏中,仿佛你就是Geralt,你的使命就在眼前。在上升期的末尾,游戏戛然而止,来到下降期。巫师三的下降期非常短暂,我认为大致可以从Ciri献身开始算做下降期,在这个节点,玩家之前所有的选择都会体现在不同的结局上,突然结尾更加凸显了玩家之前决策带来的种种后果。显然,CDPR没有采取让游戏慢慢结束,而且一下子就关闭了游戏主线剧情,带来了一种“惊愕感”:“这游戏结束了!?”这样的设计是很巧妙的,但也是建立在之前的平缓期与上升期的铺垫之上的。可以说,巫师三这种有条不紊、循序渐进的三阶段推进方式,是它能够取得沉浸式体验的另一大重要原因。

    +

    人物:形象丰满,行为骨感

    +

    谈到剧情就不得不稍微说一下人物了。奥德赛对人物的刻画是非常到位的,作为一部史诗大作,奥德赛不仅对主角马拉卡和一些主要人物进行了细致入微的刻画,并且对一些关键配角也有非常到位的描写!

    +

    首先说一下主要人物:马拉卡、妈和妹妹。马拉卡无疑是最核心的人物了,玩家在关键剧情上的不同选择会呈现出多面的马拉卡形象,由于我选择的是真情圣母路线,所以就按照这个形象说。马拉卡给人的最大印象,在上面已经说了,作为一个铁血真汉子、无情雇佣兵,他的内心其实是非常渴望亲情的,无论是一直心心念念想要找到妈,想要挽回失足妹妹,还是对Phoibe如待女儿一般的呵护与关爱,抑或是对Markos的帮助,都体现了一个流浪在外无家可归的人向往亲情、渴望家庭的内心最真切的期盼。马拉卡不滥杀无辜,同情战争下家破人亡的底层百姓,路见不平也能拔刀相助,时而放荡不羁,时而收敛拘束,就好似武侠小说里的绝世大侠,执剑走江湖,四海皆为家。在游戏的时候,左下角的提示会出现“xx号是你的家,记得常回来看看”(大意如此),不禁让人唏嘘,马拉卡总是在外漂泊,以船为家,在注定不平凡的寻亲之路上经历这么多人生的坎坷,着实让人心疼!另外,马拉卡这个角色还透露着呆萌的气质,一方面是来自配音+动补演员本身的气质,另一方面就是在游戏中,马拉卡的确也很幽默,经常开一些黄腔,引发一些笑话。这些对丰富和塑造人物形象都非常有帮助。

    -通关主线,从空荡的凯尔莫罕重新出发,寂寥涌上心头 - +性感吗?我可以 +
    -

    写在最后

    -

    尽管本文的目的在于从任务系统上简要感受一下巫师三为什么能带给人沉浸式的体验,但是对于巫师三来说,画面、人物、音乐等等其他方面都是促成巫师三能成为神作的重要因素,尤其是巫师三的音乐,直击人心,给人带来的沉浸感不亚于剧情,在此强烈推荐。

    +

    然后再说说一些关键配角,这里说几个人:妈、后爸、Phoibe、基友Brasidas、炮王阿尔西比亚迪斯、苏格拉底。这几个人应该是除了主角之外给我留下印象最深刻的几个人了。

    +

    奥德赛对妈的刻画是非常到位的:坚强独立、能力突出,同时也和马拉卡一样渴望完整幸福的家庭。在找妈的路上,我们已经通过几个支线知道了妈是如何去找妹妹,如何带着她逃跑,又是如何在失去她之后绝望,到她最后重新振作成为一岛的领袖的。在这个过程中,妈的形象跃然纸上,后来和马拉卡一起挽救妹妹更是突出了她追寻亲情的一面。

    +

    对后爸的笔墨虽然不多,但是也能大致勾勒出一个教子严厉但关怀备至、有些教条但也饱含感情的一个将军形象。作为一个将军,他当初在悬崖边没有办法与神教抗衡,但是他也在一直懊悔。在几个CG里,我们都看出来,尽管他是继父,但是他仍然对马拉卡和妹妹视如己出,教导和关爱也都无微不至。

    +

    Phoibe和Brasidas应该是马拉卡人生中非常关键的两个人了。一个在他的生活中和他超越了朋友的关系,一个在他的斗争中给予了莫大的帮助。可以说,Phoibe与Brasidas是马拉卡少年时和成年时的两个缩影,一个象征着无邪的天真烂漫,一个象征着成熟的稳重冷静。站在马拉卡的视角,他想要紧紧地把握住他们,不但是对朋友的珍惜,更是对自己这两面的珍视,在他的心里,永远有一个小孩子,愿意陪着Phoibe一起长大,也永远有一个大人,能够和Brasidas并肩作战。

    -Geralt太可爱了吧 - + +
    马拉卡对Phoibe非常关心,因为她是最亲密的人
    -

    之后我会介绍一下英灵殿和12月份的赛博朋克2077,到时候再来看看,巫师三这款5年前的游戏是否仍有一战之力。

    +

    其实说实话,我对Phoibe是又爱又恨的,爱的是她的善良机智,恨的是她的自作聪明,无视马拉卡警告对自己的能力没有清晰的判断,导致自己身死他手,实在让人惋惜。显然,既然作为一个玩家,我已经能够对她产生这样的情感了,那么无疑,奥德赛对Phoibe的塑造也是相当成功的,虽然不那么讨喜,但是至少她是真实的。

    +

    基友的镜头没有Phoibe那么多,但是当他在贩夫仓库第一次出场时,就注定他有一个悲剧式英雄的解决了。在熊熊燃烧的大火中单挑对方几个好汉,与马拉卡多次在战场上默契配合,在斯巴达时多次帮助主角一家恢复名誉,以至于最后也是战死在战场上的,这样一个人物,实在令人肃然起敬。而且,基友不但是一个优秀的将军战士,他其实也很善良,他在能不杀人的时候是尽量不杀人的,从贩夫,到后来的斯巴达剧情,乃至到DLC的冥界,都体现了基友刚毅且善良的一面。然而,在DLC冥界那里,只要选错一个选项Brasidas就会留在冥界,这个行为这个剧情无非就是编剧强行喂屎表达泛滥圣母心的一面,实在是为这个角色抹黑!

    -陶森特美丽的风光 - +基友真的太帅了 +
    +

    最后,炮王阿尔西比亚迪斯和苏格拉底的刻画也是相当有意思。在游戏后半段这两个人都会有很多任务,炮王会不断地让你去帮他约炮,或者和他约炮,而苏格拉底就是不断和你强行抬杠探讨哲学,总的来说,这两个人物的刻画也非常鲜明。其他的包括船长、鬼魅、斯巴达领袖、表弟,甚至是那个性欲很强的老女人,奥德赛对他们的刻画也都有所突出,所谓众生各相,让玩家在走剧情、赏风景的同时还是感受古希腊多姿多彩的人文特色。

    +

    但是,正如这一节的标题所说的,很多人物的形象是很丰满,但是在一些细节方面,人物的行为动机是严重匮乏的,以至于玩家会觉得“为什么非要这么做”,这样的设计对人物的刻画是有害的。举个典型的例子,亲爸毕达哥拉斯,莫名其妙找到一个神器,然后莫名其妙又觉得自己无敌了,最后又莫名其妙地挂了,过完剧情玩家只会觉得这个人脑子有点不正常,至于其他的性格、形象、心理活动?不不不,脑子有问题就是了。人物行为骨感集中体现在DLC1,这也是DLC1被大家广为诟病之所在。上面已经说过这个问题了,这里不再赘述。

    +

    最后的最后,在游戏结局时马拉卡与苏格拉底在墓园的对话让人感慨万千,在此摘录如下:

    +
    +

    Alexios:Phoibe,她从没有过小女孩的时光,我总是以成人的方式与她对话。 +苏格拉底:这是因为你尊重她。你可以问问自己为何这么选择,Alexios,但千万不要质疑自己的决定。 +Alexios:谢谢你给了她该有的葬礼。 +苏格拉底:在极乐世界中还有无数的人,这些受到祝福的人已经获得了永恒的喜乐,其中一个就是我们伟大的伯里克利。 +Alexios:基于他的一切作为,全雅典都欠他一份情。 +苏格拉底:我们会称他为“雅典第一公民”不是没有道理的。他是个有很多贡献的人,但也是个孤僻的人。 +Alexios:要是他肯让我们分担他的重担就好了…… +苏格拉底:我们只能从他表现出来的部分来了解他,但谁敢说那就不是他真正的自我呢? +Alexios:这场战争牺牲太多人了,就连布拉西达斯都陨落了。 +苏格拉底:或许如此。但身为一个斯巴达人,他已经尽了自己的义务并战死沙场了。 +Alexios:我当时也有尽全力帮助他。他是我的朋友。 +苏格拉底:你还活着就是他最好的复仇,人们会将他作为英雄来尊敬的。 +Alexios:人们会记得我们是如何打垮克勒翁的。

    +
    +

    类型:转型成功,平衡欠佳

    +

    起源之前的刺客信条属于传统意义上的ACT游戏,从起源开始,逐渐向RPG转型,到了奥德赛,已经形成了ARPG的初步格局。尽管现代游戏ACT、RPG、ARPG的界限已经趋于模糊化,但是我认为我们还是有必要对游戏进行一个粗略的分类,以更好地对游戏整体的类型风格进行评价。

    +

    如果用ACT的视角审视奥德赛,那么奥德赛显然是不合格的。这体现在以下几点:

    +
      +
    • 正如剧情一节所述,奥德赛非常侧重剧情的讲述,大量的CG、对话、支线任务就是为了铺垫剧情、描绘人物形象,这和传统的ACT游戏淡化剧情是相悖的;
    • +
    • 奥德赛的养成元素非常多,这体现在等级压制、等级上限、装备体系、技能体系上,尽管游戏默认的是等级跟随,但是等级提高带来的技能点收益是非常重要的,尤其在打传奇动物和传奇生物的时候更为显著;
    • +
    • 奥德赛的装备体系决定了它不是一个纯粹的ACT游戏,游戏的蓝装、紫装、黄装品类非常多,并且,极品装备是满属性的紫装,这就意味着玩家可以追求极致一刀99999,尽管奥德赛没有刻意去引导玩家这么做,但是显然,很多玩家已经开始爆肝了。
    • +
    +

    但是另一方面,我们也不能纯粹从RPG的视角去看待奥德赛,因为游戏尽管整体上非常看重技能,但是如果你没有极品装备而只有黄色套装,那在很多时候,你还是要通过射箭、刺杀或开启无双模型与敌人硬刚,这对你的手法还是有所要求,比如闪避、防反、换装、流派,如果你不想“失去同步”,在高难度下还是需要一定的熟练程度才能手起刀落斩敌人于马下。尽管和起源的防反、马战比起来这都是小儿科,但手残玩家挑战奥德赛的噩梦难度也还是颇有难度的。从这个意义上讲,奥德赛还是保留了一些ACT的元素。

    +

    其实,当前纯粹的ACT游戏已经是难以走下去了,这是因为游戏作为一种艺术作品,随着时代的发展玩家越发看重它的精神内核。一个游戏可以不要高难度的战斗操作,只要它有足够优秀的剧本,那么它依然可以是神作;但是,一个游戏如果只要求高难度的操作,以及精心设计的关卡,而没有剧情或者足够有说服力的剧情,那么今天的大部分玩家是不会买账的。ACT游戏的RPG化是时代下游戏发展的一个趋势,但对刺客信条这个具有ACT传统的系列游戏来说,如何在这样的趋势下顺利转型是一大难题。

    +

    就我的体验来说,如果说起源是刺客信条转型的初步尝试,那么奥德赛就是转型的成功探索,它是一次探索,并且整体上成功了。如果你玩过起源和奥德赛,你会发现它们之间有莫名的相似性,但是给你的游戏体验又是完全不同的。上面讲到,起源的剧情是比较破碎的,而在很多地方,你不得不进行战斗,又加之战斗本身的难度,你会觉得剧情反而不那么重要,干掉敌人完成任务这个过程反而才是重点;同时,起源较少支线为主线让路的这个做法本身也是突出战斗的一大考量。如果把起源当成一个ARPG游戏,那么它“A”的成分还是更多一些。但是反观奥德赛,它的战斗就进一步简化了,没有马战,防反简单,刺客的飞雷神简直开挂,后期技能及其变态,甚至凑齐极品紫装后就是一刀一个小朋友,战斗本身就成了服务剧情的工具,玩家玩得爽就完事了。但是,仍然作为刺客信条系列游戏的奥德赛,总不能全是过剧情吧,那怎么办,疯狂增加要塞、兵营、洞穴就好了!再给你设计无穷多的支线,每个支线都让你去打怪,难度不够,数量来凑,这不动作的成分一下子就高上来了。

    +

    这是一个简单且聪明的想法,但对于奥德赛的定位来说,不够明智。我们可以体会到制作人想要保留APRG的动作成分和角色扮演成分,并且都要做大做强。这当然是可能的,如果做的时间足够久。但是,对于奥德赛来说却不可能,理由如下:

    +
      +
    • 开发时间短。尽管实际的开发时间我们不能精确得知,但是奥德赛发行于2018年10月,它的上一作发行于2017年10月,两作中间仅间隔一年,是标准的年货游戏。虽然奥德赛是魁北克工作室开发的,而起源是蒙特利尔工作室开发的,但是二者在整个系列的表现形式上具体显著的承接关系,故姑且认为奥德赛的实际开发周期约为2年,这个时间对3A游戏来说不算长;
    • +
    • 奥德赛的定位。奥德赛位于刺客信条系列从ACT向PRG转型的过渡阶段,是比起源更具标志性的一部作品。我个人认为,奥德赛的定位就是一部不成熟的ARPG过渡作品;
    • +
    • 经验的缺乏。显然,阿育对如何结合刺客信条系列传统的ACT元素与RPG元素的经验还有所缺乏,在短时间内要做一部顶级APRG游戏是非常困难的。记得是谁说过,“奥德赛就是想让你玩两年,直到下一部作品问世”,于是,他们把奥德赛的内容强行用问号、感叹号去填充,让玩家去爆肝刷装备,然后体验一刀99999的快感,但实际上,这种大而空的填鸭式内容对大部分骨灰级单机游戏玩家都没有吸引力,有的只是机械重复式的屠杀敌人,毫无乐趣。
    • +
    +

    所以说,在奥德赛的游戏类型上(ARPG),平衡性是不够优秀的。大到动作成分与角色扮演成分的平衡,小到装备的平衡、技能的平衡、数值的平衡等多方面,奥德赛的“全都要”战略俨然对大部分玩家来说只是一个噱头。如果只把奥德赛玩成体验剧情、模拟旅游,那奥德赛是再好不过的,可是一旦要玩操作、玩养成,奥德赛好像就走向了低配版的国产网游之路。游戏类型的平衡,是奥德赛的一大不足。

    +

    总结:育碧特色,系列之巅

    +

    总的来说,和以往的刺客信条年货作品不同,奥德赛算得上是一部精心打磨的作品,无论是剧情、画面,还是人物、音乐,抑或是育碧特色BUG,都看得出来是经过仔细调教了的。我个人认为奥德赛是综合看来刺客信条系列的巅峰之作,IGN评分9.2也算是比较中肯的评价了(对比起源9.0和巫师三9.3的评分)。如果要我来打分的话,我会打一个9.0分,要是阿育能够在剧情上再多打磨打磨,就可以给到9.5分。如果要说和巫师三差在哪儿,就差在剧情上。

    +

    另外,在本文中我没有谈到奥德赛的音乐,但这并不意味着它不出色,相反,我非常喜欢奥德赛的配乐,对比起源阴间的配乐,奥德赛的整体音乐风格就显得非常阳光和带感。OST可以在B站或者QQ音乐搜到,我已经循环很多天了,强烈推荐大家也去听一听。

    +

    对于11.10号即将发售的英灵殿来说,我个人还是非常期待的,一是可以亲手操作猛男,二是从试玩片段来看,它革除了奥德赛中饱受诟病的一些要素(比如剧情、满屏幕的问号、又臭又多的支线,过于强调等级和装备等),同时还保留了优良的画面。从这两点来看,英灵殿无疑是让人期待的。不管你预卜预购,我反正是已经预购了(还是等打骨折更划算一些/(ㄒoㄒ)/~~)

    ]]>
    游戏 - 玩后感 @@ -4075,264 +3441,426 @@ Radicals)两种,这里重点讨论的是右无穷根式的情况,左无穷 随笔 游戏 生活 - 巫师三 + 刺客信条
    - 《游戏设计的236个技巧》笔记 - /2021/08/17/01/07/ - 本文是《游戏设计的236个技巧:游戏机制、关卡设计和镜头窍门》的笔记。

    + 《Assassain's Creed Valhalla》玩后感 + /2020/11/12/23/23/ + 刺客信条:英灵殿(Assassin's Creed +Valhalla,下称英灵殿)无疑是刺客信条“神话三部曲”中最成功的一部,无论是从游戏的质量上,还是从销售成绩上。在80个小时的主线与10多个小时的“内置DLC”游玩后,我个人对英灵殿的评价可以总结为“自我突破,承前启后”。说它自我突破是因为它革除了起源和奥德赛中的绝大部分缺点,在自我的改进中完成了里程碑式的跨越;说它承前启后式因为它标志着刺客信条系列一次华丽而成功的转型与过渡,是游戏特色与市场充分交合后的最佳发展方向,是游戏缺点自我祓除与优点渐进式凸显的结果。本文将重点从游戏的任务系统、剧情节奏和人物刻画这三个方面介绍英灵殿的蜕变,至于游戏画面和风景,还有育碧特色BUG,都是刺客信条系列经典的历史特征了,在本文不再赘述。

    -

    前言

    -

    一款优秀的游戏是如何让玩家在某个瞬间感到无比有趣、极度畅快的呢?本书旨在引领读者发现“让游戏更有趣的设计技巧”。 -本书将内容分为“玩家角色”“敌人角色”“关卡设计”“碰撞检测”“镜头”五个部分。

    -

    让3D游戏更有趣的玩家角色技术

    -

    能够吸引2D游戏玩家的3D游戏设计技巧(《超级马里奥兄弟》《超级马里奥3D大陆》)

    +

    任务系统:众星捧月映空青,稀光散落满夜明

    +

    剧情节奏:一马平川驰此间,峰峦叠嶂牛羊见

    +

    人物刻画:穷极千里观百态,瓦泥滂沱照众生。

    +

    总结:长路漫漫终将至,共邀朝阳行远方。

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +

    +]]>
    + + 游戏 - 玩后感 + + + 随笔 + 游戏 + 生活 + 刺客信条 + +
    + + ComponentCameraSystem - A Simplified Camera System for You to Create Plentiful Gameplay Camera Movements and Effects + /2023/02/09/23/21/ + ComponentCameraSystem is a simplified, extensible +and designer-friendly camera system for Unreal Engine. It enhances the +built-in spring arm and camera components in native Unreal editor across +a wide variety of common gameplay camera behaviours such as keeping a +target at a fixed screen position, moving on rail, and resolving +occulusion in complex occasions, enabling you to easily create plentiful +smooth camera movements and effects within only few minutes. Go to the +Documentation +for more details.

    +

    Currently ComponentCameraSystem supports Unreal +Engine versions >= 5.0. So before using this plugin, please upgrade +your project to Unreal Engine 5.0 at its minimum version +requirement.

    +

    You can buy this plugin at Unreal Marketplace. +Persistent upgrade will be made to make it more stable and support more +features.

    +]]>
    + + 游戏 - 相机 + + + 计算机 + UE + 相机 + 游戏 + 插件 + +
    + + 《电脑游戏:文本、叙事与游戏》纪要 + /2021/08/14/18/08/ + 本文是《电脑游戏:文本、叙事与游戏》的简单纪要,在此备份。

    + +

    游戏与叙事

    +

    叙事理论

    + +

    叙事理论与《博德之门》

    + +

    叙事的限度

    + +

    游戏与快感

    + +

    角色的生成

    + +

    角色、特征和游戏

    + +

    沉浸、卷入与“心流”体验

    + +

    空间、导航与情绪反应

    +

    《异域镇魂曲》与《寂静岭》

    + +

    导航:迷阵、根茎与迷宫

    + +

    游戏文本与遍历函数

    +

    替身

    -

    B键冲刺带来的感官刺激以及风险与回报的趣味性

    +

    (更多细节,侧重代入感,带来感知沉浸)小<---------视距--------->大(更多信息,侧重策略性)

    +

    角色扮演

    +

    社会符号学视角

    +

    克劳德——大英雄

    -
  • 有趣秘密还在挑战中蕴含的风险与回报。 +
  • 克劳德这样的角色在相当大的程度上利用了民间文化、口头叙事和罗曼司等传统形式,通过精心构建的寓言故事,为日常生活中的过渡仪式和苦难提供了情感慰藉、道德争论和心灵拷问。
  • +
  • 电脑游戏是被翁称为高科技社会“次级口述”的案例之一,它是口述文化这种思维模式的进化,基础是文学和以技术为媒介的文化。
  • + +

    克劳德——数码傀儡?

    +

    化身的操纵

    + -

    勾起玩家跳跃冲动的互动式玩法

    +

    多模态的给予与需求

    -

    从《2D马里奥》到《3D马里奥》

    +

    文本再创作:网络上的粉丝文化

    -

    小结

    +

    游戏攻略作者

    -

    让游戏更具临场感的玩家角色动作设计技巧(战神三)

    -

    不需控制镜头的移动操作机制

    +

    虚构文学写作者

    +

    诗人

    +
  • 直接阐释了游戏主角的情感,这是游戏文本无法做到的。【现代游戏在有面捕和动捕之后是可以实现的。】
  • -

    实现快节奏战斗的玩家移动动作机制

    +

    “三无”漫画家

    +

    结论

    +

    动机与网络游戏

    +

    再现动机:欢迎来到鲁比卡世界

    -
  • 每个游戏都有一套能让玩家觉得舒服的“速度”(转身速度、移动速度、拔刀速度、收刀速度、硬直速度)“节奏”(具体的动作设计、动作之间的连贯性)和“触感”(动作的打击感)。根据这三点找出合适的玩家角色动作机制,是现代游戏开发的重点。
  • +
  • 《混乱在线》以科幻小说为基础进行设定,在游戏网站上,鲁比卡世界的故事片段以各种形式呈现。
  • +
  • 我们借以创建化身的个人标准,远比我们最初所能意识到的更能暴露自身经历及偏好。
  • -

    不带来烦躁感的地图切换机制

    +

    娱乐动机:游戏、目标与策略

    -

    让人不由得手指发力的玩家角色动作机制

    +

    公共动机:共享鲁比卡世界

    +

    结论

    +
  • 游戏动机的三种类型:再现动机(戏剧性的、表演性的、修饰性的、图像化的、叙事的)、娱乐动机(指向游戏层面的:数值、升级等)和公共动机(共有的期待、广泛的网络文化、游戏所分享的外部世界)。
  • -

    小结

    +

    社交性的游戏与学习

    +

    探究游戏的社交性

    -

    让割草游戏更有趣的攻击动作设计技巧(战神三)

    -

    让攻击准确命中目标敌人的机制

    +

    观察玩家

    +

    游戏

    +
  • 《凯恩的遗产:噬魂者》。
  • -

    让连击畅快淋漓的机制

    +

    玩游戏

    +

    叙事与游戏

    +
  • 如何处理游戏角色的死亡对动作冒险游戏而言十分重要。《噬魂者》的处理方式是:死亡不会导致重新开始,而是进入阴间,这使得玩家在相似环境下继续游戏,且包括了许多之前不存在的道路。
  • +
  • “管控调整”语言明显见于游戏和玩家之间以及玩家和玩家之间所交换的各种问题和命令中,“高手”完全关注于游戏系统以及对操作的指导。
  • +
  • 电脑游戏的试听魅力明显降低了在游戏过程中当面讨论的需要,如果故事已经展现在你眼前,描述故事甚至事无巨细地加以讨论就显得多余。
  • +
  • “玩后叙事”可以更多地展示出游戏地叙事魅力。
  • -

    菜鸟也能轻松上手的畅快的浮空连击机制

    +

    结论

    -

    用简单操作发动复杂连击的机制

    +

    游戏内外的能动性

    -

    让玩家角色动作更细腻的设计技巧(《塞尔达传说:天空之剑》)

    +

    进入奇异世界

    -

    让玩家下意识选择合适动作的Z注视机制

    +

    对玩家能动性的研究

    -

    能单独当游戏玩的移动动作——奋力冲刺

    +

    个人能动性

    -

    没有跳跃键却可以体验真实跳跃的机制

    +

    代理能动性

    -

    头脑与身体一起享受的剑战动作设计技巧(《塞尔达传说:天空之剑》)

    -

    能帅气挥剑的机制

    +

    集体能动性:粉丝作品

    -

    攻击与体力的机制

    +

    结论

    +

    电影、改编与电脑游戏

    +

    恐怖类型——从电影到游戏

    + +

    改编与《突变怪物》

    + +

    人物塑造与过场动画

    + -

    让玩家痛快反击的盾击机制

    +

    改编——从游戏到游戏

    -

    实现剑战动作的机制

    +

    游戏与性别

    +

    作为再现的游戏

    -

    剑战动作与割草游戏的区别

    +

    娱乐性与再现性

    -

    完美演绎英雄的玩家角色动作设计技巧(《蝙蝠侠:阿甘之城》)

    -

    能像蝙蝠一样在三维空间自如穿梭的机制

    +

    性别、游戏与语境

    -

    通过简单操作实现高自由度的玩家角色动作的机制

    +

    游戏分析的实践

    +

    定义游戏

    -

    演绎一名不会轻易死亡的英雄

    +

    游戏类型

    -

    让玩家化身为英雄的设计技巧(《蝙蝠侠:阿甘之城》)

    -

    让战术自由度更高的机制

    +

    叙事与游戏

    -

    让人忍不住要尝试的工具机制

    +

    穿越游戏空间

    -

    让玩家完美演绎蝙蝠侠的捕食者动作的机制

    +

    游戏动力学

    -

    改变动作游戏定式的自由流程格斗机制

    +

    走向线上

    -

    还原机器人动画的玩家角色动作设计技巧(《终极地带:引导亡灵之神》)

    +

    游戏中的社会生活

    + +

    生产游戏、生产意义

    + ]]>
    游戏 - 游戏理论 @@ -4343,109 +3871,211 @@ id="还原机器人动画的玩家角色动作设计技巧终极地带引导亡
    - 一道有趣的概率题 - /2022/10/20/23/59/ - 独立同分布,令,求。换句话说,我们要求最先使得若干个独立同分布于的随机变量之和大于的期望。

    - -

    问题定义

    -

    这个问题的定义已经定义在上面了,这里再复述一遍:

    -

    独立同分布,令,求

    -

    引入函数

    -

    乍一看这个题似乎无从下手,但是我们可以发现这里这个条件似乎可以换成任意一个,这启发我们用一个函数去表示我们要求的式子,然后通过求解一个“递推式”(实际上是一个微分方程)解出这个函数,进而得到某个具体点的值。

    -

    从这个思路出发,我们不妨定义,进而令。显然,我们的目标就是求

    -

    求解方程

    -

    那么,怎么求出呢?注意题目中的条件独立同分布,因此我们可以把里面的拆出来,变成:

    -

    -

    为了简便起见,我们不妨限定。此时考虑两种情况:

    -

    如果,那么就等于,所以这等价

    -

    如果,那么就相当于后面的,再由独立同分布知道这就是,但这是以为条件的,所以实际上还要对求个积分,也就是:

    -

    -

    把上面两个加起来,就有:

    -

    -

    进而得到微分方程及其初始值:

    -

    -

    很容易求解得到,所以我们就能得到最终的答案

    -]]>
    - - 数学 - 概率论 - - - 数学 - 随笔 - 概率论 - -
    - - 你为什么不笑了 - /2022/10/29/00/35/ - 你为什么不笑了?

    + 巫师三:一个告诉你原来游戏可以是艺术品的神作 + /2020/10/09/19/34/ + 巫师三是一款已经被时间证明的,当之无愧的神作。巫师三没有波澜壮阔气势浩天的景致,却有风格迥异人文色彩浓厚的地区特色。威伦的破败荒凉贫穷凄苦,为了一双鞋可以连父母都能出卖;诺威格瑞的大城风范,有日进斗金的土豪乡绅,也有困守城中的穷困百姓,女巫猎人穿梭其中,种族矛盾暗流涌动;史凯利杰群岛的剽悍民风,对外来者的敌视,对入侵者的抵御,捍卫土地的决心让诸多岛屿团结在一起;凯尔莫罕的静谧安详,森林环抱狼堡,猎魔人镇守故乡,仿佛出世的仙境,危机四伏但又简单质朴;陶森特的梦幻美丽,人们自得其乐,生活在这宛若仙境的城都中。不仅仅是景色,巫师三更是以它的剧情和对人物的刻画出名,抛开难以入流的战斗系统,单凭巫师三对剧情的把控、对人物的描写和对画面的雕琢,就足以令这部游戏称为艺术品。在经历了完整的主线和DLC流程后,几乎没有玩家会给巫师三一个低分,尽管它有瑕疵,但是它在剧情、人物和画面上已经到达巅峰造极的水平了,更难能可贵的是,这三者完美融合,在体验游戏的同时,给予玩家美的享受、身心的震撼。这是奥德赛无法比拟的,也是大多数游戏难以企及的高度。

    -

    奶奶,你为什么不笑了?
    -还记得,一年前的你,
    -走在春风里,
    -向着山顶慢慢登去。
    -你摘下路边的一朵浅梅,
    -捧在手心。
    -阳光洒下,
    -手中的梅花,也映衬出了你脸上的笑容。

    -

    你的儿子女儿挽着你的手,
    -一步一步向山顶走去,
    -你看见一棵古树,
    -你说这是拍照好去处。
    -女儿扶着你,
    -你扶着树,
    -阳光洒下,
    -树上的绿叶,也甘愿陪衬你脸上的笑容。

    -

    来到山顶,
    -黄花遍地,
    -你开心得像个孩子,
    -伸出双手,
    -比了两个大大的耶,
    -那时的你,真的好美。

    -

    奶奶,从什么时候开始,你不笑了?
    -从拔掉爷爷呼吸机的那个夜晚开始,
    -你似乎一直睡得不好。
    -你还能梦见吗,
    -另一张空荡荡的床上,
    -曾经那个老人的模样?
    -从前他是那样健康,
    -如今却骨瘦嶙峋,
    -让时间风干了皮肤,
    -侵蚀了思想。
    -你还能看见吗,
    -那个明媚下午的阳光,
    -案前那个老人伏着阅读着,报刊也泛黄。

    -

    奶奶,你为什么不笑了?
    -近日来,
    -你总是抱怨,
    -胸口有恙。
    -你变得啰嗦、唠叨,
    -总是对小事斤斤计量。
    -我好想你能多笑笑,
    -放下生活的疲劳,
    -忘却心中的郁结,
    -再回忆,
    -我们一起出游时,
    -小鸟的啼叫,
    -鲜花的绽放,
    -阳光的照耀,
    -我们手拉着手,
    -在田园中,聊些家常,传来欢笑。

    -

    奶奶,时间真的很残酷,
    -也许当我走时,
    -这个世界便再无你的回响,
    -人生人寂,人来人往,
    -至我去时,此情已了,略无痕迹。

    -

    奶奶,再让我看看你的笑,
    -那个阳光中,
    -像孩子般最天真的笑容。

    +

    前言

    +

    由于巫师三的世界观过于宏大,一篇未经雕琢的读后感不能道尽巫师三的所有优点,故本文旨在从宏观上呈现巫师三是如何完美统一任务、节奏与剧情这三者的。至于其他的,我们有机会留在以后再说。我相信,通关巫师三的玩家,一定会承认巫师三在任务的组织和剧情的展开上非常连贯丝滑,而且剧情上的节奏递进、叙述上的跌宕起伏都让人回味无穷。游戏本质是在讲故事,但是巫师三成功地给予了玩家沉浸式的体验,也就是,我们从观众的角色深入到了主角的角色,从游戏外的世界走进了游戏内的世界,仿佛每个人都是真实可及的,都是有血有肉的,都是有情有义的。那么,如何讲好这个故事,把观众代入到游戏中,就是巫师三不同于其他游戏的关键所在,这也是这篇玩后感的主要内容。

    +
    +被附身的Geralt帅中泄露出一丝痞气 + +
    +

    主线为林,支线为溪

    +

    巫师三的一大特色就是它的任务系统非常丰富,从表层看,巫师三的主线只有一个——寻找女儿,但是,在每个地区,都会有非常多的支线为主线提供背景。就好比一个建筑,主线是骨架,支撑起整个游戏的大致轮廓,而支线是钢筋水泥,垒起了整个建筑的最终格局。当然玩家可以只做主线不做支线,但我相信如果不做支线,这个游戏的乐趣就会少一半。

    +
    +父女之间的亲昵 + +
    +

    说到支线繁多,一个典型的对比就是刺客信条奥德赛。同样有非常多的支线,但是从我个人的游玩体验来说,我宁愿无视奥德赛的90%的支线,直接一条路走完主线,但是巫师三的支线不然,玩家会有强烈的意愿去做大部分支线,在做支线的过程中解锁问号,发掘游戏中隐藏的剧情,是巫师三最为亮眼的一大特色。如果要对比巫师三和奥德赛的任务系统,可以从下面几个方面评价:

    +
      +
    • 支线多样化:巫师三的支线是多样的,支线之间没有重复,猎魔人委托可能会更无聊一点,但生意人的事情嘛,不寒碜。除了猎魔人委托之外,寻宝任务有解密探险要素,区域日常支线有搞笑奇葩要素,重要支线甚至会改变整个巫师三世界格局。然而,奥德赛的支线是单调的,支线的选择不会影响主线的进程,支线品类非常单一,并且缺乏逻辑。巫师三支线给玩家的动力是充分的:委托赚钱,寻宝得装备,日常支线放松一下,重要支线扣人心弦;而奥德赛不是的,除了几个从头到尾都有的支线之外(类似于巫师三的寻宝任务),其他的支线毫无意义,既对主线没有补益,而且也缺乏特色。
    • +
    • 支线重要化:当然,支线多样丰富是一方面,更重要的是,支线是需要起到作用的,有时候甚至是决定性的作用。巫师三的主线和支线的分工相当明确:主线用来推进整个游戏进程,而支线则负责主线缺失的娱乐性与严肃性。这大大补充了单主线的贫乏,让玩家在游戏的时候不会觉得推进主线是无聊的,因为在同时还有大量丰富有趣的支线在支撑游戏的饱满度。而且,巫师三的支线并不是其他游戏中如过往云烟般的支线,而是不同的支线会在主线的不同时间点产生决定性的影响。比如,迪胖的支线会决定整个游戏最终的政治格局,这是从大了讲。从小了讲,如果细心留意,就会发现很多很多支线都涉及到游戏中不同人物的命运,即使是路人,我们也能够感到他们是真实的,而不仅仅是一堆数据。这些都是支线带来的重要积极影响。巫师三赋予了支线游戏的精神内核,并令其成为承载游戏厚度的“实力担当”。
    • +
    +
    +这样有趣的小支线在巫师三里不胜枚举 + +
    +
      +
    • 支线惊奇化。巫师三的支线时常给人一种惊奇的感觉,无论是之前无意之中做的支线会在后来的某一天发现原来会产生这样的影响,还是后来做到的支线会发现是之前剧情的关键结果,这种突如其来的“因果”呈现都带给玩家游戏体验上的冲击。重点是,正所谓大音希声,这样的惊奇化支线完全不需要漫长的铺垫,而只需要一个小小的“接口”,把因果串联起来就可以达到这样震撼的效果。一个典型的例子就是在DLC石之心里,拍卖行里的一个小支线展现了维瑟米尔的不为人知的一面,不但极大丰富了人物形象,而且还带给玩家无尽的唏嘘。此类四两拨千斤的支线在巫师三里比比皆是,
    • +
    +
    +一个非常小的细节,但是却折射出了两个饱满的人物形象 + +
    +
    +一个非常小的细节,但是却折射出了两个饱满的人物形象 + +
    +

    所以,巫师三成功的一大关键因素就在于他巧思的任务系统,尤以支线为代表,主线与支线的交织,主线推动整个剧情的发展。支线却承载了多样化、重要化和惊奇化的具体内容,让人家流连忘返,深陷其中。

    +

    选择困境,人生模拟

    +

    当然,除了巫师三之外,还有很多游戏的支线也很丰富,主线支线的组织也很巧妙,那凭什么巫师三这么牛逼呢?这就是巫师三的第二个牛逼之处:通过合逻辑的选择带给你极尽真实的人生体验。

    +

    巫师三的任务绝大多数都是需要玩家做出选择的,无论主线还是支线,这在从威伦到诺威格瑞之后尤为突出。不同于很多游戏可有可无的“可选项”,巫师三的每一个选项都是经过反复斟酌的,不存在无意义的选项。威伦雷索的选择直接决定了他之后会不会在凯尔莫罕的时候来帮你;凯拉的连续选项直接决定了她的命运,也决定了兰伯特的命运(这个有些小伙伴可能还不知道);威伦有个狼人的支线直接决定了这个悲惨爱情故事的结局;诺威格瑞迪胖的支线决定了游戏最终的政治格局。对主线来说,这样的决定性选项无处不在:血腥男爵的选项,特莉丝和椰奶的选项,Ciri的一系列选项等等。在巫师三中,选项的重要性直接以前后的因果关系体现出来,也许你的不经意的一个选择,就很有可能在未来决定了不同的世界线,其中的很多选项,你甚至都意识不到是由自己的决定造成的,这是不是有《命运石之门》的感觉了。

    +
    +Ciri猎魔人结局片段 + +
    +
    +Ciri猎魔人结局 + +
    +

    我们之前说了,巫师三带给玩家的是沉浸式的体验,那实现这一点的关键就在“真实”。这里的真实,大部分是成年人的部分:我们会遇到各种各样的决策,尽管有句话是说“小孩子才做选择,成年人全都要”,但实际上,只有小孩子才能全都要,成年人的世界不能兼得鱼和熊掌。有些选择比较简单,但也有很多选择,可以说是直接决定了往后人生的整个发展方向。世界上没有后悔药,所以我们常常看到成年人的无奈与悔恨。但是游戏不一样,我们可以回档,可以重来,可以把现实中无法完成的夙愿转移到游戏中,体味人生抉择的无奈,尝尽人生起伏的精彩,但最爽的,还是能够重来,再走一遭。

    +

    巫师三是在真正意义上模拟了人生: - +首先,它的选项逻辑是合理的。很多游戏,包括奥德赛在内,它们所谓给出的选项很多都是不合理的。我为什么要这么做?为什么只有这几个选择?策划是不是脑子有坑?正常人会这么做?在选择的时候,不合理、不充分的选项不但不能产生真实的沉浸感,而且还会极大破坏游戏剧情推进的合理性。巫师三不然,它给出的每一个选项都是合理的,都是玩家真的可能在现实生活中面对的两难困境,从而不会让玩家产生“这个选项好弱智”的疑惑。真实的选项才能获得真实的体验,为选择而选择的设置只能适得其反。 +- +其次,它的选项是有反馈的。所谓反馈,就是无论你选了什么选项,都能在游戏的过程中获得该选择的结果,而且在看到这个结果的时候,玩家是可以或多或少发现它的起源就是那个选项。巫师三的选项就是有始有终的,它可能在有意无意间唤起你的决定,或最近,或久远,那个时候,玩家就会惊叹:原来如此!这是很重要的,因为在现实中,人们会感到“后悔”或者“幸好”,就是这样的“记忆唤醒”在作祟。人是健忘的,但这不是说记忆会消失,而是会被暂时隐藏,所以必须要有一个触发点(Trigger)才能重新唤醒这段记忆,而记忆一旦唤醒,就会有首尾呼应的触动,进而给玩家带来震撼感。这也是巫师三能带来真实体验的一个重要因素。

    +
    +Geralt和夏妮 + +
    +
      +
    • 最后,它的选项是关键的。所谓关键,就是一些选项会产生极其重大的影响,此类选项在主线中最多,但也不乏一些支线。为什么说一些选项需要具备关键性?其实这就像欣赏任何一个文学作品一样,无论是小说,还是电影,剧情总是需要跌宕起伏。一平到底,或者过于波折,都会给观众造成审美疲劳。这在游戏里也是一样的。如果所有的支线都是做了就做了的那种,那么就不会给人留下深刻印象,反之,只有平淡与冲突交错的支线才会充分勾起玩家的兴趣。上面我们说了巫师三的支线都是有反馈,那么反馈对后续游戏造成的影响就可以定义为该支线的“关键度”。一个比较合理的关键度分布,应该需要满足5:3:2或者6:3:1的比例的,也就是大部分任务都是比较平淡的,立马能得到反馈的,而且对主要剧情没有影响的;少部分任务会在游戏后续呈现出比较重要的影响;而极少的任务会产生决定性的影响。举例来说,委托任务,城中任务,基本上都可以归为第一类,像凯拉、雷索这样的任务可以归为第二类,最后像迪胖、希里这样的就可以归为第三类。可以看到,巫师三的选项是非常有层次的,这样的层次感不会让玩家感到枯燥疲倦,从而更好地代入到游戏中。这也是巫师三让人停不下来的一个原因之一。
    • +
    +
    +Geralt的回忆 + +
    +

    有条不紊,循序渐进

    +

    在前面的两节中,我们说了很多支线的内容,包括支线的特性、选项的特性,但是在游戏里,决定玩家游戏体验是否“丝滑”的决定因素是主线的推进节奏。巫师三的主线的推进非常顺滑,玩家不会感到节奏上的拖沓或者赶工,从百草园,到威伦,到诺威格瑞,再到Skellig、凯尔莫罕,每个地方的风土人情都在剧情中得以充分展开,每个地方,从开始到结尾,都有明显的渐变,不会造成突兀感。这就是主线承接上的无缝性。

    +

    从整体上来看,巫师三的剧情推进呈现出前期平缓,后期陡峭上升,在最后达到高潮之后迅速下降收尾的趋势,尤其是在最后经过高潮后的突然结束,让玩家回味无穷。从百草园到是Skellig是整个游戏的平缓期,在这个时期,玩家更多地是在品味一个新地点的独有风格,所以游戏没有安排太波折的剧情,只是一点一点让玩家代入到整个游戏的剧情中。之后从凯尔莫罕开始,剧情开始迅速推进,寻找Ciri——>找到Ciri——>凯尔莫罕保卫战——>决战狂猎——>真相浮出——>Ciri献身,这一系列重要剧情节点被安排地非常紧凑,这是因为经过前中期长时间的铺垫,玩家已经全然进入到角色,当前最期待的是一波快节奏的剧情轰炸。笔者在出Skellig之后,就有预感剧情一定会出现巨大转折,从乌马开始,到狂猎结束,整个线非常完整,发展也非常迅速。但在这样的快节奏下,游戏不是混乱的,而是始终围绕着一个线索在有序地推进(找Ciri——>干狂猎),这样一来,即使游戏的节奏突然加快,玩家也没有不适感。

    +
    +老爷子战逝 + +
    +
    +老爷子死去Ciri流泪 + +
    +

    巫师三的三个时期“平缓——上升——下降”是处理得很好的。平缓期大概占了整个游戏进度的50%左右,在这个期间,游戏的主要内容缓慢推进。注意,不是没有推进,而是以叙述的方式娓娓道来,逐渐营造引人入胜的氛围。上升期大概占了45%的内容,在这个阶段内,游戏的剧情迅速发展,剧情节点迅速变化,游戏状态迅速切换,然而玩家没有任何的不适应,反而更加乐在其中,停不下来。这是因为前50%的铺垫已经将玩家去完全代入到游戏中,仿佛你就是Geralt,你的使命就在眼前。在上升期的末尾,游戏戛然而止,来到下降期。巫师三的下降期非常短暂,我认为大致可以从Ciri献身开始算做下降期,在这个节点,玩家之前所有的选择都会体现在不同的结局上,突然结尾更加凸显了玩家之前决策带来的种种后果。显然,CDPR没有采取让游戏慢慢结束,而且一下子就关闭了游戏主线剧情,带来了一种“惊愕感”:“这游戏结束了!?”这样的设计是很巧妙的,但也是建立在之前的平缓期与上升期的铺垫之上的。可以说,巫师三这种有条不紊、循序渐进的三阶段推进方式,是它能够取得沉浸式体验的另一大重要原因。

    +
    +通关主线,从空荡的凯尔莫罕重新出发,寂寥涌上心头 + +
    +

    写在最后

    +

    尽管本文的目的在于从任务系统上简要感受一下巫师三为什么能带给人沉浸式的体验,但是对于巫师三来说,画面、人物、音乐等等其他方面都是促成巫师三能成为神作的重要因素,尤其是巫师三的音乐,直击人心,给人带来的沉浸感不亚于剧情,在此强烈推荐。

    +
    +Geralt太可爱了吧 + +
    +

    之后我会介绍一下英灵殿和12月份的赛博朋克2077,到时候再来看看,巫师三这款5年前的游戏是否仍有一战之力。

    +
    +陶森特美丽的风光 + +
    ]]>
    - 随笔 + 游戏 - 玩后感 随笔 + 游戏 生活 + 巫师三 + +
    + + 无穷连根式求极限的充要条件 + /2020/09/09/18/52/ + 在刷习题集或者考试的时候我们经常会遇到诸如或者的极限求解或极限存在性证明。解决此类问题的方法有很多,但都可以归结为一点:缩放。要么是两端缩放然后夹逼定理,要么是证明有界然后两边取极限。本文记录此类问题极限存在的一个充要条件,以供参阅。

    + +

    Ramanujan's Problem

    +

    这类问题最著名的是拉马努金(Ramanujan)所提出的恒等式:

    +
    +

    证明:

    +
    +

    这个等式的证明是简单而有趣的:

    +

    +

    同时,Ramanujan还断言下面的结论:

    +

    +

    这个的证明也是容易的。首先把上式和(1)式比较,就发现上式以3为上界,并且由单调性可知,其极限是存在的。为了证明的极限就是3,我们证明:对任意的,都存在,使得所有的都有

    +

    现在任取,令,故,故有:

    +

    +

    乘进去,就有:

    +

    +

    由于,且存在,当时,有

    +

    +

    把这些全部带入(2)式,就可以证明:

    +

    +

    从而完成证明。

    +

    Polya's Criterion(Polya准则)

    +

    在考虑普遍情况下首先来观察一些特例,一个典型的特例就是形如的无穷根式,每个根号的次数都是,或者幂次都是。对于来看,控制它的幂次是,对于来说,控制它的幂次是,对于来说,控制它的幂次是。假设这个无穷根式极限存在,那么我们关心的肯定是足够大时,它被什么控制,显然是及控制它的的幂次。所以,一个合理的猜测是,如果极限存在,那么该根式就收敛。下面我们将看到,这个猜测已经非常接近“真相”,甚至是真相的一部分。

    +

    Description

    +

    设序列,则可以用下述条件判定:

    +

    +

    上述准则还可以进一步推广为:

    +
    +

    序列收敛的充要条件是: +

    +
    +

    注意到,这个极限可以取有限数或者负无穷。我们将在陈述下面的定理一之后进行证明。

    +
    +

    (定理一) 序列收敛当且仅当存在有限上极限 +

    +
    +

    首先证明必要性,即假定收敛。因为,故一定是有限的,得证。

    +

    再来证明充分性。假定,则存在使得对所有,有,因此。从而有:

    +

    +

    同时又因为

    +

    +

    从而有,又由的单调性知收敛。

    +

    到此为止,我们发现定理一和开始我们的猜测是非常相似的,只是定理一只需要上极限,这比我们的猜测更加宽松。下面我们利用此定理证明Polya's +Criterion.

    +

    Proof of Polya's Criterion

    +

    时,存在,当,也即,由定理一收敛。

    +

    时,存在某个,对某些无限的,使得,也即。因此,对这些而言:

    +

    +

    因此.

    +

    最后考虑

    +

    收敛,则有限,即存在对所有成立,因而。此时若,则

    +

    +

    而当时,按照约定有,则综上公式(3)的必要性得证。

    +

    同时公式(3)也是充分的。假定条件成立但不收敛,则由定理一,则对任意的,有充分大的使得,从而,于是有

    +

    +

    这说明上极限是无穷大,与假设矛盾。充分性得证。

    +

    Examples

    +

    例一

    +

    现在我们考虑一个序列,当的时候,它的上界是,而后者我们上面已经证明了它的上界是2。现在我们考虑的情景。此时有:

    +

    +

    所以我们证明了,对,序列都是收敛的,并且没有使用定理一

    +

    例二

    +

    现在考虑下述恒等式:

    +

    +

    于是可以立即得到:

    +

    +

    现在令,就有:

    +

    +

    替换,有:

    +

    +

    两边约去2,就有:

    +

    +

    例三

    +

    由余弦二倍角公式可知:

    +

    +

    此时令,就有:

    +

    +

    所以可以立刻得到下式的极限:

    +

    +

    Herschfeld’s +Convergence Theorem (Herschfeld收敛定理)

    +

    Polya's Criterion只考虑了指数为的情况,对于更加普遍的情况,即形如的序列,Herschfeld’s Convergence +Theorem给出了一个其收敛的充要条件。

    +

    Herschfeld’s +Convergence Theorem 告诉我们了一个无穷根式收敛的充要条件:

    +
    +

    设序列且级数收敛,则序列收敛的充分必要条件是:

    +
    +

    这个定理的证明之后有空了补充。

    +

    后记

    +

    实际上无穷根式分为右无穷根式(Right Infinite +Radicals)和左无穷根式(Left Infinite +Radicals)两种,这里重点讨论的是右无穷根式的情况,左无穷根式可以仿照进行推导。

    +]]>
    + + 数学 - 数学分析 + + + 数学 + 随笔
    @@ -4456,1831 +4086,2128 @@ Developers》的阅读笔记,放在此备份供参阅。

    Part 1: Core Concepts

    +

    Chapter 1: Game Overview

    +

    一个典型的游戏引擎(Game Engine)应当包括:

    + +
    +游戏各系统之间的联系。 + +
    +

    游戏的每个系统都有相对固定的更新顺序,如下图所示:

    +
    +游戏各系统的更新顺序。 + +
    +

    对于每个步骤的介绍如下:

    + +

    对于相机而言,Occam's +Razor法则适用:最简单的相机解决方案通常是最好的。

    +

    相机系统的作用包括:

    + +

    角色控制与角色移动之间的关系被称为控制参考帧(control +reference frame)

    +

    Chapter 2: Camera +Fundamentals

    +

    Real-World Cameras

    +

    真实世界的相机大概包含以下关键要素:

    + +

    真实世界相机的一些特点:

    + +

    游戏相机的一些特点:

    + +

    一些专有名词:

    + +

    Camera Presentation Styles

    +

    Presentation style +通常被划分为正交(2D)或者透视(3D)渲染,有时也会使用2.5D

    +

    Camera Behaviors

    +

    主要有三种相机行为:

    + -

    Chapter 1: Game Overview

    -

    一个典型的游戏引擎(Game Engine)应当包括:

    +

    此外,相机也可以分为predictive和reactive两类: - Reactive: +根据游戏对象的变化而变化 - Predictive: +根据当前游戏物体预测最佳的相机位置和朝向

    +

    Path finding solutions: - +全局路径搜索:搜索环境中的一条路径,能够保持美学质量 - +局部路径搜索:以某种具体的物体类型为核心进行搜索 - +基于目标的搜索:在各种约束下搜索路径

    +

    View Generation

    +

    视图生成步骤:

    -游戏各系统之间的联系。 - +简化的渲染流程。 +
    -

    游戏的每个系统都有相对固定的更新顺序,如下图所示:

    +

    在上述步骤中,与相机系统直接相关的有:view frustum, view +transform和projection transform

    +

    Player Controls

    +

    A control reference frame refers to a relationship between changes to +the controller input and how it affects movement or other aspects of +player control.

    +

    在FP游戏中,control reference +frame直接对应了玩家角色面朝的方向,且通常只能绕up +axis旋转。在TP游戏中,control reference +frame基于相机与玩家的相对位置。

    +

    Control reference frame需要始终反应玩家的意图

    +

    Chapter 3: Cinematography

    +

    Nomenclature

    +

    电影学中的一些专有名词:

    + +

    Dynamically +Generated Movies/Replay Cameras

    +

    为了实现回放,可以记录初始游戏状态和玩家操作,然后模拟行为。一些回放系统还支持观测者视角。

    +

    有三种形式的回放相机:reproduction, scripted, dynamically +generated:

    + +

    一些常用的相机特效:

    + +

    Scripting

    +

    Scripting通常指设计师手动指定相机的位置和朝向,要么在编辑器中进行编辑,要么使用Maya等工具编辑后直接导入

    +

    一个典型的scripting system应当包括:

    + +

    Scripting system最好还支持编辑时预览,尽管非常困难

    +

    Editing

    +

    编辑就是把所有的shot重新组织、拼接的过程,主要包含以下内容:

    +
    -游戏各系统的更新顺序。 - +Rule of thirds示意。 +
    -

    对于每个步骤的介绍如下:

    +

    Tools

    +

    如果电影镜头使用游戏引擎进行渲染,即用常规游戏环境制作镜头,则最好让编辑器支持直接控制cinematic +sequences,包括:

    +

    上述属性都可以通过一条曲线完成(类似Unity),横坐标是elapsed +time,纵坐标是具体值

    +

    Part 2: Design Principles

    +

    Chapter 4: Camera Design

    +

    Interactive 2D Camera +Systems

    +

    2D游戏通常使用tile +map,每个tile都是一个小图片,且使用hash存储,因此极大节省内存

    +

    2D相机的主要功能之一是让角色一直位于屏幕可视范围,比如可以使用scrolling,即让背景做相对运动。下面是一些常见的scrolling类型:

    -
  • Post-Camera:更新依赖于相机的物体
  • -
  • Render:有时候一个camera view也会被用于另一个camera -view的生成过程中
  • +
  • Continuous: 背景的scrolling随着游戏连续进行
  • +
  • Character-relative: 相机的运动与角色的运动同步
  • +
  • Directional lag: 期望的相机位置基于角色运动的方向
  • +
  • Burst: 期望的相机位置只有当角色到达某个位置或距离时才变化
  • +
  • Screen-relative: 只有在角色超出预定义的边界时相机才开始移动
  • +
  • Region-based: 当角色超过相对于世界的边界时相机才开始移动
  • -

    对于相机而言,Occam's -Razor法则适用:最简单的相机解决方案通常是最好的。

    -

    相机系统的作用包括:

    +

    有时候相机的位置要独立于角色位置。对共用一个viewport的多人游戏来说,所有角色的位置共同决定了相机的位置。解决方案:

    +

    Cinematic 2D Camera Systems

    +

    2D cinamatic camera system的一些典型特征包括:

    + +

    Interactive 3D Camera +Systems

    +

    交互式3D相机系统的难点在于提供一个上下文合适的视角,包括艺术性与游戏性,特征包括:

    + -

    角色控制与角色移动之间的关系被称为控制参考帧(control -reference frame)

    -

    Chapter 2: Camera -Fundamentals

    -

    Real-World Cameras

    -

    真实世界的相机大概包含以下关键要素:

    +

    Cinematic 3D Camera Systems

    +

    当设计3D cinematic camera system的时候有几个有用的建议:

    -

    真实世界相机的一些特点:

    +

    2.5D Camera Systems

    +

    2.5D相机系统有自身的优势,比如让游戏玩家更容易理解和接受游戏

    +

    Display Devices

    +

    让游戏分辨率适应显示分辨率的方法:

    -

    游戏相机的一些特点:

    +

    Camera Design process

    +

    首先,游戏的整体体验/玩法需要制定下来,然后再制定相机的宏观设计框架。相机设计的总体流程是:

    -

    一些专有名词:

    +

    在相机设计的时候可以问一些问题,这有助于我们更好地设计:

    -

    Camera Presentation Styles

    -

    Presentation style -通常被划分为正交(2D)或者透视(3D)渲染,有时也会使用2.5D

    -

    Camera Behaviors

    -

    主要有三种相机行为:

    +

    对于相机的要求、限制应该在项目早期就明确,除非是个别例外,并且要避免在项目开展后大改相机系统。因此,要在项目商讨环节把需求都明确清楚

    +

    团队中的camera +designer不仅需要负责相机表现,而且也需要负责大部分情况下的相机解决方案。Lead +camera +designer需要具备美学sense,包括游戏内容的呈现和玩家操作、感知的表现,此外,他还需要推动团队提高认知

    +

    Camera Design Guidelines

    +

    一些相机设计的建议:

    -

    此外,相机也可以分为predictive和reactive两类: - Reactive: -根据游戏对象的变化而变化 - Predictive: -根据当前游戏物体预测最佳的相机位置和朝向

    -

    Path finding solutions: - -全局路径搜索:搜索环境中的一条路径,能够保持美学质量 - -局部路径搜索:以某种具体的物体类型为核心进行搜索 - -基于目标的搜索:在各种约束下搜索路径

    -

    View Generation

    -

    视图生成步骤:

    +

    Chapter 5: Camera Solutions

    +

    Game Genre Camera Solutions

    -
    -简化的渲染流程。 - -
    -

    在上述步骤中,与相机系统直接相关的有:view frustum, view -transform和projection transform

    -

    Player Controls

    -

    A control reference frame refers to a relationship between changes to -the controller input and how it affects movement or other aspects of -player control.

    -

    在FP游戏中,control reference -frame直接对应了玩家角色面朝的方向,且通常只能绕up -axis旋转。在TP游戏中,control reference -frame基于相机与玩家的相对位置。

    -

    Control reference frame需要始终反应玩家的意图

    -

    Chapter 3: Cinematography

    -

    Nomenclature

    -

    电影学中的一些专有名词:

    +
  • Racing games: +可提供额外的视角以观测其他人的位置,增大FOV可以制造物体快速通过玩家的感觉
  • +
  • Ground vehicles
  • +
  • RTS
  • +
  • Flight simulation: 一个重要的方面是是否允许相机随着飞机一起roll
  • +
  • Adventure: present a very cinematic experience to the player
  • +
  • Puzzle/party games/board games
  • +
  • Fighting/close combat: +场景一般很简单以便于相机摆放,需要一些相机移动突出角色的操作
  • -

    Dynamically -Generated Movies/Replay Cameras

    -

    为了实现回放,可以记录初始游戏状态和玩家操作,然后模拟行为。一些回放系统还支持观测者视角。

    -

    有三种形式的回放相机:reproduction, scripted, dynamically -generated:

    +

    Multi-Player Camera +Solutions

    +

    多人共享屏幕时,相机设计会有很大难度,有时候可以通过alternate +players解决,但多数情况下并不适用。一般来说可以有两种解决方法:

    +

    下面是对相关技术的介绍:

    -

    一些常用的相机特效:

    +

    Gamera Scripting

    +

    What is Meant by Scripting

    +

    定义与控制物体加偶和的过程被称为scripting,在游戏中,指控制游戏事件发生的事件与物体之间的交互。Scripting允许设计师在没有程序员介入的情况下完成迭代

    +

    Types of Scripting

    +

    我们希望构建一个与游戏类型无关的scripting系统,主要由两个方面组成:scripting +language和event messaging

    +

    Scripting languages

    -

    Scripting

    -

    Scripting通常指设计师手动指定相机的位置和朝向,要么在编辑器中进行编辑,要么使用Maya等工具编辑后直接导入

    -

    一个典型的scripting system应当包括:

    +

    Event messaging

    +

    Event +messaging要求定义不同物体之间的关系。典型的能够发送消息的事件包括:

    -

    Scripting system最好还支持编辑时预览,尽管非常困难

    -

    Editing

    -

    编辑就是把所有的shot重新组织、拼接的过程,主要包含以下内容:

    +

    能够被事件发送的典型消息包括:

    +

    Script Objects

    +

    用于定义物体的属性和行为

    +

    Scriptable game hints

    +

    Game hints are script objects that provide one possible type of +runtime mechanism by which designers can override player properties, +game controls or camera properties according to events

    -
    -Rule of thirds示意。 - -
    -

    Tools

    -

    如果电影镜头使用游戏引擎进行渲染,即用常规游戏环境制作镜头,则最好让编辑器支持直接控制cinematic -sequences,包括:

    +

    很多时候事件需要有先后顺序,一个sequenced event +manager可以用来定义事件的先后顺序。

    +

    Camera Scripting

    +

    Camera scripting methods

    -

    上述属性都可以通过一条曲线完成(类似Unity),横坐标是elapsed -time,纵坐标是具体值

    -

    Part 2: Design Principles

    -

    Chapter 4: Camera Design

    -

    Interactive 2D Camera -Systems

    -

    2D游戏通常使用tile -map,每个tile都是一个小图片,且使用hash存储,因此极大节省内存

    -

    2D相机的主要功能之一是让角色一直位于屏幕可视范围,比如可以使用scrolling,即让背景做相对运动。下面是一些常见的scrolling类型:

    +

    DCamera control

    -

    有时候相机的位置要独立于角色位置。对共用一个viewport的多人游戏来说,所有角色的位置共同决定了相机的位置。解决方案:

    +

    一些经验法则:

    -

    Cinematic 2D Camera Systems

    -

    2D cinamatic camera system的一些典型特征包括:

    +

    Scripting Tools

    +

    World editor support

    +

    必须支持script objects的放置与操作,而且还要支持message passing, +state transition, event trigger和其他物体间的关系

    +

    Communication +between target platform and development PC

    +

    要获得运行物体的状态

    +

    Messaging/event logging

    +

    对消息和事件进行记录

    +

    Object properties debugging

    +

    当游戏运行时要动态检查物体的属性

    +

    Replay

    +

    最简单的方法是内置video recording

    +

    Console window

    +

    支持打印文本消息,通过GM指令查看想要的文本消息

    +

    Scripting Debugging

    +

    常见的debugging方法:

    -

    Interactive 3D Camera -Systems

    -

    交互式3D相机系统的难点在于提供一个上下文合适的视角,包括艺术性与游戏性,特征包括:

    +

    Part 3: Camera Engineering

    +

    Chapter 7: Position and +Orientation

    +

    Coordinate Schemes

    +

    有几种不同的坐标空间:

    -

    Cinematic 3D Camera Systems

    -

    当设计3D cinematic camera system的时候有几个有用的建议:

    +

    Desired Position

    +

    在相机移动的过程中需要关注与目标点的距离

    +

    First person camera +positioning

    +

    大多数情况下,相机的desired +position就是角色眼睛的位置,此时增加一点dvertical +amping会有用。在玩家遇到崎岖地形或与物体碰撞时,需要smooth +out轻微的相机运动

    +

    Third person camera +positioning

    +

    有三种策略决定相机位置:

    -

    2.5D Camera Systems

    -

    2.5D相机系统有自身的优势,比如让游戏玩家更容易理解和接受游戏

    -

    Display Devices

    -

    让游戏分辨率适应显示分辨率的方法:

    +

    Desired Position +Determination Methods

    +

    相机位置应该独立于朝向,尽管后者常常依赖于前者。下面是一些决定desired +position的方法

    +

    Stationary

    +

    主要有两种stationary cameras: fixed position 和 dynamic fixed +position:

    -

    Camera Design process

    -

    首先,游戏的整体体验/玩法需要制定下来,然后再制定相机的宏观设计框架。相机设计的总体流程是:

    +

    Slaved/tracking

    +

    相机的offset可以采取以下的几种形式:

    -

    在相机设计的时候可以问一些问题,这有助于我们更好地设计:

    - -

    对于相机的要求、限制应该在项目早期就明确,除非是个别例外,并且要避免在项目开展后大改相机系统。因此,要在项目商讨环节把需求都明确清楚

    -

    团队中的camera -designer不仅需要负责相机表现,而且也需要负责大部分情况下的相机解决方案。Lead -camera -designer需要具备美学sense,包括游戏内容的呈现和玩家操作、感知的表现,此外,他还需要推动团队提高认知

    -

    Camera Design Guidelines

    -

    一些相机设计的建议:

    +

    下面是决定路径位置的方法:

    -

    Chapter 5: Camera Solutions

    -

    Game Genre Camera Solutions

    - +

    Volume constrained

    +

    相机与圆柱体的碰撞检测:

    +
    Vec3 direction = currentPosition - cylinder.GetPosition();
    direction.SetZ(0.0f);
    float radius = direction.Magnitude();
    if (radius > kMaxRadius)
    radius = kMaxRadius;
    direction = direction.AsNormalized() * radius;
    Vec3 newPosition = cylinder.GetPosition() + direction;
    newPosition.SetZ(currentPosition.GetZ());
    +

    Framing

    +

    该方法在屏幕空间上保持目标角色的位置,这可以通过移动相机、修改FOV、伸缩viewport等方法实现

    +

    Object-framing relative

    +

    该方法不仅考虑物体在屏幕空间中的小,而且也考虑它和另一个物体之间的相对距离,一些因素包括:

    -
  • Adventure: present a very cinematic experience to the player
  • -
  • Puzzle/party games/board games
  • -
  • Fighting/close combat: -场景一般很简单以便于相机摆放,需要一些相机移动突出角色的操作
  • +
  • Object screen size
  • +
  • Multiple objects must be kept on screen
  • +
  • Distance between objects
  • +
  • Relative position to other objects
  • +
  • Relative position to the screen (not rendered size)
  • +
  • Orientation with respect to the camera
  • +
  • Distance aiming/ranged weapons
  • -

    Multi-Player Camera -Solutions

    -

    多人共享屏幕时,相机设计会有很大难度,有时候可以通过alternate -players解决,但多数情况下并不适用。一般来说可以有两种解决方法:

    +

    Axis rotational/spindle

    +

    相机围绕游戏世界中的一个轴旋转、平移,适用于玩家需要围着一个物体导航的情况,或限制在一个圆柱物体的情况

    +

    一些影响相机位置的因素:

    -

    下面是对相关技术的介绍:

    +

    此外,我们也可以改变相机的朝向:

    +

    玩家位置相对于spindle axis的半径可以作为mapping +function的输入,当玩家移动半径更小时,相机移动得更高

    +

    Common Position Problems

    -
  • Split-screen techniques +
  • 期望位置和一个物体碰撞,或者太近以至于物体穿透相机的近平面
  • +
  • 期望位置离环境中的边界物体太近以至于有环境外的视野
  • +
  • 期望位置离目标对象太远,玩家没有好的视野
  • +
  • 环境复杂相机不能提供好的视野
  • + +

    Orientation

    +

    旋转有四种表示方法:欧拉角、变换矩阵、轴角和四元数

    +

    Desired Orientation +Determination Methods

    +

    Constant orientation

    +

    朝向不变,但是位置可以移动。可以变式为constant elevation +cameras,即只有pitch可以改变

    +

    这种相机可以用在:

    -
  • Transitioning from full-screen to split-screen +
  • Player controlled remote cameras
  • +
  • Dynamic positioning of replay cameras
  • +
  • Dynamic positioning of caemras for non-interactive game play +sequences
  • + +

    Tracking a target object +or position

    +

    相机达到期望朝向的方法取决于目标物体的移动和相机的重朝向速度,此类相机一般保持固定的pitch

    +

    Look-at offset

    +

    许多三人称游戏使用一个固定的look-at offset

    +

    Locked look-at position

    +

    玩家的朝向也会随便改变

    +

    Target object position +prediction

    +

    Object framing

    +

    一个很好的例子是格斗游戏,双方玩家都希望自己和对方都能呈现在屏幕上,当玩家距离增加的时候,相机要么拉远,要么增大FOV,但是频繁切换FOV通常不可取

    +

    回放相机通常会从不同的视角呈现玩家行为

    +

    Idle wandering

    +

    A semi-random camera reorientation while the player character is +idle

    +

    Automated orientation +control

    +

    在没有玩家操作的情况下自动帮助相机转向:

    -
  • Transitioning from split-screen to full-screen +
  • Automated control over camera pitch when the player is jumping: +从玩家起跳时开始相机可以向下看
  • +
  • Automated pitch control when traversing environmental features: This +is applied to present a view facing up or down a ramp, staircase or +other incline as appropriate so that players have a better view of what +they are moving toward, +在有洞穴或悬崖的地方,相机应该自动看向以给予提示
  • +
  • Automated pitch control during combat or interactions: +自动调整pitch以提示可交互的物体
  • +
  • Automated reorientation of the player or a camera toward a target +position: 锁定到目标物体
  • +
  • Repositioning and reorientation of the camera to face the same +direction as the player character
  • +
  • Transitions from first to third person cameras: +要保证当相机移动地充分远的时候才渲染物体,避免穿帮,此时可通过fade角色解决此问题
  • +
  • Transitions from third to first person cameras: 可通过cut +transition实现
  • + +

    Reorientation Methods

    +

    Applying rotations

    +

    有几种方法去应用旋转:

    +
  • Constant angular velocity: +匀速变动旋转角,但是开始和结束会有突变
  • +
  • Acceleration and deceleration: 应用加速度与减速度
  • +
  • Angular velocity damping: 用damp使开始结尾更皮规划
  • +
  • Free-look damping: 用bump和其他的ease +functions防止因noise导致的相机朝向变动
  • +
  • Twist reduction
  • -

    Gamera Scripting

    -

    What is Meant by Scripting

    -

    定义与控制物体加偶和的过程被称为scripting,在游戏中,指控制游戏事件发生的事件与物体之间的交互。Scripting允许设计师在没有程序员介入的情况下完成迭代

    -

    Types of Scripting

    -

    我们希望构建一个与游戏类型无关的scripting系统,主要由两个方面组成:scripting -language和event messaging

    -

    Scripting languages

    +

    Reorientation lag

    +

    通常我们希望相机朝向的变化能有一些延迟(lag),同时保持平滑

    +

    很多游戏没有任何延迟,这有两个影响:第一,相机直接看向角色会导致玩家不能提前看见角色的移动,第二,相机非常依赖角色的移动,任何小的扰动就会影响相机表现

    +

    因此需要使小的移动没有影响,并且使用damp。当插值的时候,可以限制每帧允许的旋转角度。此外,lag还可以通过用springs或feedback +controller实现

    +

    Offsets

    +

    一个常被忽略的点是look-at position和target +object之间的关系。如果直接看向角色,那么就容易丢失玩家想要看的东西。可以用一些视觉提示帮助玩家瞄准目标对象,比如highlight敌人,或者lock-on +to the target object

    +

    Smoothing and damping

    +

    常用的平滑方法是limit the angular velocity of the camera +proportionally to the angle between the current and desired +orientations,这可以表示为一个简单的三角函数:

    +
    Real32 const kDampingAngle(30.0f * gkRadiansPerDegree);
    Real32 angle = acosf(CVector3f::Dot(currentOrientation, desiredOrientation));
    Real32 const kDampingFactor = Cmath::Limit(angle / kDampingAngle, 1.0f); // linearly proportional
    Real32 angularLimit = angularSpeed * deltaTime * kDampingFactor;
    CQuaternion newOrientation = CQuaternion::LookAt(currentOrientation, desiredOrientation, angularLimit);
    +

    始终记住我们有两个矛盾的要求:平滑移动和保持角色合理视角

    +

    Springs and PID controllers

    +

    In practice, tuning the characteristics of the controller to achieve +this behavior can be time-consuming but very worthwhile

    +

    Free-Look

    +

    First person free-look

    +

    很多一人称游戏采用circle +strafing技术允许玩家free-look,有些游戏也只允许垂直方向的朝向变化,当然也要限制最大角度

    +

    Third person free-look

    +

    用一个圆锥体围绕look-at点,并使用一个弹簧在没有输入指令的时候令相机能够回到初始位置

    +

    Free-look orientation +determination

    +

    决定free-look朝向通常有两种方法:self-centering和non-centering

    -

    Event messaging

    -

    Event -messaging要求定义不同物体之间的关系。典型的能够发送消息的事件包括:

    +

    Common orientation problems

    +

    一些常见的相机朝向的问题:

    -

    能够被事件发送的典型消息包括:

    +

    Chapter 8: Navigation and +Occulusion

    +

    Dynamic determination of how the camera should reach its desired +position is referred to here as navigation

    +

    The Cemera as an AI Game +Object

    +

    需要假定环境是封闭的,即有碰撞表面

    + +

    相机的寻路需要考虑环境限制

    +

    Dynamic navigation +techniques

    +

    主要包括以下方法:

    -

    Script Objects

    -

    用于定义物体的属性和行为

    -

    Scriptable game hints

    -

    Game hints are script objects that provide one possible type of -runtime mechanism by which designers can override player properties, -game controls or camera properties according to events

    +

    Pre-defined navigation +techniques

    +

    一些常见的pre-defined navigation技术:

    +

    Occulision

    +

    Occulusion determination

    -
  • Control hints +
  • Ray casting: 通常使用三个部分进行遮挡检测——头部、躯体和脚部
  • +
  • Volume casting
  • +
  • Rendering techniques:
  • -

    很多时候事件需要有先后顺序,一个sequenced event -manager可以用来定义事件的先后顺序。

    -

    Camera Scripting

    -

    Camera scripting methods

    +

    Occulusion prediction +methodologies

    +

    可以用一个predictive相机预测遮挡

    +

    Line of Sight

    +

    Resolving line of sight +problems

    +

    可能有时候相机不能快速移动保持对目标物体的LOS,下面是一些可能的解决方案:

    -

    DCamera control

    +

    Path generation

    +

    该方法生成一条路径,相机沿着路径移动直到遮挡消失,生成的路径不仅要避免碰撞,并且也要符合美学要求:

    -

    一些经验法则:

    +

    Avoiding loss of LOS

    +

    如果不能避免loss of LOS,我们可以采取一些方法进行弥补:

    -

    Scripting Tools

    -

    World editor support

    -

    必须支持script objects的放置与操作,而且还要支持message passing, -state transition, event trigger和其他物体间的关系

    -

    Communication -between target platform and development PC

    -

    要获得运行物体的状态

    -

    Messaging/event logging

    -

    对消息和事件进行记录

    -

    Object properties debugging

    -

    当游戏运行时要动态检查物体的属性

    -

    Replay

    -

    最简单的方法是内置video recording

    -

    Console window

    -

    支持打印文本消息,通过GM指令查看想要的文本消息

    -

    Scripting Debugging

    -

    常见的debugging方法:

    +

    Fail-safes

    +

    Fail-safe检测可以分为三类:

    -

    Part 3: Camera Engineering

    -

    Chapter 7: Position and -Orientation

    -

    Coordinate Schemes

    -

    有几种不同的坐标空间:

    +
  • Per-update: 在一些情况下必须在每个update进行fail-safe检测 -

    Desired Position

    -

    在相机移动的过程中需要关注与目标点的距离

    -

    First person camera -positioning

    -

    大多数情况下,相机的desired -position就是角色眼睛的位置,此时增加一点dvertical -amping会有用。在玩家遇到崎岖地形或与物体碰撞时,需要smooth -out轻微的相机运动

    -

    Third person camera -positioning

    -

    有三种策略决定相机位置:

    +
  • Geometry interpenetration of the camera near plane: +可以用一个足够大的collision volume避免
  • +
  • An invalid (non-normalized) camera transformation matrix: +此时可以orthonormalize或者reconstruct矩阵,或者可以回到上次正确的旋转矩阵
  • +
  • The camera is external to the game world
  • +
  • Excessive rotation required aounrd the world up-axis in one update: +限制旋转角度
  • + +
  • Frequent: 有时候每隔几次update进行一次fail-safe检测
  • +
  • Infrequent: 每隔几秒检测一次 +
  • -

    Desired Position -Determination Methods

    -

    相机位置应该独立于朝向,尽管后者常常依赖于前者。下面是一些决定desired -position的方法

    -

    Stationary

    -

    主要有两种stationary cameras: fixed position 和 dynamic fixed -position:

    +

    一旦触发fail-safe condition,最好是立刻将相机移动到新的safe +position,通常是jump +cut。另一个方法是把相机移动回过去的已知点直到满足条件

    +

    Chapter 9: Motion and +Collision

    +

    Camera Movement Sequence

    +

    我们可以按照下述过程移动相机:

    -

    Slaved/tracking

    -

    相机的offset可以采取以下的几种形式:

    +

    Character motion

    +

    首先看看人物移动会怎样影响第一人称和第三人称相机

    -

    Path

    -

    有几种不同类型的路径:

    +

    Movement methods

    +

    一些移动相机的方法包括:

    + -

    下面是决定路径位置的方法:

    +

    Smoothing and damping +techniques

    +

    Damping方法通常要用ease +functions,把一个输入值(0到1之间)映射到相同区间,只不过是非线性映射且开始和结尾的导数为零

    -

    Splines. 可以用brute -force的方法去计算spline的长度,代码如下

    float length(0.0f);
    for (int i = 0; i < controlPoints.Size(); ++i)
    {
    Vec3 pathPosition = EvaluateSegment(i, 0.0f);
    // start of i'th segment
    controlPoints[i].mLength = length;
    // save length at the control point
    for (int j = 1; i < kMaxSegmentSlices; ++j)
    // includes next control point
    {
    Vec3 newPosition = EvaluateSegment(i, j/kMaxSegmentSlices);
    Vec3 delta = newPosition - pathPosition;
    length += delta.Magnitude();
    // add the "length" of this slice
    pathPosition = newPosition;
    }
    } // length now holds the approximate total length

    -

    一种更快且准确的方法是用多项式逼近

    -

    Mapping functions. -最简单的是从时间到长度的线性映射,此时相机的速度不变,导致abrupt开始或结束。一种常见的方法是使用一个二维spline曲线(Hermite -curves),用户可以定义控制点和切线控制曲线的形状

    -

    Surface constrained

    -

    在一些情况下,相机可能限制在一个隐式的平面上,比如一个flat平面,一个椭球、圆柱等等,该平面的大小和朝向可能是动态的

    -

    下面是一些常见的surface类型:

    +

    Motion constraints

    +

    一般有下述几种相机约束:

    -

    Volume constrained

    -

    相机与圆柱体的碰撞检测:

    -
    Vec3 direction = currentPosition - cylinder.GetPosition();
    direction.SetZ(0.0f);
    float radius = direction.Magnitude();
    if (radius > kMaxRadius)
    radius = kMaxRadius;
    direction = direction.AsNormalized() * radius;
    Vec3 newPosition = cylinder.GetPosition() + direction;
    newPosition.SetZ(currentPosition.GetZ());
    -

    Framing

    -

    该方法在屏幕空间上保持目标角色的位置,这可以通过移动相机、修改FOV、伸缩viewport等方法实现

    -

    Object-framing relative

    -

    该方法不仅考虑物体在屏幕空间中的小,而且也考虑它和另一个物体之间的相对距离,一些因素包括:

    +

    Player camera control

    +

    一个原则: > The player should be not REQUIRED to manipulate the +camera simply to play the game, unless explicitly dictated by the game +design.

    +

    If camera-relative, the sheer act of moving the camera changes the +control reference frame and "pulls the rug out from under the player's +feet". Sadly, some games seem to treat this behavior as acceptable. It +is not. Changing the control reference frame without player knowledge is +counter to good game play practice.

    -

    Axis rotational/spindle

    -

    相机围绕游戏世界中的一个轴旋转、平移,适用于玩家需要围着一个物体导航的情况,或限制在一个圆柱物体的情况

    -

    一些影响相机位置的因素:

    +
  • Maunipulation of the camera position: +有时候允许玩家直接操纵相机,分为2D和3D相机
  • +
  • Observer cameras: 提供观察者相机,即可以随意自由移动的相机
  • +
  • Camera motion validation: 一些游戏不允许操纵相机位置
  • +
  • Positional control constraints: +Character-relative相机通常保持在玩家身后的一定区域内,一般不会让相机面朝角色。相机移动要尽可能平滑和慢以避免player +disorientation
  • -

    此外,我们也可以改变相机的朝向:

    +

    Camera position control +schemes

    +

    主要有两种方法决定相机位置:

    -

    玩家位置相对于spindle axis的半径可以作为mapping -function的输入,当玩家移动半径更小时,相机移动得更高

    -

    Common Position Problems

    +

    Manipulation of camera +orientation

    -

    Orientation

    -

    旋转有四种表示方法:欧拉角、变换矩阵、轴角和四元数

    -

    Desired Orientation -Determination Methods

    -

    Constant orientation

    -

    朝向不变,但是位置可以移动。可以变式为constant elevation -cameras,即只有pitch可以改变

    -

    这种相机可以用在:

    +

    Automated camera +positioning and orientation

    +

    除了cinematic +sequences之外,也有一些情况会需要相机自动改变位置和朝向:

    -

    Tracking a target object -or position

    -

    相机达到期望朝向的方法取决于目标物体的移动和相机的重朝向速度,此类相机一般保持固定的pitch

    -

    Look-at offset

    -

    许多三人称游戏使用一个固定的look-at offset

    -

    Locked look-at position

    -

    玩家的朝向也会随便改变

    -

    Target object position -prediction

    -

    Object framing

    -

    一个很好的例子是格斗游戏,双方玩家都希望自己和对方都能呈现在屏幕上,当玩家距离增加的时候,相机要么拉远,要么增大FOV,但是频繁切换FOV通常不可取

    -

    回放相机通常会从不同的视角呈现玩家行为

    -

    Idle wandering

    -

    A semi-random camera reorientation while the player character is -idle

    -

    Automated orientation -control

    -

    在没有玩家操作的情况下自动帮助相机转向:

    +

    Debug camera control

    +

    该相机需要在不影响游戏的情况完全由用户操作,同时,如果能在降低游戏运行速度的情况能以正常速度操作debugging +camera,则会非常有利于debug

    +

    Camera Collisions

    +

    The importance of camera +collisions

    +

    Camera collision可能引起的问题:

    -

    Reorientation Methods

    -

    Applying rotations

    -

    有几种方法去应用旋转:

    +

    Collision determination

    -

    Reorientation lag

    -

    通常我们希望相机朝向的变化能有一些延迟(lag),同时保持平滑

    -

    很多游戏没有任何延迟,这有两个影响:第一,相机直接看向角色会导致玩家不能提前看见角色的移动,第二,相机非常依赖角色的移动,任何小的扰动就会影响相机表现

    -

    因此需要使小的移动没有影响,并且使用damp。当插值的时候,可以限制每帧允许的旋转角度。此外,lag还可以通过用springs或feedback -controller实现

    -

    Offsets

    -

    一个常被忽略的点是look-at position和target -object之间的关系。如果直接看向角色,那么就容易丢失玩家想要看的东西。可以用一些视觉提示帮助玩家瞄准目标对象,比如highlight敌人,或者lock-on -to the target object

    -

    Smoothing and damping

    -

    常用的平滑方法是limit the angular velocity of the camera -proportionally to the angle between the current and desired -orientations,这可以表示为一个简单的三角函数:

    -
    Real32 const kDampingAngle(30.0f * gkRadiansPerDegree);
    Real32 angle = acosf(CVector3f::Dot(currentOrientation, desiredOrientation));
    Real32 const kDampingFactor = Cmath::Limit(angle / kDampingAngle, 1.0f); // linearly proportional
    Real32 angularLimit = angularSpeed * deltaTime * kDampingFactor;
    CQuaternion newOrientation = CQuaternion::LookAt(currentOrientation, desiredOrientation, angularLimit);
    -

    始终记住我们有两个矛盾的要求:平滑移动和保持角色合理视角

    -

    Springs and PID controllers

    -

    In practice, tuning the characteristics of the controller to achieve -this behavior can be time-consuming but very worthwhile

    -

    Free-Look

    -

    First person free-look

    -

    很多一人称游戏采用circle -strafing技术允许玩家free-look,有些游戏也只允许垂直方向的朝向变化,当然也要限制最大角度

    -

    Third person free-look

    -

    用一个圆锥体围绕look-at点,并使用一个弹簧在没有输入指令的时候令相机能够回到初始位置

    -

    Free-look orientation -determination

    -

    决定free-look朝向通常有两种方法:self-centering和non-centering

    +

    Collision geometry design

    +

    下面是一些设计场景的tips:

    -

    Common orientation problems

    -

    一些常见的相机朝向的问题:

    +

    Collision resolution

    +

    当我们检测到发生碰撞时,就需要决定相机怎么办,可以有以下几种策略:

    -

    Chapter 8: Navigation and -Occulusion

    -

    Dynamic determination of how the camera should reach its desired -position is referred to here as navigation

    -

    The Cemera as an AI Game -Object

    -

    需要假定环境是封闭的,即有碰撞表面

    - -

    相机的寻路需要考虑环境限制

    -

    Dynamic navigation -techniques

    -

    主要包括以下方法:

    +

    Disabling collision +detection

    +

    有时候我们不需要相机的碰撞检测。比如第一人称和第三人称视角的切换、path-based +cameras。总之取决于期望的相机效果

    +

    Avoiding camera collisions

    +

    可以动态生成一条相机跟随的路径,或者统一采用半透明的方式。在三人称游戏中,当玩家在墙角或无法移动的地区时,相机可能和角色碰撞,此时可以切换到第一人称中,或者旋转相机调整相机位置

    -

    Pre-defined navigation -techniques

    -

    一些常见的pre-defined navigation技术:

    +

    Chapter 10: Camera +Mathematics

    +

    摄像机的一些数学:

    -

    Occulision

    -

    Occulusion determination

    +
  • Camera orientation
  • +
  • Camera motion
  • +
  • Rendering +
  • +
  • General camera math +
  • +
  • Camera math problems and fixes +
  • -

    Occulusion prediction -methodologies

    -

    可以用一个predictive相机预测遮挡

    -

    Line of Sight

    -

    Resolving line of sight -problems

    -

    可能有时候相机不能快速移动保持对目标物体的LOS,下面是一些可能的解决方案:

    +

    Common Mathematical +Techniques

    +

    Look-at

    +

    此时通过一个旋转矩阵或四元数把当前的相机朝向变换到新的朝向

    +
    Mat4 const Mat4::LookAt (Vec3 const& source, Vec3 const& dest, Vec3 const& worldUpVector)
    {
    Vec3 viewDirection = Vece (dest - source).AsNormalized ();
    float dot = Vec3::Dot (viewDirection, worldUpVector);
    Vec3 unnormalizedUp = worldUpVector - (dot * vewDirection); // 相机的unnormalized Up axis
    Vec3 up = unnormalizedUp.AsNormalized (); // 相机的up axis
    Vec3 right = Vec3::Cross (up, viewDirection);

    // matrix ordering depends on row/column major
    return Mat4 (
    right[X], viewDirection[X], up[X], source[X],
    right[Y], viewDirection[Y], up[Y], source[Y],
    right[Z], viewDirection[Z], up[Z], source[Z]
    )
    }
    +

    注意到上面的变换矩阵是把世界空间中的点变换到相机在(0,0)点的位置

    +

    Roll removal

    +

    为了移除roll,我们需要重新计算view transform的right +axis同时保持当前的forward vector,然后可以通过叉乘决定up vector

    +

    Twist reduction

    +

    在三人称相机中,当物体在相机上方或者下方的时候,可能导致相机快速旋转。一个方法是检测相机绕着forward +vector旋转的速度,但是只有在forward vector几乎在和world up +axis平行的时候

    +

    World space to screen +space conversion

    +

    取决于projection算法

    -

    Path generation

    -

    该方法生成一条路径,相机沿着路径移动直到遮挡消失,生成的路径不仅要避免碰撞,并且也要符合美学要求:

    +

    Screen space to +camera/world space conversion

    +

    通常来说,神都会被设置为相机的近平面,或者一个特定的距离相机的距离

    +
    Vec3 const ConvertToWorldSpace (Mat4 const& cameraTransform, Vec3 const& screenPosition)
    {
    Vec3 const viewSpace = GetProjectionMatrix ().Inverted ().MultiplyOneOverW (screenSpacePosition);
    Vec3 const worldSpace = cameraTransform * viewSpace;
    return worldSpace;
    }
    +

    FOV conversion

    +

    考虑把HFOV转化为VFOV,假设我们知道了近平面距离和aspect +ratio,与HFOV

    +

    我们定义变量alphabeta: +

    alpha = HFOV / 2
    beta = VFOV / 2
    tan (alpha) = (viewport width / 2) / near plane distance
    tan (beta) = (viewport height / 2) / near plane distance

    +

    从而有:

    +
    tan (alpha) * near plane distance = viewport width / 2
    Near plane distance = (viewport width / 2) / tan (alpha)
    tan (beta) * near plane distance = viewport height / 2
    Near plane distance = (viewport height / 2) / tan (beta)
    +

    进而有:

    +
    (viewport width / 2) * tan (beta) = (viewport height / 2) * tan (alpha)
    tan (beta) = [(viewport height / 2) / (viewport width / 2)] * tan (alpha)
    tan (beta) = aspect ratio * tan (alpha)
    VFOV = 2 * arctan (tan (HFOV / 2) * aspect ratio)
    +

    所以,只要知道了aspect ratio和其中一个FOV,就可以求出另一个FOV

    +

    Quaternions

    +

    四元数的好处在于可以很方便地插值,且没有Gimbal Lock问题。

    +

    Bump and Ease Functions

    +

    Bump和ease +functions都用来保证开始和结束的平滑,ease函数分为ease-in和ease-out函数,ease-in函数也叫damping函数。下面讨论几个简单的函数来生成S型曲线

    +

    Exponentials

    +

    使用简单的三次函数:

    float exp = 3t^2 - 2t^3;

    +

    Proportional

    +

    Proportional ease +function使用当前值和期望值之间的差值作为输入,常用一个damping range: +

    float deltaValue = desiredValue - currentValue;
    if (fabs(deltaValue) < kRange>)
    {
    float factor = Math::Limit (deltaValue / kRange, 1.f);
    currentValue += kSpeed * factor * deltaTime;
    }

    +

    Proportional damping +function实现简单且高效,但是可能不如其他方法平滑。另一种方法是根据经过的时间计算factor: +

    float const dampingFactor (1.0f - elapsedTime / totalTime);
    interpolant += (destinationValue - interpolant) * dampingFactor * deltaTime;
    return interpolant;

    +

    Spherical linear +interpolation

    +

    球面线性插值

    +

    Transcendentals

    +

    用三角函数:

    +
    angle = (pi * time factor) - (pi / 2);  // in radians, -pi/2 ... pi/2
    time factor = (sinf(angle) + 1) / 2
    +

    Springs

    +

    当实现相机移动的时候我们常常碰到相机overshoot的问题,这是因为目标在不断移动,阻止相机足够快地改变方向、速度以避免被目标对象自身抢占位置,但同时我们也不想相机过快移动,这就导致了矛盾

    +

    此时我们可以使用弹簧方案,基于下述的方程:

    +

    +

    是弹性常量,一个正数表示弹簧的弹性,是弹簧伸缩度,这样我们可以写出下面的伪代码: +

    Vec3 deltaPosition = desiredPosition - currentPosition;
    Vec3 movementDirection = deltaPosition.AsNormalized ();
    float extension = deltaPosition.Magnitude ();
    float force = -kSpringConstant * extension; // for a unit mass, this is acceleration, F = ma
    Vec3 newVelocity = currentVelocity + (movementDirection * force);
    new Position = currentPosition + (currentVelocity * deltaTime);

    +

    弹簧方案的一个问题是设置弹簧的弹性常量,并且会出现震荡现象,这可以用两种思路解决:

    +

    Digital Filters

    +

    在控制器输入或相机移动中,我们想要移除小的震荡,此时可用滤波器

    +

    Low pass

    +

    低通滤波让低频信号通过,而过滤高频信号

    +

    High pass

    +

    与低通滤波相反

    +

    Band

    +

    移除某个频率范围之外的信号

    +

    Finite impulse response

    +

    有限脉冲响应滤波在计算当前值的时候结合之前的输入值,因为易于实现,所以与IIR滤波相比更倾向于FIR滤波

    +

    History +buffer中的每一项都有一个对应的滤波系数,对应了该项目的影响有多大,即改变对输入值的响应度

    +
    static float const firCoefficients[] = 
    {
    // these values greatly influence the filter
    // response and may be adjusted accordingly
    0.f, 0.f, 0.f, 1.f, 2.f, 3.f, 4.f
    };
    float CFIRFilter::Initialize (void)
    {
    // setup the coefficients for desired response
    for (int i = 0; i < mHistoryBuffer.size(); ++i)
    mCoefficients[i] = firCoefficients[i];
    }
    float CFIRFilter::Update (float const input)
    {
    // copy the entries in the history buffer up by one
    // position (i.e. lower entries are more recent)
    for (int i = mHistoryBuffer.size() - 2; i >= 0; --i)
    {
    // not efficient! Can use circular buffer
    mHistoryBuffer[i + 1] = mHistoryBuffer[i];
    }
    mHistoryBuffer[0] = input;
    float fir(0);
    // now accumulate the values from the history
    // buffer multiplied by the coefficients
    for (int i = 0; i > mHistoryBuffer.size(); ++i)
    {
    fir += mCoefficients[i] * mHistoryBuffer[i];
    }
    return fir;
    }
    +

    Infinite impulse response

    +

    不同于FIR,IIR也加入了之前的输出值

    +
    float CIIRFilter::Initialize (void)
    {
    mInputCoefficients[0] = 0.5f;
    mInputCoefficients[1] = 0.3f;
    mOutputCoefficients[0] = 0.5f;
    mOutputCoefficients[1] = 0.3f;
    }
    float CIIRFilter::Update (float const input)
    {
    for (int i = mInputHistoryBuffer.size() - 2; i >= 0; --i)
    {
    // not efficient! Can use circular buffer
    mInputHistoryBuffer[i + 1] = mInputHistoryBuffer[i];
    }
    mInputHistoryBuffer[0] = input;
    float const result =
    mInputCoefficients[0] * mInputHistoryBuffer[0] +
    mInputCoefficients[1] * mInputHistoryBuffer[1] +
    mOutputCoefficients[0] * mOutputHistoryBuffer[0] +
    mOutputCoefficients[1] * mOutputHistoryBuffer[1];
    for (int i = mOutputHistoryBuffer.size() - 2; i >= 0; --i)
    {
    // not efficient! Can use circular buffer
    mOutputHistoryBuffer[i + 1] = mOutputHistoryBuffer[i];
    }
    mOutputHistoryBuffer[0] = result;
    return result;
    }
    +

    Spline Curves

    +

    Spline由一系列控制点和对应的tangent +vector控制,每个segment通常由两个控制点组成,每个控制点有1~2个切线向量。相邻两个segment之间共享的控制点叫做joint

    +

    Camera spline usage

    +

    相机Spline的通常用法是定义一条路径,再用一个evaluation函数将时间映射到路径上的位置。二维spline通常用来表示物体的属性,三维spline通常用来表示空间位置

    +

    Cubic polynomials

    +

    三次多项式可以表示为:

    +

    +

    有时候需要给定解出

    +

    Spline types

    +

    下面介绍几种不同的spline types:

    -

    Avoiding loss of LOS

    -

    如果不能避免loss of LOS,我们可以采取一些方法进行弥补:

    +

    +
    Vec3 const QuadraticBezier (Vec3 const & a, Vec3 const & b, Vec3 const & c, float const time)
    {
    float const oneMinusTime (1.f - time);
    Vec3 const bezier = (a * oneMinusTime * oneMinusTime) + (b * 2.f * time * oneMinusTime) + (c * time * time);
    return bezier;
    }
    +

    三次贝塞尔曲线方程为:

    +

    +
    Vec3 const CubicBezier (Vec3 const & a, Vec3 const & b, Vec3 const & c, Vec3 const & d, float const time)
    {
    float const oneMinusTime (1.f - time);
    Vec3 const bezier = (a * oneMinusTime * oneMinusTime * oneMinusTime) + (b * 3.f * time * oneMinusTime * oneMinusTime) + (c * 3.f * time * time * oneMinusTime) + (d * time * time * time);
    return bezier;
    }
    -

    Fail-safes

    -

    Fail-safe检测可以分为三类:

    - +

    Continuity

    +

    C0是位置连续,C1是速度连续,C2是加速度连续。所以C1或更高的连续会在视觉上效果更好,C2或更高的连续会有更平滑的移动

    +

    Spline definitions

    +

    为了充分地定义spline curve,我们需要几个机制:

    +
  • 一个能够在游戏世界放置控制点的编辑器,甚至可以在游戏运行的时候生成
  • +
  • Spline evaluation type
  • +
  • 跨国spline的总的时间或一个映射函数
  • +
  • 一个可视化展示spline curve的界面,随参数改变动态变化
  • -

    一旦触发fail-safe condition,最好是立刻将相机移动到新的safe -position,通常是jump -cut。另一个方法是把相机移动回过去的已知点直到满足条件

    -

    Chapter 9: Motion and -Collision

    -

    Camera Movement Sequence

    -

    我们可以按照下述过程移动相机:

    +

    Spline evaluation

    +

    可以预先计算整个spline的长度,然后用一个线性长度作为spline上的位置。如果再搭配速度damping则会产生比较平滑的效果

    +

    Control point generation

    -

    Character motion

    -

    首先看看人物移动会怎样影响第一人称和第三人称相机

    +

    Parameterized arc length

    +

    积分法

    +

    Total spline length

    +

    总长度是各个spline弧长度的和,往往采用数值方法近似曲线长度

    +

    Closest position

    +

    计算spline上离某个位置最近的点往往很有用,但问题是可能有多个解,这时候就需要对这些解做个排序,比如考虑相机的前一个位置或者LOS,或者相机的角速度

    +
    Determine the nornal at each end of the segment and by using similar triangles
    Determine the length on the segment
    If length within 0..1 then
    Convert linear 0..1 into a parametric value
    With parametric value 0..1 find the position within the arc using the usual spline evaluation
    Check position against source position for LOS and other factors
    If OK, determine the physical distance between two points and compare to current "best"
    Else
    Not within segment, so proceed to next segment
    +

    Spline editing

    +

    开发能够编辑spline的工具

    +

    Interpolation

    +

    线性插值在一对数据点中生成新数据,piecewise插值则是由几个连续的数据点去生成。相机朝向往往用非线性插值

    +

    Camera Property +Interpolation

    +

    Position interpolation

    +

    位置插值应该是基于当前的位置和目标位置,用这个距离相比于原来的距离

    +
    Vec3 interpFactor = CMath::Clamp (0.0f, interpTimer/maxInterpTime, 1.0f);
    Vec3 currentDeltaPosition = desiredPosition - GetTranslation ();
    Vec3 newPosition = GetTranslation () + (currentDeltaPostion * interpFactor);
    // when interpTimer reaches maxInterpTime, the camera reaches the destination
    +

    Orientation interpolation

    +

    朝向插值通常不涉及roll,即使需要考虑roll,也会单独处理

    +

    由于小的朝向改变会引起巨大的视觉变化,所以一定要确保朝向插值的平滑。线性插值并不保证对象一定在视野里。如果朝向改变很大,要限制角速度,或者使用jump +cut。朝向插值也要保证路径最短

    -

    Movement methods

    -

    一些移动相机的方法包括:

    +

    FOV interpolation

    +

    如果没有其他渲染效果,那么只改变FOV就显得很突兀,快速的FOV改变会让玩家不适,这时候一个jump +cut反而更好。zoom in也是通过FOV实现的

    +
    float targetFOV = GetTargetFOV ();
    float deltaFOV = mFOV - targetFOV;
    float newFOV = targetFOV + (deltaFOV * deltaTime);
    float newDeltaFOV = newFOV - targetFOV;
    if (absF(newDeltaFOV) < absF(deltaFOV))
    {
    mFOV = newFOV;
    }
    +

    Viewport Interpolation

    +

    改变显示设备的大小,通常用于cinematic sequences和regular game +play之间的转换。比如从2.35:1到1.33:1

    +

    Player Control Interpolation

    +

    First person cameras

    +

    control interpolation通常用于从一个第一人称control reference +frame变化到一个fixed control reference frame比如object orbiting

    +

    Third person cameras

    +

    在很多情况下,我们要保证如果相机出现巨大移动,则玩家控制不会马上改变

    +

    一个问题是如何处理玩家移动比相机移动快的问题,而且玩家绕着相机垂直轴的任何移动会导致相机绕着该轴的快速转动

    +

    Interpolation Choices

    +

    首先要问现有的数据是kay value还是control +values;第二,要考虑插值方法的效率和效果;第三,要考虑插值结果的平滑性;最后,也要考虑不同插值方法需要的数据量

    +

    Linear interpolation

    +

    线性插值只需要三个参数:source value, destination +value和interpolation method

    +

    Destination value往往会随时间改变,我们就需要考虑到destination +value的变化率,当插值的变化率不匹配目标值的变化率时,不连续就会发生

    +

    插值方法需要考虑是否要用固定的时间完成插值。不考虑变化率会在开始和结束时产生不连续现象

    +

    Piecewise interpolation

    +

    通常有多于两个数据点进行插值,一种策略是把它们视为独立的interpolation +segments:

    bool foundTime (false);
    for (int i = 0; i < valueTimes.Size() - 1; ++i)
    {
    if (valueTimes[i+1] > time)
    {
    float timeDelta = valueTimes[i+1] - valueTimes[i];
    timeFactor = (time - valueTimes[i]);
    segment = i;
    source = values[i];
    destination = values[i+1];
    foundTime = true;
    break;
    }
    }
    if (foundTime)
    return Interpolate (source, destination, timeFactor);

    +

    此外,也可以在每对数据点中假设均匀时间区间,但会有比较大的问题

    +

    Methods of Interpolation

    +

    Linear time interpolation

    +
    Interpolated value = source + ((destination - source) * t)
    +

    Parametric functions

    +

    比如ease函数

    +

    Spherical linear +interpolation

    +

    用于角的插值

    +

    Potential Interpolation +Problems

    +

    Aesthetic problems

    +

    一些视觉上的问题包括:

    +

    Mathematical problems

    +

    数学上的问题一般是由浮点误差导致的:

    -
  • Locked
  • -
  • Proportional controller: 该方法在目标也移动的时候表现不好 -
    Vec3 const deltaPosition = desiredPosition - currentPosition;
    // the distance at which velocity damping is applied
    float const kDampDistance (5.0f);
    float const K = Math::Limit (deltaPosition.Magnitude() / kDampDistance, 1.0f);
    // Limit constant to 0..1 based on distance
    Vec3 const cameraVelocity = deltaPosition.AsNormalized () * K;
    Vec3 const newPosition = currentPosition + cameraVelocity * deltaTime;

    // We can help solve the problem of the camera being left behind by adding a
    // portion of the target object's velocity into the original equation.
    Vec3 targetVelocity = (desiredPosition - previousDesiredPosition) / deltaTime;
    Vec3 = cameraVelocity = (deltaPosition.AsNormalized () * K * deltaTime) + (targetVeclocity * T);

    // To have smooth motion we need to accelerate the camera over time
    // with a limiter to provide some degree of lag in the motion.
    float const acceleration = Math::Limit ( (desiredVelocity - currentVelocity), kMaxAcceleration);
    Vec3 const currentVelocity += acceleration * deltaTime;
    Vec3 const desiredPosition = currentPosition + (currentVelocity * deltaTime);
  • -
  • Physical simulations
  • -
  • Springs: -当目标物体朝相机移动或突然停止时,相机可能出现overshooting问题,我们希望critical -damping,即无论目标物体怎么动,都不会出现overshooting
  • -
  • PID controllers: proportional integral derivative (PID) -controllers,把feedback应用到控制器中减少当前值和期望值的错误量 -
    // The usage of PID controller
    Vec3 const currentDelta = currentPosition - desiredPosition;
    float const currentDistance = currentDelta.Magnitude ();
    float const newDistance = PIDController.Update (desiredDistance, currentDistance, deltaTime);
    Vec3 const currentPosition = desiredPosition + (currentDelta.AsNormalized () * newDistance);
  • -
  • Circular movement: 相机的运动由reference -point到当前位置和期望位置之间的夹角决定,因此需要计算其角速度,有两个方法计算: +
  • Co-linear (or exactly opposed) orientation
  • +
  • Coincident positions: 0为除数
  • +
  • Floating-point inaccuracy
  • + +

    Interruption of +Interpolation

    +

    有可能在一个插值过程中触发了另一个插值,这时候可以从当前值开始直接开始新的插值

    +

    Transitions

    +

    Position during transitions

    +

    Orientation during +transitions

    +

    有两种方法在transition的过程中控制插值相机的朝向,如果source和des相机没有reorienting,那么简单的线性插值或slerp可以处理得很好,但如果有一个或者两个都reorient就会有问题。一个方法是计算从目标值到当前值之间得剩余量(比如角度),如果新的插值大于当前值,则忽略

    +

    Camera Math Problems

    +

    Floating-point precision

    +

    相机系统一般用单精度浮点数,所以不能表示很大的数

    +

    Epsilon usage

    +

    要根据用途改变epsilon的值

    +

    Compiler differences

    +

    编译器也有不同

    +

    Hardware FPU differences

    +

    Vector normalization

    +

    Matrix concatenation +floating-point drift

    +

    在应用旋转矩阵后,正交化该矩阵以保证浮点精确度

    +

    Periodic Camera Mathematical +Fixes

    +

    最好在渲染之前检查当前的相机变换是不是正确的,包括:

    -
  • Interpolation: -考虑在两个相机的速度之间插值,为了避免discontinuity,要让加速度匹配而不仅仅是速度
  • +
  • 变换矩阵的每个元素不包含异常值,比如NaN
  • +
  • 变换矩阵的每个向量都是单位向量
  • +
  • Up-vector和游戏内的Up-vector一致
  • +
  • 必要时移除roll
  • +
  • 必要时限制相机快速的reorientation
  • -

    Smoothing and damping -techniques

    -

    Damping方法通常要用ease -functions,把一个输入值(0到1之间)映射到相同区间,只不过是非线性映射且开始和结尾的导数为零

    +

    如果矩阵不能被修复,则使用上一帧的矩阵;记得多正交化矩阵

    +

    Chapter 11: Implementation

    +

    Game Engine Architecture

    +

    Game update loop

    +

    大多数相机逻辑都要在其他逻辑之后执行,典型的执行顺序是:

    -

    Motion constraints

    -

    一般有下述几种相机约束:

    +

    Game system managers

    +

    一些管理系统包括:

    -

    Player camera control

    -

    一个原则: > The player should be not REQUIRED to manipulate the -camera simply to play the game, unless explicitly dictated by the game -design.

    -

    If camera-relative, the sheer act of moving the camera changes the -control reference frame and "pulls the rug out from under the player's -feet". Sadly, some games seem to treat this behavior as acceptable. It -is not. Changing the control reference frame without player knowledge is -counter to good game play practice.

    +

    Delta time

    +

    现在游戏通常将逻辑层与渲染层分开,这有利于CPU处理和GPU渲染,游戏逻辑可能以固定的速率更新,也可能以动态的速度更新,从而,相邻两次更新的时间间隔不一定一致,经过的时间就称为delta +time

    +

    Input processing

    +

    很多相机需要把输入值传递给它们,这通常由相机管理器实

    +

    Camera System Architecture

    +

    Viewport manager

    +

    主要工作是包含所有在场景内需要渲染的东西,处理控制器输入、渲染、masking、buffer管理、aspect +ratio等等,能够被其他游戏系统用于访问关于当前活跃相机的相机系统。数据结构是:

    +
    class CViewportManager
    {
    public:
    typedef int32 TViewportHandle;
    TViewportHandle const CreatViewport (EViewportType);
    void DeleteViewport (TViewportHandle const viewport);
    void Update (float const deltaTime);
    void ProcessInput (CInput const & input);
    CViewport const & GetViewport (TViewportHandle const handle) const;
    }
    +

    在定义了显示媒介之后,我们需要描述投影,因此VM需要:

    +

    每个Viewport都控制了所有需要渲染的信息,比如相机、控制器输入、surface +locatio and +size、渲染模式等等,甚至还包含了用于多种输出设备渲染需要的信息

    +

    VM还处理不同viewport之间的过渡,通常用于玩家在菜单界面、暂停时,或者画中画。Transition可能包括:

    -
  • Observer cameras: 提供观察者相机,即可以随意自由移动的相机
  • -
  • Camera motion validation: 一些游戏不允许操纵相机位置
  • -
  • Positional control constraints: -Character-relative相机通常保持在玩家身后的一定区域内,一般不会让相机面朝角色。相机移动要尽可能平滑和慢以避免player -disorientation
  • +
  • Cut
  • +
  • Wipe
  • +
  • Cross fade
  • +
  • Morphing
  • -

    Camera position control -schemes

    -

    主要有两种方法决定相机位置:

    +

    Render manager

    +

    从当前的viewports和cameras获取数据并渲染,此外会移除frustum外的的物体,决定渲染顺序,应用后处理

    +

    Camera manager

    +

    CM的主要责任是扮演所有相机的控制器,生成相机新实例、处理转场、插值、优先级、控制器输入、replay +modes和时间控制

    +

    CM有Update函数,处理步骤是:

    -

    Manipulation of camera -orientation

    +

    Camera update loop

    +

    相机一般是下面的更新逻辑:

    -

    Automated camera -positioning and orientation

    -

    除了cinematic -sequences之外,也有一些情况会需要相机自动改变位置和朝向:

    +

    Hint manager

    +

    每个CM都有一个与之关联的camera hint manager (CHM)

    +

    Shake manager

    +

    相机震动一般发生在渲染阶段而不是实际移动相机,因为这可能导致相机穿过物体。Shake +transform在局部相机空间中计算应用在渲染之前

    +

    相机震动有三个组件:

    -

    Debug camera control

    -

    该相机需要在不影响游戏的情况完全由用户操作,同时,如果能在降低游戏运行速度的情况能以正常速度操作debugging -camera,则会非常有利于debug

    -

    Camera Collisions

    -

    The importance of camera -collisions

    -

    Camera collision可能引起的问题:

    +

    Game Cameras

    +

    Inherited camera behaviors

    +

    可以用下面的层级去实现相机类:

    -

    Collision determination

    +

    Component-based camera +behaviors

    +

    不用类继承的方式,另一种方法是使用component-based相机。任何相机的属性都可以拆分为一些可交换的组件,称为behavior,这些behavior能够在运行时组合或交换以产生很多相机变体。一些behavior包括:

    -

    Collision geometry design

    -

    下面是一些设计场景的tips:

    +

    尽管单个component从设计上讲是独立的,但是可能某个特定的component,比如orientation,依赖于其他component的状态,所以需要有特定的component更新顺序

    +

    Cinematic cameras

    +

    通常会把cinematic camera与game +camera分开考虑,有自己独立的viewport

    +

    Debug camera

    +

    只用于render

    +

    Scripting System +Implementation

    +

    Camera script objects

    +

    有时候需要动态改变相机行为,这就是scripting,一些script +objects包括:

    -

    Collision resolution

    -

    当我们检测到发生碰撞时,就需要决定相机怎么办,可以有以下几种策略:

    +

    Ordering of scripting logic

    +

    如果scripting +logic引起任何需要发送的消息,则它们会立即发送给接收者,但是可能此时接收者已经执行了自己的逻辑,所以要等到下个update时才能做出对当前消息的反应,可以把message +cache

    +

    Messaging

    +

    当事件发生时,需要通知其他游戏物体事件的发生,这一般用messaging +system实现。实际的消息只包含了与该事件有关的信息,比如发送消息的物体、消息本身、其他可能触发该消息的物体

    +

    比如当玩家进入trigger volume时,会让对应的script +object发送一个enter消息、是谁发送的消息

    +

    Prioritization

    +

    可用一个整数代表优先级,也可以用属性表示优先级,比如和玩家之间的距离

    +

    Interpolation

    +

    可以用一个专门的interpolation camera管理相机插值

    +

    Performance Considerations

    +

    Amortization

    +

    一般用于缓存几个update内的中间值,但相机移动需要立即执行。在采用amortization之前,需要考虑哪些属性不需要每次update都更新,哪些属性需要立即更新

    +

    Preprocessing

    +

    大多数的相机CPU消耗都用于ray +casting或碰撞检测,预处理,如沿着特定轨道的相机移动,可以减少CPU开销

    +

    Tools Support

    +

    World editor

    +

    大多数常用的属性都以易用的界面实现,比如camera path definition, +camera hint placement,property editing, pre-defined macros of script +objects:

    -

    Disabling collision -detection

    -

    有时候我们不需要相机的碰撞检测。比如第一人称和第三人称视角的切换、path-based -cameras。总之取决于期望的相机效果

    -

    Avoiding camera collisions

    -

    可以动态生成一条相机跟随的路径,或者统一采用半透明的方式。在三人称游戏中,当玩家在墙角或无法移动的地区时,相机可能和角色碰撞,此时可以切换到第一人称中,或者旋转相机调整相机位置

    +

    Camera collision mesh

    +

    Camera有自己的collision geometry会更方便,因为可以允许动态改变

    +

    Camera Debugging Techniques

    +

    Interactive debugging

    +

    Interactive debugging包括:

    -

    Chapter 10: Camera -Mathematics

    -

    摄像机的一些数学:

    +

    Data logging

    +

    注意logging对游戏性能的影响,一个优化是cache日志信息直到某个不影响游戏性能的时间点

    +

    在获取log之后,除了直接阅读文本之外,还可以采用可视化的手段,把数据导入游戏复盘相机数据

    +

    Game replaying

    +]]> + + 游戏 - 游戏理论 + + + 随笔 + 相机 + 游戏 + 设计 + +
    + + 《游戏设计的236个技巧》笔记 + /2021/08/17/01/07/ + 本文是《游戏设计的236个技巧:游戏机制、关卡设计和镜头窍门》的笔记。

    + +

    前言

    +

    一款优秀的游戏是如何让玩家在某个瞬间感到无比有趣、极度畅快的呢?本书旨在引领读者发现“让游戏更有趣的设计技巧”。 +本书将内容分为“玩家角色”“敌人角色”“关卡设计”“碰撞检测”“镜头”五个部分。

    +

    让3D游戏更有趣的玩家角色技术

    +

    能够吸引2D游戏玩家的3D游戏设计技巧(《超级马里奥兄弟》《超级马里奥3D大陆》)

    +

    B键冲刺带来的感官刺激以及风险与回报的趣味性

    +

    勾起玩家跳跃冲动的互动式玩法

    -

    Common Mathematical -Techniques

    -

    Look-at

    -

    此时通过一个旋转矩阵或四元数把当前的相机朝向变换到新的朝向

    -
    Mat4 const Mat4::LookAt (Vec3 const& source, Vec3 const& dest, Vec3 const& worldUpVector)
    {
    Vec3 viewDirection = Vece (dest - source).AsNormalized ();
    float dot = Vec3::Dot (viewDirection, worldUpVector);
    Vec3 unnormalizedUp = worldUpVector - (dot * vewDirection); // 相机的unnormalized Up axis
    Vec3 up = unnormalizedUp.AsNormalized (); // 相机的up axis
    Vec3 right = Vec3::Cross (up, viewDirection);

    // matrix ordering depends on row/column major
    return Mat4 (
    right[X], viewDirection[X], up[X], source[X],
    right[Y], viewDirection[Y], up[Y], source[Y],
    right[Z], viewDirection[Z], up[Z], source[Z]
    )
    }
    -

    注意到上面的变换矩阵是把世界空间中的点变换到相机在(0,0)点的位置

    -

    Roll removal

    -

    为了移除roll,我们需要重新计算view transform的right -axis同时保持当前的forward vector,然后可以通过叉乘决定up vector

    -

    Twist reduction

    -

    在三人称相机中,当物体在相机上方或者下方的时候,可能导致相机快速旋转。一个方法是检测相机绕着forward -vector旋转的速度,但是只有在forward vector几乎在和world up -axis平行的时候

    -

    World space to screen -space conversion

    -

    取决于projection算法

    +

    从《2D马里奥》到《3D马里奥》

    -

    Screen space to -camera/world space conversion

    -

    通常来说,神都会被设置为相机的近平面,或者一个特定的距离相机的距离

    -
    Vec3 const ConvertToWorldSpace (Mat4 const& cameraTransform, Vec3 const& screenPosition)
    {
    Vec3 const viewSpace = GetProjectionMatrix ().Inverted ().MultiplyOneOverW (screenSpacePosition);
    Vec3 const worldSpace = cameraTransform * viewSpace;
    return worldSpace;
    }
    -

    FOV conversion

    -

    考虑把HFOV转化为VFOV,假设我们知道了近平面距离和aspect -ratio,与HFOV

    -

    我们定义变量alphabeta: -

    alpha = HFOV / 2
    beta = VFOV / 2
    tan (alpha) = (viewport width / 2) / near plane distance
    tan (beta) = (viewport height / 2) / near plane distance

    -

    从而有:

    -
    tan (alpha) * near plane distance = viewport width / 2
    Near plane distance = (viewport width / 2) / tan (alpha)
    tan (beta) * near plane distance = viewport height / 2
    Near plane distance = (viewport height / 2) / tan (beta)
    -

    进而有:

    -
    (viewport width / 2) * tan (beta) = (viewport height / 2) * tan (alpha)
    tan (beta) = [(viewport height / 2) / (viewport width / 2)] * tan (alpha)
    tan (beta) = aspect ratio * tan (alpha)
    VFOV = 2 * arctan (tan (HFOV / 2) * aspect ratio)
    -

    所以,只要知道了aspect ratio和其中一个FOV,就可以求出另一个FOV

    -

    Quaternions

    -

    四元数的好处在于可以很方便地插值,且没有Gimbal Lock问题。

    -

    Bump and Ease Functions

    -

    Bump和ease -functions都用来保证开始和结束的平滑,ease函数分为ease-in和ease-out函数,ease-in函数也叫damping函数。下面讨论几个简单的函数来生成S型曲线

    -

    Exponentials

    -

    使用简单的三次函数:

    float exp = 3t^2 - 2t^3;

    -

    Proportional

    -

    Proportional ease -function使用当前值和期望值之间的差值作为输入,常用一个damping range: -

    float deltaValue = desiredValue - currentValue;
    if (fabs(deltaValue) < kRange>)
    {
    float factor = Math::Limit (deltaValue / kRange, 1.f);
    currentValue += kSpeed * factor * deltaTime;
    }

    -

    Proportional damping -function实现简单且高效,但是可能不如其他方法平滑。另一种方法是根据经过的时间计算factor: -

    float const dampingFactor (1.0f - elapsedTime / totalTime);
    interpolant += (destinationValue - interpolant) * dampingFactor * deltaTime;
    return interpolant;

    -

    Spherical linear -interpolation

    -

    球面线性插值

    -

    Transcendentals

    -

    用三角函数:

    -
    angle = (pi * time factor) - (pi / 2);  // in radians, -pi/2 ... pi/2
    time factor = (sinf(angle) + 1) / 2
    -

    Springs

    -

    当实现相机移动的时候我们常常碰到相机overshoot的问题,这是因为目标在不断移动,阻止相机足够快地改变方向、速度以避免被目标对象自身抢占位置,但同时我们也不想相机过快移动,这就导致了矛盾

    -

    此时我们可以使用弹簧方案,基于下述的方程:

    -

    -

    是弹性常量,一个正数表示弹簧的弹性,是弹簧伸缩度,这样我们可以写出下面的伪代码: -

    Vec3 deltaPosition = desiredPosition - currentPosition;
    Vec3 movementDirection = deltaPosition.AsNormalized ();
    float extension = deltaPosition.Magnitude ();
    float force = -kSpringConstant * extension; // for a unit mass, this is acceleration, F = ma
    Vec3 newVelocity = currentVelocity + (movementDirection * force);
    new Position = currentPosition + (currentVelocity * deltaTime);

    -

    弹簧方案的一个问题是设置弹簧的弹性常量,并且会出现震荡现象,这可以用两种思路解决:

    +

    小结

    -

    Digital Filters

    -

    在控制器输入或相机移动中,我们想要移除小的震荡,此时可用滤波器

    -

    Low pass

    -

    低通滤波让低频信号通过,而过滤高频信号

    -

    High pass

    -

    与低通滤波相反

    -

    Band

    -

    移除某个频率范围之外的信号

    -

    Finite impulse response

    -

    有限脉冲响应滤波在计算当前值的时候结合之前的输入值,因为易于实现,所以与IIR滤波相比更倾向于FIR滤波

    -

    History -buffer中的每一项都有一个对应的滤波系数,对应了该项目的影响有多大,即改变对输入值的响应度

    -
    static float const firCoefficients[] = 
    {
    // these values greatly influence the filter
    // response and may be adjusted accordingly
    0.f, 0.f, 0.f, 1.f, 2.f, 3.f, 4.f
    };
    float CFIRFilter::Initialize (void)
    {
    // setup the coefficients for desired response
    for (int i = 0; i < mHistoryBuffer.size(); ++i)
    mCoefficients[i] = firCoefficients[i];
    }
    float CFIRFilter::Update (float const input)
    {
    // copy the entries in the history buffer up by one
    // position (i.e. lower entries are more recent)
    for (int i = mHistoryBuffer.size() - 2; i >= 0; --i)
    {
    // not efficient! Can use circular buffer
    mHistoryBuffer[i + 1] = mHistoryBuffer[i];
    }
    mHistoryBuffer[0] = input;
    float fir(0);
    // now accumulate the values from the history
    // buffer multiplied by the coefficients
    for (int i = 0; i > mHistoryBuffer.size(); ++i)
    {
    fir += mCoefficients[i] * mHistoryBuffer[i];
    }
    return fir;
    }
    -

    Infinite impulse response

    -

    不同于FIR,IIR也加入了之前的输出值

    -
    float CIIRFilter::Initialize (void)
    {
    mInputCoefficients[0] = 0.5f;
    mInputCoefficients[1] = 0.3f;
    mOutputCoefficients[0] = 0.5f;
    mOutputCoefficients[1] = 0.3f;
    }
    float CIIRFilter::Update (float const input)
    {
    for (int i = mInputHistoryBuffer.size() - 2; i >= 0; --i)
    {
    // not efficient! Can use circular buffer
    mInputHistoryBuffer[i + 1] = mInputHistoryBuffer[i];
    }
    mInputHistoryBuffer[0] = input;
    float const result =
    mInputCoefficients[0] * mInputHistoryBuffer[0] +
    mInputCoefficients[1] * mInputHistoryBuffer[1] +
    mOutputCoefficients[0] * mOutputHistoryBuffer[0] +
    mOutputCoefficients[1] * mOutputHistoryBuffer[1];
    for (int i = mOutputHistoryBuffer.size() - 2; i >= 0; --i)
    {
    // not efficient! Can use circular buffer
    mOutputHistoryBuffer[i + 1] = mOutputHistoryBuffer[i];
    }
    mOutputHistoryBuffer[0] = result;
    return result;
    }
    -

    Spline Curves

    -

    Spline由一系列控制点和对应的tangent -vector控制,每个segment通常由两个控制点组成,每个控制点有1~2个切线向量。相邻两个segment之间共享的控制点叫做joint

    -

    Camera spline usage

    -

    相机Spline的通常用法是定义一条路径,再用一个evaluation函数将时间映射到路径上的位置。二维spline通常用来表示物体的属性,三维spline通常用来表示空间位置

    -

    Cubic polynomials

    -

    三次多项式可以表示为:

    -

    -

    有时候需要给定解出

    -

    Spline types

    -

    下面介绍几种不同的spline types:

    +

    让游戏更具临场感的玩家角色动作设计技巧(战神三)

    +

    不需控制镜头的移动操作机制

    +

    实现快节奏战斗的玩家移动动作机制

    -

    -
    Vec3 const QuadraticBezier (Vec3 const & a, Vec3 const & b, Vec3 const & c, float const time)
    {
    float const oneMinusTime (1.f - time);
    Vec3 const bezier = (a * oneMinusTime * oneMinusTime) + (b * 2.f * time * oneMinusTime) + (c * time * time);
    return bezier;
    }
    -

    三次贝塞尔曲线方程为:

    -

    -
    Vec3 const CubicBezier (Vec3 const & a, Vec3 const & b, Vec3 const & c, Vec3 const & d, float const time)
    {
    float const oneMinusTime (1.f - time);
    Vec3 const bezier = (a * oneMinusTime * oneMinusTime * oneMinusTime) + (b * 3.f * time * oneMinusTime * oneMinusTime) + (c * 3.f * time * time * oneMinusTime) + (d * time * time * time);
    return bezier;
    }
    +

    不带来烦躁感的地图切换机制

    -

    -
    Vec3 const BSpline (Vec3 const & a, Vec3 const & b, Vec3 const & c, Vec3 const & d, float const time)
    {
    float const t2 (time * time);
    float const t3 (t2 * time);

    Vec3 const result ((a * (-t3 + (3 * t2) + (-3 * time) + 1)) +
    (b * ((3 * t3) + (-6 * t2) + 4)) +
    (c * ((-3 * t3) + (3 * t2) + (3 * time) + 1)) +
    (d * t3));
    return (result / 6.0f);
    }
    +

    让人不由得手指发力的玩家角色动作机制

    -

    Continuity

    -

    C0是位置连续,C1是速度连续,C2是加速度连续。所以C1或更高的连续会在视觉上效果更好,C2或更高的连续会有更平滑的移动

    -

    Spline definitions

    -

    为了充分地定义spline curve,我们需要几个机制:

    +

    小结

    -

    Spline evaluation

    -

    可以预先计算整个spline的长度,然后用一个线性长度作为spline上的位置。如果再搭配速度damping则会产生比较平滑的效果

    -

    Control point generation

    +

    让割草游戏更有趣的攻击动作设计技巧(战神三)

    +

    让攻击准确命中目标敌人的机制

    -

    Parameterized arc length

    -

    积分法

    -

    Total spline length

    -

    总长度是各个spline弧长度的和,往往采用数值方法近似曲线长度

    -

    Closest position

    -

    计算spline上离某个位置最近的点往往很有用,但问题是可能有多个解,这时候就需要对这些解做个排序,比如考虑相机的前一个位置或者LOS,或者相机的角速度

    -
    Determine the nornal at each end of the segment and by using similar triangles
    Determine the length on the segment
    If length within 0..1 then
    Convert linear 0..1 into a parametric value
    With parametric value 0..1 find the position within the arc using the usual spline evaluation
    Check position against source position for LOS and other factors
    If OK, determine the physical distance between two points and compare to current "best"
    Else
    Not within segment, so proceed to next segment
    -

    Spline editing

    -

    开发能够编辑spline的工具

    -

    Interpolation

    -

    线性插值在一对数据点中生成新数据,piecewise插值则是由几个连续的数据点去生成。相机朝向往往用非线性插值

    -

    Camera Property -Interpolation

    -

    Position interpolation

    -

    位置插值应该是基于当前的位置和目标位置,用这个距离相比于原来的距离

    -
    Vec3 interpFactor = CMath::Clamp (0.0f, interpTimer/maxInterpTime, 1.0f);
    Vec3 currentDeltaPosition = desiredPosition - GetTranslation ();
    Vec3 newPosition = GetTranslation () + (currentDeltaPostion * interpFactor);
    // when interpTimer reaches maxInterpTime, the camera reaches the destination
    -

    Orientation interpolation

    -

    朝向插值通常不涉及roll,即使需要考虑roll,也会单独处理

    -

    由于小的朝向改变会引起巨大的视觉变化,所以一定要确保朝向插值的平滑。线性插值并不保证对象一定在视野里。如果朝向改变很大,要限制角速度,或者使用jump -cut。朝向插值也要保证路径最短

    +

    让连击畅快淋漓的机制

    -

    FOV interpolation

    -

    如果没有其他渲染效果,那么只改变FOV就显得很突兀,快速的FOV改变会让玩家不适,这时候一个jump -cut反而更好。zoom in也是通过FOV实现的

    -
    float targetFOV = GetTargetFOV ();
    float deltaFOV = mFOV - targetFOV;
    float newFOV = targetFOV + (deltaFOV * deltaTime);
    float newDeltaFOV = newFOV - targetFOV;
    if (absF(newDeltaFOV) < absF(deltaFOV))
    {
    mFOV = newFOV;
    }
    -

    Viewport Interpolation

    -

    改变显示设备的大小,通常用于cinematic sequences和regular game -play之间的转换。比如从2.35:1到1.33:1

    -

    Player Control Interpolation

    -

    First person cameras

    -

    control interpolation通常用于从一个第一人称control reference -frame变化到一个fixed control reference frame比如object orbiting

    -

    Third person cameras

    -

    在很多情况下,我们要保证如果相机出现巨大移动,则玩家控制不会马上改变

    -

    一个问题是如何处理玩家移动比相机移动快的问题,而且玩家绕着相机垂直轴的任何移动会导致相机绕着该轴的快速转动

    -

    Interpolation Choices

    -

    首先要问现有的数据是kay value还是control -values;第二,要考虑插值方法的效率和效果;第三,要考虑插值结果的平滑性;最后,也要考虑不同插值方法需要的数据量

    -

    Linear interpolation

    -

    线性插值只需要三个参数:source value, destination -value和interpolation method

    -

    Destination value往往会随时间改变,我们就需要考虑到destination -value的变化率,当插值的变化率不匹配目标值的变化率时,不连续就会发生

    -

    插值方法需要考虑是否要用固定的时间完成插值。不考虑变化率会在开始和结束时产生不连续现象

    -

    Piecewise interpolation

    -

    通常有多于两个数据点进行插值,一种策略是把它们视为独立的interpolation -segments:

    bool foundTime (false);
    for (int i = 0; i < valueTimes.Size() - 1; ++i)
    {
    if (valueTimes[i+1] > time)
    {
    float timeDelta = valueTimes[i+1] - valueTimes[i];
    timeFactor = (time - valueTimes[i]);
    segment = i;
    source = values[i];
    destination = values[i+1];
    foundTime = true;
    break;
    }
    }
    if (foundTime)
    return Interpolate (source, destination, timeFactor);

    -

    此外,也可以在每对数据点中假设均匀时间区间,但会有比较大的问题

    -

    Methods of Interpolation

    -

    Linear time interpolation

    -
    Interpolated value = source + ((destination - source) * t)
    -

    Parametric functions

    -

    比如ease函数

    -

    Spherical linear -interpolation

    -

    用于角的插值

    -

    Potential Interpolation -Problems

    -

    Aesthetic problems

    -

    一些视觉上的问题包括:

    +

    菜鸟也能轻松上手的畅快的浮空连击机制

    -

    Mathematical problems

    -

    数学上的问题一般是由浮点误差导致的:

    +

    用简单操作发动复杂连击的机制

    -

    Interruption of -Interpolation

    -

    有可能在一个插值过程中触发了另一个插值,这时候可以从当前值开始直接开始新的插值

    -

    Transitions

    -

    Position during transitions

    -

    Orientation during -transitions

    -

    有两种方法在transition的过程中控制插值相机的朝向,如果source和des相机没有reorienting,那么简单的线性插值或slerp可以处理得很好,但如果有一个或者两个都reorient就会有问题。一个方法是计算从目标值到当前值之间得剩余量(比如角度),如果新的插值大于当前值,则忽略

    -

    Camera Math Problems

    -

    Floating-point precision

    -

    相机系统一般用单精度浮点数,所以不能表示很大的数

    -

    Epsilon usage

    -

    要根据用途改变epsilon的值

    -

    Compiler differences

    -

    编译器也有不同

    -

    Hardware FPU differences

    -

    Vector normalization

    -

    Matrix concatenation -floating-point drift

    -

    在应用旋转矩阵后,正交化该矩阵以保证浮点精确度

    -

    Periodic Camera Mathematical -Fixes

    -

    最好在渲染之前检查当前的相机变换是不是正确的,包括:

    +

    让玩家角色动作更细腻的设计技巧(《塞尔达传说:天空之剑》)

    -

    如果矩阵不能被修复,则使用上一帧的矩阵;记得多正交化矩阵

    -

    Chapter 11: Implementation

    -

    Game Engine Architecture

    -

    Game update loop

    -

    大多数相机逻辑都要在其他逻辑之后执行,典型的执行顺序是:

    +

    让玩家下意识选择合适动作的Z注视机制

    -

    Game system managers

    -

    一些管理系统包括:

    +

    能单独当游戏玩的移动动作——奋力冲刺

    -

    Delta time

    -

    现在游戏通常将逻辑层与渲染层分开,这有利于CPU处理和GPU渲染,游戏逻辑可能以固定的速率更新,也可能以动态的速度更新,从而,相邻两次更新的时间间隔不一定一致,经过的时间就称为delta -time

    -

    Input processing

    -

    很多相机需要把输入值传递给它们,这通常由相机管理器实

    -

    Camera System Architecture

    -

    Viewport manager

    -

    主要工作是包含所有在场景内需要渲染的东西,处理控制器输入、渲染、masking、buffer管理、aspect -ratio等等,能够被其他游戏系统用于访问关于当前活跃相机的相机系统。数据结构是:

    -
    class CViewportManager
    {
    public:
    typedef int32 TViewportHandle;
    TViewportHandle const CreatViewport (EViewportType);
    void DeleteViewport (TViewportHandle const viewport);
    void Update (float const deltaTime);
    void ProcessInput (CInput const & input);
    CViewport const & GetViewport (TViewportHandle const handle) const;
    }
    -

    在定义了显示媒介之后,我们需要描述投影,因此VM需要:

    +

    没有跳跃键却可以体验真实跳跃的机制

    +

    头脑与身体一起享受的剑战动作设计技巧(《塞尔达传说:天空之剑》)

    +

    能帅气挥剑的机制

    + -

    每个Viewport都控制了所有需要渲染的信息,比如相机、控制器输入、surface -locatio and -size、渲染模式等等,甚至还包含了用于多种输出设备渲染需要的信息

    -

    VM还处理不同viewport之间的过渡,通常用于玩家在菜单界面、暂停时,或者画中画。Transition可能包括:

    +

    攻击与体力的机制

    -

    Render manager

    -

    从当前的viewports和cameras获取数据并渲染,此外会移除frustum外的的物体,决定渲染顺序,应用后处理

    -

    Camera manager

    -

    CM的主要责任是扮演所有相机的控制器,生成相机新实例、处理转场、插值、优先级、控制器输入、replay -modes和时间控制

    -

    CM有Update函数,处理步骤是:

    +

    让玩家痛快反击的盾击机制

    -

    Camera update loop

    -

    相机一般是下面的更新逻辑:

    +

    实现剑战动作的机制

    -

    Hint manager

    -

    每个CM都有一个与之关联的camera hint manager (CHM)

    -

    Shake manager

    -

    相机震动一般发生在渲染阶段而不是实际移动相机,因为这可能导致相机穿过物体。Shake -transform在局部相机空间中计算应用在渲染之前

    -

    相机震动有三个组件:

    +

    剑战动作与割草游戏的区别

    -

    Game Cameras

    -

    Inherited camera behaviors

    -

    可以用下面的层级去实现相机类:

    +

    完美演绎英雄的玩家角色动作设计技巧(《蝙蝠侠:阿甘之城》)

    +

    能像蝙蝠一样在三维空间自如穿梭的机制

    +

    通过简单操作实现高自由度的玩家角色动作的机制

    -
  • First Person
  • +
  • 玩家角色的移动动作就有很多种,移动动作并不由玩家的手柄决定,而是由玩家触碰的物体决定。(类似刺客信条)
  • +
  • 蝙蝠侠将移动动作特有的难点——时机把握从基本移动操作中剔除,是一款专注功能可供性的动作游戏。
  • -

    Component-based camera -behaviors

    -

    不用类继承的方式,另一种方法是使用component-based相机。任何相机的属性都可以拆分为一些可交换的组件,称为behavior,这些behavior能够在运行时组合或交换以产生很多相机变体。一些behavior包括:

    +

    演绎一名不会轻易死亡的英雄

    -

    尽管单个component从设计上讲是独立的,但是可能某个特定的component,比如orientation,依赖于其他component的状态,所以需要有特定的component更新顺序

    -

    Cinematic cameras

    -

    通常会把cinematic camera与game -camera分开考虑,有自己独立的viewport

    -

    Debug camera

    -

    只用于render

    -

    Scripting System -Implementation

    -

    Camera script objects

    -

    有时候需要动态改变相机行为,这就是scripting,一些script -objects包括:

    +

    让玩家化身为英雄的设计技巧(《蝙蝠侠:阿甘之城》)

    +

    让战术自由度更高的机制

    -

    Ordering of scripting logic

    -

    如果scripting -logic引起任何需要发送的消息,则它们会立即发送给接收者,但是可能此时接收者已经执行了自己的逻辑,所以要等到下个update时才能做出对当前消息的反应,可以把message -cache

    -

    Messaging

    -

    当事件发生时,需要通知其他游戏物体事件的发生,这一般用messaging -system实现。实际的消息只包含了与该事件有关的信息,比如发送消息的物体、消息本身、其他可能触发该消息的物体

    -

    比如当玩家进入trigger volume时,会让对应的script -object发送一个enter消息、是谁发送的消息

    -

    Prioritization

    -

    可用一个整数代表优先级,也可以用属性表示优先级,比如和玩家之间的距离

    -

    Interpolation

    -

    可以用一个专门的interpolation camera管理相机插值

    -

    Performance Considerations

    -

    Amortization

    -

    一般用于缓存几个update内的中间值,但相机移动需要立即执行。在采用amortization之前,需要考虑哪些属性不需要每次update都更新,哪些属性需要立即更新

    -

    Preprocessing

    -

    大多数的相机CPU消耗都用于ray -casting或碰撞检测,预处理,如沿着特定轨道的相机移动,可以减少CPU开销

    -

    Tools Support

    -

    World editor

    -

    大多数常用的属性都以易用的界面实现,比如camera path definition, -camera hint placement,property editing, pre-defined macros of script -objects:

    +

    让人忍不住要尝试的工具机制

    -

    Camera collision mesh

    -

    Camera有自己的collision geometry会更方便,因为可以允许动态改变

    -

    Camera Debugging Techniques

    -

    Interactive debugging

    -

    Interactive debugging包括:

    +

    让玩家完美演绎蝙蝠侠的捕食者动作的机制

    -

    Data logging

    -

    注意logging对游戏性能的影响,一个优化是cache日志信息直到某个不影响游戏性能的时间点

    -

    在获取log之后,除了直接阅读文本之外,还可以采用可视化的手段,把数据导入游戏复盘相机数据

    -

    Game replaying

    +

    改变动作游戏定式的自由流程格斗机制

    + +

    还原机器人动画的玩家角色动作设计技巧(《终极地带:引导亡灵之神》)

    ]]>
    游戏 - 游戏理论 随笔 - 相机 - 游戏 - 设计 + 游戏 + +
    + + 一道有趣的概率题 + /2022/10/20/23/59/ + 独立同分布,令,求。换句话说,我们要求最先使得若干个独立同分布于的随机变量之和大于的期望。

    + +

    问题定义

    +

    这个问题的定义已经定义在上面了,这里再复述一遍:

    +

    独立同分布,令,求

    +

    引入函数

    +

    乍一看这个题似乎无从下手,但是我们可以发现这里这个条件似乎可以换成任意一个,这启发我们用一个函数去表示我们要求的式子,然后通过求解一个“递推式”(实际上是一个微分方程)解出这个函数,进而得到某个具体点的值。

    +

    从这个思路出发,我们不妨定义,进而令。显然,我们的目标就是求

    +

    求解方程

    +

    那么,怎么求出呢?注意题目中的条件独立同分布,因此我们可以把里面的拆出来,变成:

    +

    +

    为了简便起见,我们不妨限定。此时考虑两种情况:

    +

    如果,那么就等于,所以这等价

    +

    如果,那么就相当于后面的,再由独立同分布知道这就是,但这是以为条件的,所以实际上还要对求个积分,也就是:

    +

    +

    把上面两个加起来,就有:

    +

    +

    进而得到微分方程及其初始值:

    +

    +

    很容易求解得到,所以我们就能得到最终的答案

    +]]>
    + + 数学 - 概率论 + + + 数学 + 随笔 + 概率论
    @@ -6307,6 +6234,79 @@ logging, messaging filtering, object state 打油诗 + + 你为什么不笑了 + /2022/10/29/00/35/ + 你为什么不笑了?

    + +

    奶奶,你为什么不笑了?
    +还记得,一年前的你,
    +走在春风里,
    +向着山顶慢慢登去。
    +你摘下路边的一朵浅梅,
    +捧在手心。
    +阳光洒下,
    +手中的梅花,也映衬出了你脸上的笑容。

    +

    你的儿子女儿挽着你的手,
    +一步一步向山顶走去,
    +你看见一棵古树,
    +你说这是拍照好去处。
    +女儿扶着你,
    +你扶着树,
    +阳光洒下,
    +树上的绿叶,也甘愿陪衬你脸上的笑容。

    +

    来到山顶,
    +黄花遍地,
    +你开心得像个孩子,
    +伸出双手,
    +比了两个大大的耶,
    +那时的你,真的好美。

    +

    奶奶,从什么时候开始,你不笑了?
    +从拔掉爷爷呼吸机的那个夜晚开始,
    +你似乎一直睡得不好。
    +你还能梦见吗,
    +另一张空荡荡的床上,
    +曾经那个老人的模样?
    +从前他是那样健康,
    +如今却骨瘦嶙峋,
    +让时间风干了皮肤,
    +侵蚀了思想。
    +你还能看见吗,
    +那个明媚下午的阳光,
    +案前那个老人伏着阅读着,报刊也泛黄。

    +

    奶奶,你为什么不笑了?
    +近日来,
    +你总是抱怨,
    +胸口有恙。
    +你变得啰嗦、唠叨,
    +总是对小事斤斤计量。
    +我好想你能多笑笑,
    +放下生活的疲劳,
    +忘却心中的郁结,
    +再回忆,
    +我们一起出游时,
    +小鸟的啼叫,
    +鲜花的绽放,
    +阳光的照耀,
    +我们手拉着手,
    +在田园中,聊些家常,传来欢笑。

    +

    奶奶,时间真的很残酷,
    +也许当我走时,
    +这个世界便再无你的回响,
    +人生人寂,人来人往,
    +至我去时,此情已了,略无痕迹。

    +

    奶奶,再让我看看你的笑,
    +那个阳光中,
    +像孩子般最天真的笑容。

    +]]>
    + + 随笔 + + + 随笔 + 生活 + +
    向量绕任意轴旋转的简单推导 /2021/06/07/08/38/ @@ -6988,6 +6988,34 @@ Lock,因此无法转化为对应的Euler角。从上面的过程来看,对 计算机 + + 樱花 + /2021/06/29/00/24/ + 昨夜 我收到一封书札
    +旧纸上 缀满了一朵樱花
    +风干的墨迹 渗透了陌生人的迷茫
    +我慢慢 把信合上

    +

    昨夜 我写了一封书札
    +述说着 近日的苦闷衷肠
    +窗外的灯火 依旧那么辉煌
    +我贴上 一朵樱花珍藏

    +

    同样的夜晚 走过了岁月多少锋芒
    +心中仍 呐喊着一个熟悉人的回响
    +把信 随风寄向远方
    +留给陌生的他 打开新的过往
    +愿他不要怯懦 续写昨夜的感慨
    +还有清晨的阳光

    +

    案台旁 樱花在绽放

    +]]>
    + + 随笔 + + + 随笔 + 生活 + 打油诗 + +
    根据角色体型和俯角自动确定FreeLook镜头参数 /2022/06/21/23/40/ @@ -7047,75 +7075,6 @@ Lock,因此无法转化为对应的Euler角。从上面的过程来看,对 游戏 - - 用生成函数和复数巧解一道计数题 - /2022/06/26/23/03/ - 对集合,求出其中有多少子集,使得子集中的元素和为5的倍数。本文对3Blue3Brown的解法上进行总结,形成较为数学化的语言。本题背后有较为深刻的数学思想,故记载于此。

    - -

    把原问题转化为生成函数

    -

    原题是:对集合,求出其中有多少子集,使得子集中的元素和为5的倍数。

    -

    首先容易想到的是,可以采用穷举法,遍历的每个子集,检查是否满足条件。但是,穷举法的复杂度是,这对计算机来说都是一个天文数字。显然,需要另辟蹊径。

    -

    不妨先简化一下题目:求出集合中有多少个子集,使元素之和为,我们可以很快地列出这些集合:

    -

    -

    换句话说,可以表示为:,如果我们把它表示成一个关于未知数的多项式,那么就有:

    -

    -

    什么情况会同时出现呢?答案是生成函数。这启发我们使用下面的生成函数:

    -

    -

    这个多项式展开之后的结果是:

    -

    -

    注意五次项前面的系数是3,这是因为,有三个来源,分别是,正好对应了之前简化题中的结果!

    -

    现在分析一下,多项式中的每个项,都代表了整数,如果在括号中选择了,则表示把这个整数加入集合,如果选择了,则表示不加入。而把整个多项式展开之后的结果,项前面的系数,正好代表了元素之和为的集合的个数!

    -

    这时候,我们就能把原问题转化为下面的生成函数:

    -

    -

    求出其中所有次数为的倍数的项系数之和:

    -

    -

    下面的问题就是如何求出

    -

    转化为复数问题

    -

    显然,我们不可能把中的每一项都求出来,只能设法一次求出,那么怎么办呢?

    -

    我们还是先考虑简化问题,假设现在生成函数是:

    -

    -

    如果我们代入,可以求得;如果代入,可以求得;再代入,有。用展开式表示结果:

    -

    -

    通过后面两式,不难得到:

    -

    -

    我们找到了所有奇数项系数之和,但是我们的目标是所有的倍数的项系数之和。但这个过程可以给我们一个启发:是否可以通过代入某些值到生成函数中,通过加减运算消去我们不关心的项,得到最终的结果

    -

    分析我们把代入到中每一项的过程,所有的偶数项结果都是,所有的奇数项结果都是。换句话说:这个值对函数的未知项的循环次数为,或者,每两项代入的结果都相同。同理,对来说,循环次数是

    -

    那么,什么时候循环次数是呢?也就是,代入哪个数,会使得,或者。显然,在复空间中,这个数就是。也就是说,如果令,则有个数满足我们的要求,其中就是我们熟知的实根。

    -

    更关键的是,这几个数的和是

    -

    -

    现在,分别把这五个值代入到展开的生成函数中,有:

    -

    -

    注意对应的项,正好都有,把它们加起来,有:

    -

    -

    是已知的,所以上面的结果就变成了:

    -

    -

    现在整个式子右边只留下常数和的倍数的项!

    -

    唯一遗留的问题就是式子左侧的是多少,或者说是多少,因为只要知道了的值也就知道了。

    -

    这里的技巧是,因为是方程的五个根,所以可以把它们表示成:

    -

    -

    代入:

    -

    -

    从而,我们也就有,而。所以,我们就得到了:

    -

    -

    这样一来我们考虑的简化版问题就得到了解决!

    -

    按照这个思路,我们同样可以得到原始问题的解决,分为几步。

    -

    第一步:设是方程的五个根,把它们分别代入生成函数中,相加,就得到:

    -

    -

    第二步:把表示为,通过代入解出

    -

    第三步:把代入到生成函数中,可以得到,同理有,同时有

    -

    第四步:把所有值代回第一步中的结果,得到最终答案

    -

    总结

    -

    本题背后蕴藏着较为深刻的数学思想,一方面是巧用生成函数把一个计数问题转化为一个分析问题,另一方面是使用复数消去某些项,直接求出想要的结果。通过本题,我们可以充分了解到复数所蕴含的关于周期和频率的思想,从而也就能理解为什么傅里叶变换用复数表征。

    -

    把本题稍微进行推广:对集合和正整数,其中。设中满足元素之和为的倍数的子集个数为,你能求出的表达式吗?

    -]]>
    - - 数学 - 分析 - - - 数学 - 随笔 - -
    浅谈Hades最终BOSS的AI设计 /2021/09/22/08/52/ @@ -7233,31 +7192,72 @@ Designer画一个简单的行为树 - 樱花 - /2021/06/29/00/24/ - 昨夜 我收到一封书札
    -旧纸上 缀满了一朵樱花
    -风干的墨迹 渗透了陌生人的迷茫
    -我慢慢 把信合上

    -

    昨夜 我写了一封书札
    -述说着 近日的苦闷衷肠
    -窗外的灯火 依旧那么辉煌
    -我贴上 一朵樱花珍藏

    -

    同样的夜晚 走过了岁月多少锋芒
    -心中仍 呐喊着一个熟悉人的回响
    -把信 随风寄向远方
    -留给陌生的他 打开新的过往
    -愿他不要怯懦 续写昨夜的感慨
    -还有清晨的阳光

    -

    案台旁 樱花在绽放

    + 用生成函数和复数巧解一道计数题 + /2022/06/26/23/03/ + 对集合,求出其中有多少子集,使得子集中的元素和为5的倍数。本文对3Blue3Brown的解法上进行总结,形成较为数学化的语言。本题背后有较为深刻的数学思想,故记载于此。

    + +

    把原问题转化为生成函数

    +

    原题是:对集合,求出其中有多少子集,使得子集中的元素和为5的倍数。

    +

    首先容易想到的是,可以采用穷举法,遍历的每个子集,检查是否满足条件。但是,穷举法的复杂度是,这对计算机来说都是一个天文数字。显然,需要另辟蹊径。

    +

    不妨先简化一下题目:求出集合中有多少个子集,使元素之和为,我们可以很快地列出这些集合:

    +

    +

    换句话说,可以表示为:,如果我们把它表示成一个关于未知数的多项式,那么就有:

    +

    +

    什么情况会同时出现呢?答案是生成函数。这启发我们使用下面的生成函数:

    +

    +

    这个多项式展开之后的结果是:

    +

    +

    注意五次项前面的系数是3,这是因为,有三个来源,分别是,正好对应了之前简化题中的结果!

    +

    现在分析一下,多项式中的每个项,都代表了整数,如果在括号中选择了,则表示把这个整数加入集合,如果选择了,则表示不加入。而把整个多项式展开之后的结果,项前面的系数,正好代表了元素之和为的集合的个数!

    +

    这时候,我们就能把原问题转化为下面的生成函数:

    +

    +

    求出其中所有次数为的倍数的项系数之和:

    +

    +

    下面的问题就是如何求出

    +

    转化为复数问题

    +

    显然,我们不可能把中的每一项都求出来,只能设法一次求出,那么怎么办呢?

    +

    我们还是先考虑简化问题,假设现在生成函数是:

    +

    +

    如果我们代入,可以求得;如果代入,可以求得;再代入,有。用展开式表示结果:

    +

    +

    通过后面两式,不难得到:

    +

    +

    我们找到了所有奇数项系数之和,但是我们的目标是所有的倍数的项系数之和。但这个过程可以给我们一个启发:是否可以通过代入某些值到生成函数中,通过加减运算消去我们不关心的项,得到最终的结果

    +

    分析我们把代入到中每一项的过程,所有的偶数项结果都是,所有的奇数项结果都是。换句话说:这个值对函数的未知项的循环次数为,或者,每两项代入的结果都相同。同理,对来说,循环次数是

    +

    那么,什么时候循环次数是呢?也就是,代入哪个数,会使得,或者。显然,在复空间中,这个数就是。也就是说,如果令,则有个数满足我们的要求,其中就是我们熟知的实根。

    +

    更关键的是,这几个数的和是

    +

    +

    现在,分别把这五个值代入到展开的生成函数中,有:

    +

    +

    注意对应的项,正好都有,把它们加起来,有:

    +

    +

    是已知的,所以上面的结果就变成了:

    +

    +

    现在整个式子右边只留下常数和的倍数的项!

    +

    唯一遗留的问题就是式子左侧的是多少,或者说是多少,因为只要知道了的值也就知道了。

    +

    这里的技巧是,因为是方程的五个根,所以可以把它们表示成:

    +

    +

    代入:

    +

    +

    从而,我们也就有,而。所以,我们就得到了:

    +

    +

    这样一来我们考虑的简化版问题就得到了解决!

    +

    按照这个思路,我们同样可以得到原始问题的解决,分为几步。

    +

    第一步:设是方程的五个根,把它们分别代入生成函数中,相加,就得到:

    +

    +

    第二步:把表示为,通过代入解出

    +

    第三步:把代入到生成函数中,可以得到,同理有,同时有

    +

    第四步:把所有值代回第一步中的结果,得到最终答案

    +

    总结

    +

    本题背后蕴藏着较为深刻的数学思想,一方面是巧用生成函数把一个计数问题转化为一个分析问题,另一方面是使用复数消去某些项,直接求出想要的结果。通过本题,我们可以充分了解到复数所蕴含的关于周期和频率的思想,从而也就能理解为什么傅里叶变换用复数表征。

    +

    把本题稍微进行推广:对集合和正整数,其中。设中满足元素之和为的倍数的子集个数为,你能求出的表达式吗?

    ]]>
    - 随笔 + 数学 - 分析 + 数学 随笔 - 生活 - 打油诗
    diff --git a/sitemap.txt b/sitemap.txt index e9b1e739..1ba9a004 100644 --- a/sitemap.txt +++ b/sitemap.txt @@ -63,14 +63,14 @@ http://sulley.cc/tags/CDO/ http://sulley.cc/tags/%E7%BC%96%E8%BE%91%E5%99%A8/ http://sulley.cc/tags/%E5%8A%A8%E7%94%BB/ http://sulley.cc/tags/%E4%BD%9C%E4%B8%9A/ -http://sulley.cc/tags/%E5%B7%A5%E5%85%B7/ -http://sulley.cc/tags/%E7%BB%98%E7%94%BB/ -http://sulley.cc/tags/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/ http://sulley.cc/tags/Unity/ http://sulley.cc/tags/Cinemachine/ http://sulley.cc/tags/Damping/ -http://sulley.cc/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/ +http://sulley.cc/tags/%E5%B7%A5%E5%85%B7/ +http://sulley.cc/tags/%E7%BB%98%E7%94%BB/ +http://sulley.cc/tags/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/ http://sulley.cc/tags/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86/ +http://sulley.cc/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/ http://sulley.cc/tags/Spline/ http://sulley.cc/tags/Curve/ http://sulley.cc/tags/%E6%9B%B2%E7%BA%BF/ @@ -91,6 +91,6 @@ http://sulley.cc/categories/%E9%9A%8F%E7%AC%94/ http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E7%8E%A9%E5%90%8E%E6%84%9F/ http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E6%B8%B8%E6%88%8F%E7%90%86%E8%AE%BA/ http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E6%95%B0%E5%AD%A6%E5%88%86%E6%9E%90/ -http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E5%88%86%E6%9E%90/ http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E6%B8%B8%E6%88%8F%E5%88%86%E6%9E%90/ +http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E5%88%86%E6%9E%90/ http://sulley.cc/categories/%E7%94%B5%E5%BD%B1-%E5%9B%BD%E4%BA%A7%E7%94%B5%E5%BD%B1/ diff --git a/sitemap.xml b/sitemap.xml index bf7fef1f..df91517a 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -445,7 +445,7 @@ http://sulley.cc/ - 2023-07-28 + 2023-07-29 daily 1.0 @@ -453,238 +453,238 @@ http://sulley.cc/tags/%E6%95%B0%E5%AD%A6/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E9%9A%8F%E7%AC%94/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/UE/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E7%9B%B8%E6%9C%BA/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E7%AE%97%E6%B3%95/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E6%A6%82%E7%8E%87%E8%AE%BA/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E9%87%87%E6%A0%B7/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E8%93%84%E6%B0%B4%E6%B1%A0%E9%87%87%E6%A0%B7/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E6%B8%B8%E6%88%8F/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E8%93%9D%E5%9B%BE/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/CDO/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E7%BC%96%E8%BE%91%E5%99%A8/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E5%8A%A8%E7%94%BB/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E4%BD%9C%E4%B8%9A/ - 2023-07-28 + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/%E5%B7%A5%E5%85%B7/ - 2023-07-28 + http://sulley.cc/tags/Unity/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/%E7%BB%98%E7%94%BB/ - 2023-07-28 + http://sulley.cc/tags/Cinemachine/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/ - 2023-07-28 + http://sulley.cc/tags/Damping/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/Unity/ - 2023-07-28 + http://sulley.cc/tags/%E5%B7%A5%E5%85%B7/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/Cinemachine/ - 2023-07-28 + http://sulley.cc/tags/%E7%BB%98%E7%94%BB/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/Damping/ - 2023-07-28 + http://sulley.cc/tags/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/ - 2023-07-28 + http://sulley.cc/tags/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86/ + 2023-07-29 weekly 0.2 - http://sulley.cc/tags/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86/ - 2023-07-28 + http://sulley.cc/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/ + 2023-07-29 weekly 0.2 http://sulley.cc/tags/Spline/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/Curve/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E6%9B%B2%E7%BA%BF/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E6%8F%92%E5%80%BC/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E7%94%9F%E6%B4%BB/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E5%88%BA%E5%AE%A2%E4%BF%A1%E6%9D%A1/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E6%8F%92%E4%BB%B6/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E5%B7%AB%E5%B8%88%E4%B8%89/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E8%AE%BE%E8%AE%A1/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E6%89%93%E6%B2%B9%E8%AF%97/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/tags/%E5%BD%B1%E8%AF%84/ - 2023-07-28 + 2023-07-29 weekly 0.2 @@ -693,84 +693,84 @@ http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E7%9B%B8%E6%9C%BA/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E6%A6%82%E7%8E%87%E8%AE%BA/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E5%9B%BE%E5%BD%A2%E5%AD%A6/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E5%BC%95%E6%93%8E/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E5%8A%A8%E7%94%BB/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E9%9A%8F%E7%AC%94/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E7%8E%A9%E5%90%8E%E6%84%9F/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E6%B8%B8%E6%88%8F%E7%90%86%E8%AE%BA/ - 2023-07-28 + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E6%95%B0%E5%AD%A6%E5%88%86%E6%9E%90/ - 2023-07-28 + 2023-07-29 weekly 0.2 - http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E5%88%86%E6%9E%90/ - 2023-07-28 + http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E6%B8%B8%E6%88%8F%E5%88%86%E6%9E%90/ + 2023-07-29 weekly 0.2 - http://sulley.cc/categories/%E6%B8%B8%E6%88%8F-%E6%B8%B8%E6%88%8F%E5%88%86%E6%9E%90/ - 2023-07-28 + http://sulley.cc/categories/%E6%95%B0%E5%AD%A6-%E5%88%86%E6%9E%90/ + 2023-07-29 weekly 0.2 http://sulley.cc/categories/%E7%94%B5%E5%BD%B1-%E5%9B%BD%E4%BA%A7%E7%94%B5%E5%BD%B1/ - 2023-07-28 + 2023-07-29 weekly 0.2