渲染TA实战:眼球的渲染

哈喽,大家好,我是搜狐畅游引擎部的TA老胡,很高兴有机会和大家分享一下前一段时间工作和学习的成果。

前一阵,我做技术支持的项目提出,想要一个效果好一点的,眼睛的解决方案。

Unity自带的渲染部分,包含内容的丰富程度大家都是了解的,稍微有针对性一些的表现,就基本指望不上了,于是花了一些时间,研究学习了一下眼睛相关的知识,下面,就来和大家分享一下相关的内容。

先来看看最终的效果是什么样子的。

目前眼球实现的功能有,瞳孔的缩放,黑眼球整体的缩放,虹膜的颜色,角膜的折射,眼睛的焦散,眼睛的环境反射,眼球的次表面散射,角膜环的控制,上眼皮的遮蔽,眼底的液体,以及一些细节的调节等。

进入主题,按惯例,先从眼睛结构讲起。

眼睛的结构比较复杂,渲染的部分,基本只涉及到瞳孔,虹膜,巩膜,角膜这几个部分,这里引用Next-GenerationCharacter Rendering中的描述来说一下这几个部分。

巩膜 是眼睛的白色部分

虹膜 是彩色部分

瞳孔 是虹膜内的黑色部分

角膜 是覆盖所有这些元素的透明薄层,也是眼睛中发生的折射现象的起源

光线和视线穿过角膜和前方的房水,产生了折射后,到达了虹膜,所以要想产生眼睛的立体效果,就需要模拟折射的效果。

但是眼球中只有角膜区域(俗称黑眼仁)才会有折射产生,巩膜覆盖的区域(俗称白眼仁)并不会有折射效果,所以在计算折射前,先需要把角膜和巩膜的区域区分出来,这样就可以分别对两个区域做不同的计算了。

介绍怎么区分角膜和巩膜前,我们先看看眼睛模型的相关做法,这里主要分为了两个部分,一个部分是眼球,就只是个半球体。如下图

角膜,虹膜,巩膜,瞳孔的表现都是在这里进行的。

UE数字人Meet Mike和Next-GenerationCharacter Rendering中的眼球模型其实都是角膜部分有凸起的,如下图

这样在计算折射时,更容易产生比较好的效果。

但是这样的模型在眼球转动时,容易和外面那层半透明的模型产生交叉,凸起的规格又和shader计算上有一些关联,制作的不标准,反而会影响效果,美术制作起来会麻烦一点,所以我直接采用了半球型,大概效果上也不会差很多。

第二个部分,是内眼角,眼底的液体,睫毛和上眼皮对眼球的投影。模型是这样的。

这种做法,在游戏里应该已经很常见了,大家想必也很熟悉。

这样做,上眼皮对眼球的遮蔽和投影不会随着眼球的转动而跟着改变。眼球和下眼皮模型之间生硬的过渡,也可以产生柔和的效果。

这部分模型,使用半透明渲染,因为结构比较简单,正常屏幕占比又不会太高,所以基本不会和其他半透明物体产生排序问题。

这个部分主要是模型和贴图的工作,这里就不详细讲了。

现在我们来说怎么区分角膜和巩膜,这里虹膜和巩膜分别采样了两张单独的贴图,采样贴图时所使用的UV也是不同的。下面是虹膜和巩膜的贴图。

不过因为我们还做了眼球整体缩放的功能,所以角膜和巩膜的UV是需要在整体缩放的UV基础上做的。

整体缩放的功能比较简单,是通过以UV中心点为基点进行缩放。代码如下

Scale是传入的缩放值。

这种缩放方法,Scale值越大,模型的UV越向(0.5,0.5)的位置收缩,显示的结果就是贴图放大的效果。

基础的眼白贴图(巩膜)就可以使用缩放后的UV进行采样了。

接下来要计算出虹膜的mask区域。

使用缩放后的UV和UV的中心点(0.5,0.5)求距离,可以得到一个中间点为0,向外逐渐渐变成灰度的值,因为UV的边缘距离中心点的距离最大也不会到1,所以最亮也只是灰度值。如下图

然后我们再减去一个虹膜的半径值,可以得到一个随着半径值变大或者变小的黑色圆形区域。

半径值为0.2和0.35时的样子,半径值为shader传进来的参数。

作为mask图,我们需要的是尽量只有白或者黑的图,所以我们把结果再除以一个比较小的值,这样大于0的值,就会放大很多倍,变成白色,小于等于零的值,则依然小于等于零,显示黑色。

