AIGC教程:Midjourney高效制作伪3D游戏场景、还有动态和光照?
【GameLook专稿,未经授权不得转载!】
GameLook报道/对于大部分的中小团队而言,想要用有限的资源和人手做出高品质的效果是非常具有挑战性的。不过,随着AIGC技术的进步,越来越多的研发领域开始受益,比如AI画图、AI写剧本等等,都有很多开发者在尝试,而且对研发效率有明显提升。
那么,AI在场景创作方面的帮助有多大呢?
最近,海外一位资深同行分享了他使用生成型AI做了一个伪3D场景,并且通过为其增加了水面反射、光照探针渲染、景深以及草皮动态效果,做到了非常高的整体效果,而且几乎是有些基础的游戏圈同行就能很快上手。
他在分享研发过程的时候表示,AI生成的透视图视角几乎是接近完美的,当然,由于是2.5D游戏,实际上场景本身并不能旋转,而且模糊效果很难做到精准。不过,可以通过基于探针的照明将3D网格与2D图像更好地结合在一起,虽然还达不到真正的超写实或者3A美术的效果,但却是一个视觉效果更好、性能更高的解决方案。
以下是Gamelook编译的研发博客内容:
增加反射效果
通过我目前打造的管线,在2D图片之上增加带有阴影和互动光照的3D角色是很容易的。但是,反射表面能不能做呢?我们开始尝试。
反射场景的工作流程很大程度上和其他场景的制作是一样的,只不过多了一些纹理要求和步骤。
这个四房间温泉场景的创作,从头开始用了我六个小时左右的时间,包括指令过程。所以,使用AI制作场景的速度绝对是难以想象的。
指令
与以往一样,我们开始在Midjourney里输入指令,我努力保证指令简单一些,并且只是通过多次生成来获得一些能用的东西。对于这个浴缸场景,我生成了40个不同的池子区域以获得满足我需要的那一个:池子周围要有可行走区域,但不延伸到摄像头,而且有多扇门可以通过。
我还生成了其他场景,比如一个大堂、外部和一个泵房。
具体的指令是:
cyberpunk dirty abandoned outdoors pool, multiple doors, wide angle, hdr masterpiece adventure game –ar 5:3
cyberpunk dirty abandoned spa front entrance exterior wide angle, hdr masterpiece adventure game –ar 5:3 –seed 4046812885
cyberpunk dirty abandoned spa front entrance exterior wide angle, hdr masterpiece adventure game –ar 5:3 –seed 4046812885
cyberpunk dirty abandoned spa pump engine utility room, broken, garbage, wide angle, hdr masterpiece adventure game –ar 5:3 –seed 4046812885 –no pool
准备图片图层
为了让反射和光照起作用,我们需要四个版本的背景图片。
第一个版本是原始图片的“基础通道”版本,所有反射效果或多或少都被去掉了。由于我们将在表面之上添加实时反射效果,我们需要这个版本以避免双重反射,我也希望角色的反射能恰当地遮挡住明亮区域,所以这个通道是必备的。
第二个通道是老式的阴影通道,这个版本是图片被角色实时阴影遮住的版本,它不需要那么完美,因为只有其中很小的一部分是一直可见的。
反射通道需要的新图层就是简单的黑白遮罩,一个遮罩告诉地板哪个区域真正能反射,另一个遮罩则用来驱动反射的不同功能,比如水波纹和反射模糊。
在这个场景,我需要让池塘表面能够反射,大部分地板几乎都是全部可反射的。我开始手动在每个小石块上和地面上的一片纸上创作选区,我不希望反射效果出现在纸上、增加一些渐晕和假的菲利普斯曲线。
对于特殊功能遮罩,我需要将池塘表面从地板分隔开来,以便在池塘之上增加水波纹和在地板上增加模糊反射。
这样的遮罩也为大堂区域创作了一些,外部和泵房没有任何反射。然而,大堂并不需要一个水波纹遮罩,因为能够产生反射的只有水面。
3D建模
对于3D建模,和往常一样,第一步是逆向AI图片摄像头数据,尽管这些图片是通过一个AI产生的,但它们当中的视角每次都是接近完美的。
对此我使用了一个叫做fSpy的应用,感兴趣的同行可以参阅其教程:https://fspy.io/tutorial/
有时候摄像机数据Dows不太好,在建模时,甚至在Unity中构建场景后,你会发现视角完全错误,最好是重新执行fSpy步骤,从头开始场景建模。无论如何,这些场景大多是倒置的盒子,而且在Blender中的工作流程非常快!
我通常在一些四视图中工作,但通过查看摄像机映射来看我在做什么。Blender非常棒,因为它可以让你在透视图周围缩放和平移进行裁剪,而不会真正移动摄像机和干扰映射,这绝对是非常神奇的!
在获得场景的第一个简单通道之后,是时候拿出Loop Cut工具,并为图像增加大量的几何体了。如果几何体不是相对密集的,UV映射会导致表面上出现映射伪影,类似于旧式PSX游戏。
这是Blender当中完成后场景的一个截图,网格很简单。通常对于不需要玩家走进去的室内场景,它就是一个可以切割和挤压的简单盒子。
为了给场景获得UV,在编辑模式中,选择网格所有面,在鼠标停留在摄像机视角的时候按U键,并选择“从视角映射(project from view)”。
你现在还不能将FBX导出至Unity(或Unreal)。
平面反射着色器
对于反射,我选择使用来自资源商店的一个插件,叫做Fast Mobile Planar Reflections。
资源中的材质不再兼容最新的URP,但我只需要这个包体中的一个脚本,这个脚本叫做“PlanarURP”。它可以从指定给它的游戏对象的原点为场景渲染镜面纹理
着色器随后被发送给游戏对象网格渲染器里材质的参数_Reflection Tex。
有了这个信息,我们现在可以创作任何能够反射的shader graph类型,我将我的资源做成了一种附加材质,它可以(在屏幕空间中)分配反射纹理,并将其与反射掩膜相乘。
我还使用一些法线贴图扭曲反射纹理屏幕空间UV,并使用另一个纹理遮罩它。
作为最后一步,我还在反射之上增加了一些过于复杂的模糊,让表面更平滑。
反射材质应用于房间地板的副本上,并放置在地板真实位置的稍上方,有了遮罩和所有不同的技巧,反射效果看起来很好。
我特别喜欢现在角色恰当地遮挡了房间几何体的强反射。此外,反射表面现在也有了来自房间的精确反射,因为它实际上反映了3D空间,而不仅仅是AI做出的估算。
从图片到探针
我加入了Blockade Labs Slack进行了一些研究,我们开始讨论从AI生成的图像中获取光照数据。在VAU工作时,我们之前创建了一个脚本,可以读取视频源并将其转化为灯光探测器。
我发现这也没什么不同。也许有一种方法,可以将AI生成的图像转化为灯光探针(lighting probe)数据,而不是匹配环境灯光并添加多个聚光灯,这将使实时3D网格与环境完美匹配!
对于这个测试,我选择了一个简单的夜间售货亭场景。因为它有一些暗区和一些亮区,将会是探索灯光探针烘焙的完美候选者。
阴影通道的绘制变得非常容易。首先,我创建了一个启用暗模式的图层,用一个非常柔和的笔刷和非常低的flow,我对附近的阴影区域进行颜色选取,并在玩家可能投射阴影的所有方向亮区上绘制。
在此之后,我复制了原画,然后用“create clipping mask”指令,将这幅画嵌套在阴影图层中。随后,我对图层进行去饱和处理,并在图层上应用“high pass”滤色镜,仅显示图像的细节。然后将该图层设置为叠加模式,这会将所有丢失的细节带回到绘制的阴影中。
对于光照探针照明,我们需要一个新的纹理。一个伪HDR贴图用于拓宽照明动态范围,我们需要过载明亮区域,使探针有更多的pop。没有这个步骤,因为源材质并不是HDR,所以探针数据有点平淡。
对于这个特别的贴图,我将在图片之上增加一个黑色图层,并且将其透明度设为80%。然后将复制的原图片放到黑色图层之上,使用blending选项的blend if功能,我可以只对这一层的明亮区域曝光。因此,拓宽图片的动态区域六倍,即使如此,我也只需要把这个文件存储为8位psd。
3D灭点(vanishing point)需要用fSpy来确定,一旦这一步完成,文件就可以导入到Blender 3D之中了。
这个场景的建模和纹理步骤与每次创建新场景时我必须经历的步骤完全相同,完成这些总共需要大约一个小时,这篇文章详细介绍了blender的步骤。
一系列点击之后,我们在Unity中有了这个场景的3D版本,通过手绘阴影通道完成,但还没有灯光,这次我们以不同的方式做光照。
这个场景中有一个聚光灯,但它的密度很低,导致表面不可见。这个灯光的唯一原因就是为我的定制着色器提供阴影信息。
下一步是创建一个灯光探针组,将用于实际渲染在场景中移动的角色身上的灯光。场景中不会有太多实际的直接照明,几乎所有的照明都将来自这幅画。
这时候伪HDR图片就派上了用场。
在引擎中,fame HDR被设置为强度为10的照明纹理自发光通道。它看起来的视觉效果极不友好,但一旦被烘焙到光照探针上,它实际上会产生一种非常令人愉快的光线。我需要严重夸大自发光的值,以便为探针提供足够苛刻的照明,所以它的感觉像是直射光。
我隐藏了自发光版本的环境,并在环境中放置了一些球体来预览探针照明。它看起来很好,售货亭的光线照射在球体上,它们从地面得到了柔软的光反弹,使得售货摊背后区域足够暗。
这是是一个3D球体在去掉探针照明的图片中移动。
它看起来不错,虽然并不完美,但对于游戏而言完全是可用的。基于探针的照明将3D网格与2D图像更好地结合在一起,它还允许2D图像在网格上实际投射光线,而不必手动在每个自发光表面上放置光。这是一个视觉效果更好、性能更高的解决方案!
景深
我在工作中收到了一条评论,说角色与略显模糊的背景不能完美匹配。我想知道做一些景深是否可能,因为背景不是真正的3D,可能会烘焙进去一些模糊。
但这个想法一直伴随着我,我决定尝试。原则上,它应该是行得通的,因为我所有的场景都为角色的交互或遮挡创作了一个非常简单的3D网格。
实现景深非常容易,这是我需要添加到Prost process volume当中的一个简单的后期处理效果。
对焦距离是指清晰的区域,焦距决定了焦点区域的模糊度程度,很简单。
如果模糊不奏效,你还需要在场景主摄像机启用Depth Texture,至少是在使用URP管线的时候。
但在一开始,我根本无法让景深工作。我的角色和延伸到远处的东西会被模糊,但没有灯光的背景图像却无论如何都不会模糊。我搜索了好几个小时,试图找到如何让定制HLSL材质写入深度缓冲的方法,但我完全没那么幸运。我还意识到,这也是为何我的粒子没能恰当地与区域网格混合的原因。
我用了很长时间才弄清楚,原来是URP屏幕空间环境遮挡效果效果覆盖了我的深度缓冲。我为此找到了一个解决方案,那就是将SSAO设定为只使用深度,但对我而言,这个选择无论什么原因都有些灰色,所以我最后只好完全关闭了SSAO效果。
我的模糊设置非常高,因为我一直把它调起来,看看我在做什么。我决定把它发布到推特上,因为它看起来很有趣,人们似乎非常喜欢这种效果,公开打造也很有趣,因为每个人的反应都会立即反馈到游戏创作过程中。
我认为我必须为游戏里写一个事件,在这个事件中,景深会在很短的一段时间内变得疯狂。不过,我想不出还有什么比让角色受到类似药物os影响更合适的事情了,这会提高游戏的年龄评级,但你能做什么呢!
为了完成这个效果,我想要一个自动对焦功能,它可以在运行时基于一些指标梗概焦距。我有两个选择:将焦点放在玩家角色上,或者将注意力集中到鼠标指针上。
最终我选择了鼠标指针。因为对于点击式用户界面,你实际上并不是扮演角色,你是与他们脱离的,你作为鼠标指针在玩游戏。扫描屏幕,寻找可以互动的东西,如果游戏有方向控制(比如在用手柄玩的时候很可能会有),那么焦点当然会放在角色上。
脚本非常简单,大多数的public floats现在只是用于调试目的,唯一有区别的是Recovery Rate,即自动对焦寻找鼠标指针位置的速度有多慢,这让焦点过渡更平滑,不显得那么突兀。
鼠标的位置是通过重做从摄像机到鼠标,并获得到达3D碰撞器表面的距离来计算的。
我在游戏中留下了一个非常柔和的景深版本,它为外观增添了一些东西。目前,只有当焦点在前景的时候,景深才基本可见,这很不错。其他时候,屏幕是非常锐化的。
具有实验性的草皮系统
对于拥有松软草皮的场景,我觉得草皮可以格外蓬松,像是某种“毛发”设置。
所以这个想法是,我基于2D图片的fSpy摄像机处理来做普通的场景建模管线。我随后把草皮绘制到整个网格上,然后应用我的定制GBuffer读取草皮上的材质,以捕捉基础颜色,当我做这件事的时候,还在上面制作了一些微风顶点动画。
为了实现这一点,我需要一个与背景图像无缝融合的着色器,它可以遮挡角色,还可以接收与我的自定义手绘阴影设置完美匹配的阴影。
在我的脑海里,我认为这应该是容易的。只是需要弹出一个未发光的材质,即可读取网格枢轴点处的场景颜色缓冲区!这能有多难?事实证明,这可能非常的困难。
草皮世界到屏幕空间转换的问题
需要解决的第一个问题是从场景不透明几何体得到一个读取场景颜色的材质,就像是Photoshop里的颜色拾取器。让我震惊的是,世界空间位置到屏幕空间居然没有transform node。我不得不自己写,这是个让人气馁的工作,它用了我一整天的时间试错才搞定。
摄像机映射不是平坦的,而是弯曲的。为了让映射纹理恰当地放大,我不得不找到一个方式重做映射UV的鱼眼效应(fish-eye effect)。
草皮需要在地面上对图像中的一个点进行取样,如果它对像素位置取样,就会是不可见的,它需要像Photoshop中的涂抹刷那样工作。
Scattering。我必须在定位网格上散布数百个单独的草叶。
解决方案
具有了编辑器的支持,我现在解决了所有的着色器问题,并且得到了一个可以工作的着色器:
我不会写太多关于世界空间到屏幕空间位置转换的过程,但我在做这件事的时候非常绝望,这类东西远远超过了我的水平!
公园场景里的材质参数如展示在这张图片里的那样,大部分参数都是和风的效果有关,只是场景参数是用于颜色捕捉的,它是一个用于将捕捉到的图像与摄像机FOV匹配的倍数。
但我坚持了下来。我没有使用枢轴位置,而是让我的生活变得更轻松,只是尝试创建一种在3D网格上显示渲染图像的像素完美材质。每当我在某些方面得到一些可行的东西时,我都非常高兴和兴奋。开始只是为了能够读取材质中的不透明通道,然后以正确的高宽比获得图像,使其基于z空间中的网格位置进行缩放,最后消除鱼眼效果!
颜色
为了获得地面的颜色,我对草皮的每一片叶子建模,然后对目标世界空间位置采样,转化到屏幕空间,以得到草皮的颜色。我只是确定草叶的枢轴在根部中间,草皮的横截面是三角形的,所以我不必担心与摄像机相关的草皮旋转。
草地相对于相机的旋转。
我发现材质将会不发光,因此渲染起来会很快,所以单个做草叶不会是太大的问题。
我需要每一片草叶以获得每个草叶精准的根部定位,整个网格对象的地毯颜色是相同的,所以如果有许多草叶,它们都是相同的颜色。为了让每一个叶片都单独摆动,我需要为所有草叶单独设置枢轴。
坦白来说,我可以创建一个设置,在局部0高度采样草叶的位置坐标,但它可能会添加一些不需要的条纹。如果单个叶片是一个问题,这是我可以采取的优化措施。
为了获得shader graph里的不透明场景颜色渲染通道,你首先需要在游戏摄像机设定里开启这个功能,只要将设定里的Opaque Texture选择设置成打开(On)即可。
Scattering
首先我尝试了使用Polybrush(Unity用来在网格上绘制预制件的工具)在地形上绘制这些独立的草叶。这个方法不太理想,为了得到更好的覆盖效果,我创作了一捆可以绘制的草叶。
由于游戏只是从一个角度看到,草皮并不需要有100%的覆盖,只要游戏视角看起来是恰当的蓬松效果即可。
由于草皮基本上是一个后期处理效果,捕捉渲染图片的颜色并将其向上“涂抹”,它与背景图片完美匹配。此外,使用手绘阴影纹理的自定义阴影着色器也被完美复制到了草叶上。
使用局部的3D映射纹理作为指南,很容易绘制那些草皮是2D图片区域里的草皮。
风
我为草皮创作了一个非常基础的基于噪声的风设定,其想法是使用世界空间X、Z的位置作为UV来读取两个不同的noise map,然后使用时间旋转该UV。对两个噪声进行采样以获得高频风和较慢的风浪。对这两个noise map进行转换,使它们的范围在-0.5到0.5之间,从而使草向两个方向弯曲。
风速参数也通常也会使风朝其方向弯曲,以便风在草地上有可见的方向。
为了使风只影响草的尖端,我使用了一个简单的局部定位Y坐标作为风变形的倍数。
在动态中,草皮看起来很好而且随风飘动,比较好的部分是这是一个完全不发光的着色器,只做一些顶点变形!
如若转载,请注明出处:http://www.gamelook.com.cn/2023/03/513366