UE4 Texture纹理全解 (一)
渲染离不开纹理,关于纹理相关的知识也很杂,把之前学过的相关知识进行一下总结分享出来。1.基础扫盲
目前学习UE4的xdm可能是各行各业(比如我是地质)转过来的,对于很多计算机图形和图像处理的东西没有基础概念。为了更好的理解UE4种的纹理贴图texture与相关实际应用,这里进行简单的基础扫盲。
1.1 RGB颜色
要讲纹理,先说颜色。干CG行业还搞不清现实中人眼看到的颜色和计算机图像里的颜色就尴尬了。
小时候学的三原色红黄蓝指的是物质被光照到反射的颜色,不吸收什么色的光就呈现什么颜色,混在一起黑色。而我们CG常用的红绿蓝RGB是指光的颜色,显示器屏幕我们多少都了解其组成单元就是RGB的晶格,通过给予不同的亮度呈现不同的颜色,全亮则呈现白色。搞过平面的同学最常用的PS,搞包装设计要用CMYK,搞电商海报用RGB,一个是印刷颜色,一个是显示器颜色,印刷色多了个K黑色是因为混合CMY吸收的光不够多,呈现的黑色不够黑,多次叠加又浪费颜料,所以用一种吸收光较强的颜料作为黑色。
传统美术中,常用色相hues,饱和度saturation,明亮度brightness来表达一个颜色的属性,也就是HSB/HSV,相比RGB而言,这种调色模式也更符合艺术家的偏好。
还有其他颜色模型HSL,YUV,Lab等等,但我们主要研究的是RGB颜色模型,就不展开了。
1.2 位图
我们接下来要讲的纹理,都是位图,保存方式为点阵储存。这样就有了像素的概念,每个像素储存所要的颜色,颜色以数字化的形式保存。当放大图像时,像素点也放大了,每个像素记录的颜色还是单一的,就出现了我们平时见到的马赛克。
然后再说说16位,24位,32位颜色怎么回事。我们小时候应该都经历过16位色的时代,第一感觉就是颜色不够丰富。16位色就是用R5G6B5来储存, 2^5 * 2^6 * 2^5 = 2^16
01111 110011 11001
红 绿 蓝
现在我们使用的是32位色即R8G8B8A8,每个分量用8位表示,其中A是alpha描述透明度。而透明度是前景色与背景色混合时才有意义,计算公式为
Color = Color1 * alpha + Color2 * (1.0f - alpha);
1.3 图像概念
图像取样与量化
取样:图像空间坐标的数字化。(不就是uv么)
量化:图像函数值(灰度值)的数字化。(不就是0~1/0~255的值么)
灰度图像与彩色图像 区别就是一个量化的灰度级,跟三(RGB)个量化的不同灰度级来描述像素。
模拟图像可用连续函数来描述,空间坐标和明暗程度均为连续变化的。
I=f(x,y)
x,y是空间坐标,I是灰度。
通过以上,我们研究的texture 范围就锁定在了RGBA,位图等属性内。
2.纹理压缩
数据压缩是指减少表示给定信息量所需数据量的处理。太抽象了,反正目的就是缩减图片文件的大小,在游戏中就是为了节省内存。
一幅大小为512*512 的8比特图像,所需数据量为:
512*512*8=2Mbit=256KByte
最古老的压缩RLE算法,假设一张图片里连续几百个像素都是同一种颜色,那么就造成了数据冗余的现象,我们可以记录这个区域 0~几百为xx颜色,当然,这是当时的颜色很少的时候所用的方法,现在都32位真彩色了,这种方法失效了。
于是哈夫曼编码出场了,有点复杂这里不展开了,感兴趣的同学可以深入探索,数字图像处理的图像压缩章节。还有算术编码,LZW编码,这些都是无损压缩,解决了编码冗余,像素间冗余。
我们的重点其实是有损压缩,因为有损压缩才能真正的解决文件大小问题,但是有损压缩导致信息的损失,需要跟原始图像做偏离值的对比,通过我们人眼观察来看则是主观保真度准则,均方根误差和均方信噪比则是客观保真度准则。最常见的格式JPEG就是基于块变换编码离散余弦变化和量化的,扯远了,我们不用JPEG格式,我们在DCC软件中制作的纹理TGA格式或PNG格式,它们都支持无损压缩,都有alpha通道。不同的是TGA对于美术同学来讲更方便编辑alpha通道,而PNG更小,适合用于UI界面。
划重点,上面的TGA、PNG是我们在PS,SD,SP等等软件输出的图片格式,而我们往UE4中导入图片都会自动压缩BC/DXTC,BC就是块压缩Block Compression的缩写,DXTC是DirectX Texture Compression的缩写,二者是同一个东西。3D游戏大都使用这种DDS(DirectDraw Surface)格式,并称之为贴图。
经过上面的铺垫(废话),终于进入正题了。
无压缩
有压缩
注意看压缩设置 、resource size和 format 。一张4k的texture 未压缩的情况下format 是B8G8R8A8,大小是87381kb,而默认DXT1压缩下只有10923kb。DXT后面的序号又有什么不同呢?
BC3/DXT5是包含alpha通道的,BC1/DXT1不包含alpha通道。当我把一个有alpha通道的纹理勾选压缩不包含alpha选项时,它会自动从DXT5转成DXT1,并且size减半。
1.BC1(DXGI_FORMAT_BC1_UNORM):该格式支持3个颜色通道,仅用1位(开/关)表示alpha分量。
2.BC2(DXGI_FORMAT_BC2_UNORM):该格式支持3个颜色通道,仅用4位表示alpha分量。
3.BC3(DXGI_FORMAT_BC3_UNORM):该格式支持3个颜色通道,以8位表示alpha分量。
4.BC4(DXGI_FORMAT_BC4_UNORM):该格式支持1个颜色通道(例如,灰阶图像)。
5.BC5(DXGI_FORMAT_BC5_UNORM):该格式支持两个颜色通道。
6.BC6(DXGI_FORMAT_BC6_UF16):该格式用于压缩的HDR(高动态范围,high dynamic range)图像数据。
7.BC7(DXGI_FORMAT_BC7_UNORM):该格式用于高质量的RGBA压缩。特别的有,这个格式可以显著地减少由于压缩法线贴图带来的错误。
引擎会识别法线贴图和HDR贴图并自动为我们进行压缩设置,导入时右下角还会有提示信息。
3.纹理用途
看到这里我们回顾一下,上面在讲图片时说的都是颜色信息,但纹理存的一定是颜色么?
当然不了,我们可以存各种信息,比如地形高度图,烟雾的motion vector,法线,noise等等。下面我就常用的一些做简单总结:
3.1基础PBR流程贴图
颜色贴图:BaseColor/Diffuse 不含光照信息的,最基础的漫反射颜色贴图。只有颜色信息,那肯定是只有RGB通道,默认BC1格式压缩。这里插播一个sRGB与gama校正相关的知识点,用来储存颜色的贴图应该勾选sRGB,储存其他信息的贴图不应该勾选sRGB,还有一些信息勾不勾都无所谓。
Linear到Gamma
Linear^2.2=Gamma or 255*POWER(linear/255,1/2.2)
Gamma到Linear
Gamma^(1/2.2)=Linear or 255*POWER(gamma/255,2.2)
我们只需记住用法和2.2次幂即可,深究线性空间和gama空间可以看这。
Emissive 自发光贴图 同颜色贴图。
RMA贴图:是粗糙度金属度和AO贴图的简写。UE4渲染走的是金属度粗糙度这套PBR,储存的都是0~1范围的浮点值 单通道信息(灰度图),所以我们常常把这仨存到一张texture的RGB通道里,选mask模式(实际上还是DXT1),no sRGB,这样更节省空间,没人傻到导入三张贴图再选成灰度图grey scale压缩(R8其实无压缩)。注意这里,如果还存了specular贴图,那么RGBA四个通道都要占用,这时选mask模式 实际上是DXT5。但是我们前面讲到禁用alpha可以省一半的size,这是因为BC3每个4*4的块压缩为128bits,其中rgb占用了64bits,alpha自己占用了64bits,所以当我们四个通道都要使用的时候应该把最重要的最需要精度的信息存在alpha通道里,包括后面其他贴图也是。
法线贴图normal map:法线是干啥的懂得都懂,下面再细嗦。引擎会自动识别法线并使用BC5压缩,只支持两个通道(量身打造,法线只需要两个通道)。法线的取值范围是-1到1,但是我们图片记录数据只能是0-1,这里有一步映射,在引擎中采样时又进行了还原,这些都是自动的,了解即可。
插播一个小知识点,为什么引擎里的颜色范围都是0~1,而Photoshop里是0~255。还是引擎为了更省性能,浮点值的精度有限,还要多记录2位整数部分岂不是浪费了。
3.2 凹凸/法线/置换/视差
提起法线,那么它的好兄弟们也得上场。先上两张图感受一下,Bump map凹凸贴图是比较古老的东西已经淘汰了,他是记录了高度height的灰度图,不包含方向信息,而法线包含方向信息。他们作用都是为了增加物体表现细节,但不改变真正的几何体,在侧面看是平的(如图fake displacement)。
法线贴图还分Tangent切线空间、Object对象空间、World世界空间,我们默认使用的是前者,看起来是淡紫色的。
Displacement Map 置换贴图 跟上面二者不同,他是真的改变了几何体,常与曲面细分一同使用,是真正的添加了额外的细节和消耗。它也是8-bit的灰度图,可以由高面模型烘焙而来,也可绘制而成。
Vector Displacement Map 矢量置换贴图 是记录了模型上各点的高度和方向信息。这两种置换贴图我并没有在引擎种使用过,原画同学倒是经常在blender里用置换贴图搞骚操作,对于游戏来说几乎不可用(可能在哪里被用到我没查到欢迎补充)。
Parallax Occlusion Map 视差遮蔽贴图(POM) 根据高度图height map以及像素深度和相机位置得出的朝向矢量,从当前uv与前面的高度图做线性的碰撞检测(实际上会参与一个步进:step)。当检测到碰撞后,返回当前的Offset,然后采样使用UV加上这个Offset。通过偏移每个像素的纹理坐标以达到更好的视觉表现。性能消耗受限于ray traced算法,需要更多step提高精度,要想效果好消耗就大,所以慎用。说了那么多 其实 直接用这个节点就行,代码都在这个节点里。
效果如下(月神三期里的弹坑特效):
3.3 Noise
<br> (二维码自动识别)
最最最常用的噪波图,用SD来制作noise贴图比较方便,现成的点击即用。当然UE4里也内置了noise节点,或者我们自己写燥波生成的函数,但是实时燥波的消耗过大,我们可以通过RT(render target)把它烘焙出来。
燥波图肯定是 no sRGB了,可以多个通道存不同的燥波。
常用燥波有:
white noise
perlin noise
Voronoi Noise
这些燥波常用来做云,烟雾,模拟水的焦散等等。
在制作特效时,经常叠加多种noise来制作UV偏移,如火,空气扰动,能量波等等效果。
https://zhuanlan.zhihu.com/p/47959352
https://www.unrealengine.com/zh-CN/tech-blog/getting-the-most-out-of-noise-in-ue4
燥波编辑器
3.4 ID/Mask
ID图是指一个复杂的模型,不同部位有不同的材质,画出遮罩到SP里上材质。
或者,画出遮罩到UE4里用material layer blend来分别给予不同的材质。
前者是在DCC里使用的ID图,可以是任意颜色,后者是在引擎里使用的ID图,一张图仅限RGBA四个通道的遮罩。
3.5 特效常用贴图
Mask遮罩:特效最常用的除了上面的叠加燥波图产生的纹理作为自发光之外,还有Mask遮罩贴图,可以是任何自定义的形状,还可以是数字 文字等,一般是非黑即白的,需要多个mask可以分通道储存到RGBA。这种贴图一般用于mask或者半透明材质的opacity/opacity mask。
Ramp渐变贴图:现在一般都用曲线来做渐变了,可以少采一张图,还可以随时修改数值。
把linear color曲线放到Atlas里,再到材质里调取使用。
Flipbook 序列图:在DCC软件中如maya,blender,houdini,embergen 把制作好的流体,烟雾等等,烘焙成序列帧的形式,到UE4的材质里用flipbook节点播放,或者在粒子里用subuvindex播放。
Motion Vector:是上面烟雾序列帧的升级用法,记录的数据是上一帧向下一帧位移的向量,所以也是需要同时在DCC里烘焙的,可以达到更好的混合效果,让烟雾看起来更丝滑。并且原来8x8的序列图可以大幅度缩减成4x4来提升精度(每一帧占用的分辨率变高了)。存的是向量,类似法线,所以储存时也映射到了0-1的范围,只有RG通道(两个方向的向量)所以是这个鬼颜色。引擎给出了节点可以直接使用,用于粒子的话可能要自己写一个,月神三期里有,我就直接用了。
Flow map:也是记录的向量,看起来也是这个鬼颜色,只有RG通道,不用压缩,用来做流动效果。
直接看ben的视频,对了 4.26官方的water 插件里也带了flow map可以去翻翻看。
https://www.youtube.com/watch?v=9N-pQNPChxU&list=PL78XDi0TS4lFlOVKsNC6LR4sCQhetKJqs
特殊贴图:做特效嘛, 我们当然可以想存什么就存什么信息。
比如物体表面的水珠,可以这样做:
SD画图,一层动态的大水滴生成消失,RG通道存法线信息,B通道存灰度不统一的Mask。一层静态的小水滴一直存在,A通道存Mask。
在UE4中还原法线,用timefrac 对大水滴mask做动态。根据mask信息来决定有水滴部分的粗糙度。
再比如下雨溅起的水花,可以这样做:
两个通道分别存了侧视图和俯视图的水花序列。通过Niagara的自定义alignment和facing功能和particle random value,在平视时显示R通道,俯视显示G通道。
3.6 Cubemap/2D texture/3D texture
上面讲的全是2D texture,引擎中还有另外两种cubemap和3D texture。
立方体贴图(CubeMap) 提供了一种进行环境映射的简单方法,通过这种方法,像天空、周围环境这样的远景可以映射到一个全景贴图上。在底层,这些贴图存储为6张图片,映射到立方体的内表面上。在之前的渲染管线学习中,我们的lightmap,shadowdepth,Reflection map都是cubemap。我们这里主要说HDR。
HDR这个图片格式记录的RGB信息是可以超过1的。
可以通过HDRI Backdrop插件直接使用。
3D Texture 最常见就是用来做体积云的,然后引擎的网格体距离场存的也是3D纹理。
以后开体积云篇细嗦。需要在DCC里创建,然后导入引擎,再用volumetric 插件里的工具转换一下。
之前做的效果体积云效果:
还有一些特殊贴图,下一篇再讲,比如LUT,UI,RT等。
4.简单思考图片的缩放
缩放图片时,我们只需要用鼠标拖拽一下图片,或者输入一下数字。但是图片被缩放后的像素该显示什么颜色呢?
假设图片的高度从h1缩放到h2,找到相同比例的地方(u,v)的坐标,把最近点的颜色取出来。
float v= h/h2;
inty = (int)floor(v * float(h1) + 0.5f);
像素是整数,颜色是浮点数,所以需要一个四舍五入的取整操作。
但是最近点采样会造成颜色的丢失,最常用的是线性采样,也就是取最近的2*2像素求加权平均。假设我们有ABCD四个相邻的像素点,经过图片缩放后,我们要计算位置X(u,v)的点的颜色。
假设X点的uv坐标小数部分是(0.45,0.8)
那么计算纵坐标插值,再计算横坐标插值:
color1 = A*0.8+C*(1-0.8);
color2 = B*0.8+D*(1-0.8);
colorX = color1*(1-0.45)+color2*0.45;
这样就结束了吗?没有,让我们思考另一个问题,在工作中一直被告知贴图一定要使用2的幂次方的分辨率,如256x256,512x1024,2048x2048这种。简单两个字:优化,那到底是因为什么呢?留到下篇的采样,mipmap和纹理池流送讲。
好耶[调皮] 已收藏,[调皮]。。。很详细 感谢冲佬,扫盲好棒 批评你的陨石坑step调太小 [滑稽] 有用,但又不完全有用 下次争取写点有用的[捂脸] 这个挺好的。我在顽梗,哈哈[开心] [害羞]得到了大佬的认同
页:
[1]
2