这样我们就可以得到一个这样的值。

再反向一下,就可以得到一个虹膜的mask图了。最后记得要把值,规范到0和1之间。

并且,因为我们使用的是有缩放功能的UV值,所以mask区域除了可以使用半径值单独缩放,也是可以随着UV的整体缩放一起缩放的。

这样,我们已经有了采样后的巩膜,还有区分巩膜和角膜的Mask。

下面就该角膜部分的计算了,因为要在单层半球模型上表现出外层透明角膜和内层彩色虹膜的效果,需要在采样虹膜贴图时,对UV进行偏移,因为还需要瞳孔缩放的功能,所以还要加上缩放,这部分也是眼睛渲染中比较复杂一点的地方。

虹膜UV的偏移方式大致上有两种,一种是使用视差贴图的方式,一种是基于物理的折射。

下面是Next-GenerationCharacter Rendering中提供的两种方法的基本算法。

视差贴图的方式计算比较简单,基于物理的折射,计算上要复杂一些,但效果也会更好一些。

我这里采用了基于物理的折射。实现方法和UE数字人Meet Mike的折射算法基本一致。

我们先看一下Meet Mike中折射的大概蓝图。

还是比较复杂的,里面还有些代码处理的自定义节点,不过下载工程后捋一遍,还不算太困难。

下面先来看一下,计算需要准备那些参数。

我们需要入射方向,这里是使用视线的方向,也就是观察方向。这个比较容易求出来,不多说。

我们还需要视线经过角膜折射后的方向,这个要怎么求出来呢,我是直接搬运的UE中的算法,如下图。

airIOR是空气中的折射率,internalIOR是射入角膜的折射率,这个网上可查,一般在1.3-1.4就可以。这样就可以求出折射后的方向。

还需要一个虚拟虹膜的法线方向,也就是上面图中的frontNormal,这个要怎么得到呢,这个是通过一张法线贴图得到的,图如下

图来自UE的数字人工程。

可以看出来,左侧的适合眼球模型有凸起,右侧的适合没有凸起的。

为什么这个图可以得到虹膜的法线呢?如果想要自己制作,又要怎么制作呢?

我们通过下面这个图来想象一下,假设虹膜是眼球中的一个plane,plane前面的球形部分是角膜,那么,如果把这个plane的法线烘焙到球形上,就会得到类似上面的法线图。

然后当我们采样这张图,再把法线贴图转换成法线向量时,是不是就可以得到类似虹膜的法线了。

我们还需要角膜各个部分到虹膜的高度,即下面图中红色箭头的长度值。

因为虹膜是虚拟的,并没有真实的模型,所以需要通过取巧的方式获得。

在UE的Meet Mike项目中,是使用了一张HDR格式的HeightMap来获得的,如下图。

这张图的数值范围,大概是从0-2,为了节省一点点,我使用的是普通的从0到1的一张图,采样后,又乘了2。精度上应该没有HDR的准确,不过效果上看,也可以接受。

这样,就有了折射计算所需要的基础数据,结合之前计算出来的角膜UV,就可以计算出折射后的UV偏移值还有一个IrisMask的数值了。

具体的计算还是比较复杂的,对细节过程感兴趣的同学,可以下载Meet Mike的工程,查看ML_EyeRefraction的详细计算。

或者看看文章末尾列出的YivanLee大佬 的那篇文,里面有比较详细的代码计算步骤。

使用折射后偏移的UV和IrisMask采样虹膜的贴图,就可以得到有折射效果的眼球了。

到此,眼球区别于其他常见类型的渲染部分,就差不多说完了,剩下的光照计算部分,其实和普通的PBR渲染差不多,我们就只说说不太一样的部分和一些小调整。其他的基本光照计算,这里就不详细说了。

首先,为了眼球能有一个比较漂亮的高光,在眼球shader中,在光照方向计算时,给眼球添加了一个Y轴旋转的高光偏移值,这样可以解决场景中的光照角度比较大时,眼球的高光点位置会被眼皮遮挡的问题。示意图如下。

这样就可以在不影响场景光照的前提下,给眼睛一个合适的光照方向。

光照角度X为30时,无偏移的效果

偏移后的效果

然后眼球还需要一个单独的cubemap来计算反射,并需要给这个cubemap一个旋转值,这样可以调整到最合适的反射角度,让眼睛有一个好看的反射光斑。

