在浮动岛上的现场墙纸上工作时,我偶然发现了这些可爱的素素3D models of airplanes by Max Parata。我已经想为一些风格化的低保真3D艺术带来生命,因此在我看来,我立即看到了如何使用这些资产创建一个风格化的老式低保真景象。您可以观看live WebGL demo here。
该项目实现了很快 - 第一个使用粗糙的WIP布局和最终版本的时间跨度约为20天。然而,创建它非常有趣,因为在开发过程中,我对如何改善场景有一些新的想法。所有添加的内容确实很小,可以根据其艺术设计使场景尽可能简单。我的兄弟提供了有关如何改进它的宝贵反馈,还可以帮助优化一些几何形状。
场景组成
场景在美学上很简单,因此仅包含四个对象:飞机,地面,云和风:
接下来,让我们看一下用于渲染模型的着色器以及如何优化这些模型的几何形状。
飞机
技术平面不是作为体素渲染的(每个体素立方体),而是从MagicaVoxel导出的现成网格。它们不会使用VoxCleaner简化,以使用纹理地图集并减少PolyCount-我决定使用它们,因为它会更容易创建替代调色板,无论如何,飞机的顶点数据具有荒谬的记忆足迹。
每平面由3份组成 - 平面主体,玻璃驾驶舱和旋转的螺旋桨。飞机是使用2个着色器渲染的 - 一个简单的定向点亮的PlaneBodyLitShader.ts用于身体和道具及其变体GlassShader.ts用于带有风格的反射的玻璃。
平面模型的细节允许使用真正小的数据类型包装顶点数据。所有平面型号都很小,并且适合-127+127边界框。并且由于顶点代表体素,它们总是被捕获到1x1网格。因此,我选择将顶点位置存储在签名的字节中,这些字节具有足够的精度来完成工作。
同样,由于模型使用的调色板纹理为256x1大小,因此省略了V纹理坐标并进行了硬编码为0.5- Texel中心。剩余的u坐标拟合在一个未签名的字节中。一个字节用于将数据对齐8个字节。这是平面和Prop模型的顶点数据步幅:
在单独的抽奖电话中,绘制了带有滚动风格的假反射的玻璃:
玻璃是没有调色板纹理的玻璃 - 其颜色是通过均匀设置的。传递给此着色器的质地是反射的掩码。它的UV坐标是基于模型空间顶点坐标在顶点着色器中计算的。当然,它是出于艺术目的而没有过滤的。玻璃模型的大步是相同的,但没有纹理坐标:
GlassShader使用具有0 MIPMAP级别的textureLod
样品纹理。这样做是为了明确地告诉OpenGL ES驱动程序,我们无需mipmaps即可访问纹理并减少一些开销。您可以在皮特·哈里斯(Pete Harris)博客中阅读有关此内容以及其他一些纹理采样优化技巧-https://solidpixel.github.io/2022/03/27/texture_sampling_tips.html
玻璃型号也具有小的polycount,因此他们使用未签名的字节索引,也可以降低内存带宽。
风条条
对于风条条,我决定创建一个根本没有执行任何内存读取的着色器。风条带有非常简单的几何形状 - 一个100x100单元四边形,通过模型矩阵延伸到适当的细线中。由于其简单性,所有这些几何形状都可以用顶点着色器代码进行硬编码。而且它也不使用任何纹理 - 片段颜色通过统一传递。您可以在WindStripeShader.ts中找到实现。它使用gl_VertexID
获得给定顶点的位置。当使用此着色器绘制风条时,没有绑定缓冲区或纹理。
从技术上讲,它甚至可以用作构建块,通过发出不同的旋转/缩放/剪切/剪切的拨打电话来绘制更复杂的形状,但它的基本硬编码四边形几何,但这太效率了。 p>
地形
地形纹理为256x256平铺图像。它们基于空中照片,上面撒上一些gimp魔术 - 对比度调整,颜色降低至10-12。这为他们增加了更老的外观,并使每个Texel更加明显。
渲染地形的着色器位于DiffuseScrollingFilteredShader.ts文件中。让我们看一下。
这是一个相当简单的着色器,简单地将紫外线坐在飞机下方的幻想中,可以在飞机下产生一种幻想。但是,还有另外一件事,它是纹理过滤。您可能想知道这里使用了什么过滤,地面显然未过滤,它使用GL_NEAREST
采样!但是,此处使用了一种自定义的抗质量块状过滤。事实是,常规的GL_NEAREST
采样在Texels的边缘会产生很多混溶。从连续旋转的摄像头的某些角度,这变得特别明显。 textureBlocky()
功能减轻了这些混叠的文物,同时保留了不过滤质地的额外酥脆的老式外观。地面纹理实际上使用GL_LINEAR
过滤,而textureBlocky()
计算采样点,以在边缘处获得插值过滤值,或者在任何其他区域中从Texel中心的中心进行了精确的未经过滤的值。
此过滤的原始作者是Permutator,并且在此着色器玩具-https://www.shadertoy.com/view/ltfXWS的CC0许可下使用代码(您可能会发现对此过滤技术中使用的数学的更深入解释)。
这是常规GL_NEAREST
滤波与自定义块状过滤的比较(4倍变焦)。如您所见,两者都是像素化的,但后者不被别名。
场景的最后一个增加之一是两个不同的地形纹理之间的过渡。当您切换它们时,它们不只是切换,而是使用可爱的像素化过渡效果来平稳切换纹理。
您可以在DiffuseScrollingFilteredTransitionShader.ts文件中找到此过渡的代码。过渡使用平铺蓝噪声纹理,以均匀地出现在地面上的方块。为了使过渡更平滑,使用了smoothstep()
。但是,与step()
有一条评论的线路,如果您喜欢的话,这会使过渡更加突然。
云
云不使用这种抗质量块状滤波,因为它们旋转不透明,并且移动相对较快。这使得很难在它们上发现异叠伪像,因此他们使用最便宜的选项-GL_NEAREST
采样。云使用带有切口的自定义网格,其中纹理为空。与常规的四轮网相比,这大大减少了透支。在这里,它可以通过禁用混合来可视化:
结果
您可以看到实时的Web Demo here,如果您想在Android手机的主屏幕上使用它,则可以在Google Play上获得Live Wallpaper应用程序。
源代码可在GitHub上找到,随时可以使用它。
一如既往,Web演示是为了获得最佳效率和性能的最快下载资源和Android应用程序的大量优化。 Web演示的初始加载仅为268 kb,所有型号和纹理的大小为1.4 MB,因此您可以将此数据放在软盘上。