上面的图是使用了不同反射球的效果。

因为眼睛的反射需要的是少量的亮斑,所以需要的反射球尽量是亮暗对比比较强烈的,效果才会比较好,大家可以多多尝试一下。

还有焦散的计算,因为眼球的结构,虹膜从边缘到瞳孔的位置,其实是有一些内凹的,所以当光线从眼睛的右上方向照过来时,照亮的却是虹膜的左下部分。

图中可以看出来整体的光照方向,是从左侧照过来的,虹膜接受光照的位置是右侧。

这样,就需要一个凹陷的法线来参与光照计算了,这个凹陷的法线,可以通过反向眼球本身的法线来获得,当然我们只需要角膜范围内的部分就够了。

Meet Mike项目的眼睛ShadingModel中,还对这个凹陷的法线进行了一些加工,用虹膜的法线(就是前面通过一个plane烘焙出来的那张)和凹陷后的法线进行lerp融合,决定lerp融合的参数是通过折射计算出来的IrisMask。下面是UE中具体的焦散算法。

具体的代码,可以在ShadingModels.ush中的EyeBxDF函数中找到。我的焦散基本上采用了UE的这种方法,只是有一些简单的微调,方便美术调节

其实眼球的整体实现还是挺复杂的,说了这么多,还是有很多细节没有讲到,如果以后有机会,可以再更完整的聊一聊,这篇就先说这么多了。

最后,我们看一下完成后的动态效果。

到这里,关于眼球的渲染分享,就结束了,写写大家耐心观看,再见^_^。

在学习和实现的过程中,主要参考了以下的内容:

1向往大佬发表在博客园的文章《剖析Unreal Engine超真实人类的渲染技术》中的眼球篇

https://www.cnblogs.com/timlly/p/11144950.html

2 YivanLee 大佬在知乎上的文章 虚幻4渲染编程(人物篇)第三卷:Human Eye Rendering

虚幻4渲染编程(人物篇)【第三卷:Human Eye Rendering】 - 知乎

3 UE官方在GDC2017分享的 数字人类 Meet Mike,在虚幻商城里,可以免费下载到完整工程。

4 GDC2013上的Next-GenerationCharacter Rendering PPT

http://www.iryoku.com/downloads/Next-Generation-Character-Rendering-v6.pptx

还有一些网上零零碎碎的知识。

感谢众多大佬的无私奉献,当然,还是UE最给力。

一句话总结这段学习和研究:俺不生产知识,俺只是知识的搬运工。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组某个元素渲染数组
在Kanzi中,渲染的过程可以分为以下几个步骤: 1. 创建Renderer对象:使用Renderer类的构造函数创建一个Renderer对象,该对象用于进行渲染操作。 2. 创建Scene对象:使用Scene类的构造函数创建一个Scene对象,该对象用于管理场景节点和渲染对象。 3. 创建Camera对象:使用Camera类的构造函数创建一个Camera对象,该对象用于定义视图矩阵和投影矩阵,控制相机的位置和旋转。 4. 创建渲染对象:使用Mesh类、Material类和Texture类创建渲染对象,这些对象表示要渲染的几何图形、材质和纹理。 5. 创建场景节点:使用Node类创建场景节点,将渲染对象添加到场景节点中,并设置节点的变换矩阵。 6. 添加场景节点:将场景节点添加到Scene对象中。 7. 渲染场景:使用Renderer类的renderScene函数,将Scene对象和Camera对象作为参数传入,进行渲染操作。 具体的渲染过程可以参考以下代码示例: ```cpp // 创建Renderer对象 Renderer renderer; // 创建Scene对象 Scene scene; // 创建Camera对象 Camera camera; // 创建渲染对象 Mesh mesh; Material material; Texture texture; // 创建场景节点 Node node; node.addMesh(mesh); node.setMaterial(material); node.setTexture(texture); node.setLocalTransform(Matrix4f::translation(Vector3f(0.0f, 0.0f, -5.0f))); // 添加场景节点 scene.getRootNode().addChild(node); // 渲染场景 renderer.renderScene(scene, camera); ``` 在渲染过程中,Scene对象管理了场景节点和渲染对象,并提供了一些方便的函数来操作它们;Camera对象定义了视图矩阵和投影矩阵,并控制相机的位置和旋转;Renderer对象负责将场景渲染到屏幕上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搜狐畅游引擎部

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值