当前位置:   article > 正文

Unity 渲染教程(三):使用多张纹理贴图

unity 材质球墙面壁纸怎么重复多少次uv贴图

对多个纹理进行采样

应用一张细节贴图

在线性空间中处理颜色

使用一张splat纹理

这是关于渲染的教程系列的第三部分。 前面的部分介绍了着色器和纹理。 我们已经看到如何使用单个纹理来使平坦表面看起来更加复杂。 现在我们超越了它,同时使用多个纹理。

本教程是使用Unity 5.4.0进行的,目前该版本是开放测试版。 我使用build 5.4.0b15。

混合的多张贴图

texel的解释

texel(纹理元素的简写)是纹理图形的基本单位,用于定义三维对象的曲面。3D 对象曲面的基本单位是纹理,而 2D 对象由像素组成。

纹理,纹理元素或纹理像素是纹理图的基本单位,[1]用于计算机图形学。 纹理由表示纹理空间的纹素数组表示,就像其他图像由像素数组表示一样。

Texels也可以通过通过简单的过程获得的图像区域进行描述,例如阈值。 Voronoi细分可以用来定义它们的空间关系。 这意味着在每个纹理像素的质心和每个周围纹理的质心之间的中点进行整个纹理的划分。 结果是每个纹素重心都会围绕着一个Voronoi多边形。 这个多边形区域由所有比其他质心更贴近纹素质心的点组成

当纹理化3D表面或表面(称为纹理映射的过程)时,渲染器将纹素映射到输出图像中的适当像素。在现代计算机上,该操作在图形处理单元上完成。

纹理过程从空间中的位置开始。该位置可以在世界空间中,但通常它在模型空间中,使得纹理与模型一起移动。将投影机功能应用于位置,以将位置从三元素向量改变为值为零到一(uv)的两元素向量。[3]这些值乘以纹理的分辨率以获得纹素的位置。当请求的纹素不在整数位置时,应用纹理过滤。

当请求纹理外部的纹理,使用两种技术之一:夹紧或缠绕。夹紧将纹理限制到纹理大小,如果超过纹理大小,则将其移动到最接近的边。包装以纹理大小的增量移动纹理文件,以将其重新导入纹理。包装导致重复纹理;夹紧使其仅在一个位置。

纹理很好,但是有局限性。 它们具有固定数量的纹素,无论它们显示什么大小。 如果它们变小,我们可以使用mipmap来保持它们的良好状态。 但是当它们变大时,它们变得模糊。 我们不能发明任何细节,所以没有办法。 还是在那里?

当然,我们可以使用更大的纹理。 更多的纹素意味着更多的细节。 但纹理的大小有限制。 存储很多额外的数据是很浪费的,这些数据只是很接近。

增加纹理密度的另一种方法是平铺纹理。 那么你可以得到你想要的那么小,但你显然会得到一个重复的模式。 尽管如此,这可能并不明显。 毕竟,当你站在你的鼻子上碰壁,你只会看到整个墙壁的一小部分。

因此我们最好是能够通过合并未平铺的贴图和一张平铺的贴图来实现添加纹理。为了达到这个目的,让我们使用一张有明显样式的贴图。下面是一张方格网格。默认设置方式导入工程。我稍微扭曲了一下网格,使它更有趣,并使它可以感知到它的平铺。

轻微扭曲的网格贴图

复制一份My First Shader并重新命名为Textured With Detail。我们从现在开始使用新的 shader。

Shader"Custom/Textured With Detail"{    Properties {        _Tint ("Tint",Color) = (1,1,1,1)        _MainTex ("Texture",2D) ="white"{}    }    SubShader {        …    }}

创建一个新的材质球,并把这张贴图赋值给它。

带网格的细节材质

把材质球附加给四边形并查看一下。从远处看,它还挺好的。但是越靠近,它会变得越来越模糊。除了缺少细节外,由于压缩而导致的粗糙的艺术品也特别明显。

多次贴图采样

目前为止我们只是使用单张贴图来进行的采样,并使用采样的数据作为我们的片段程序的结果。接下来,我们将尝试去改变这种取样的方式,我们可以把采用的数据存储在一个临时的变量当中。

float4 MyFragmentProgram (Interpolators i) : SV_TARGET {                float4color= tex2D(_MainTex, i.uv) * _Tint;returncolor;}

我们推断,我们可以通过引入一张平铺纹理来增加纹理密度。 我们简单地表现第二张纹理,这张纹理的采样是原始纹理采样的10倍的平铺,它是原始样本的十倍。 实际上替换原来的颜色,而不是叠加上去的。

float4color= tex2D(_MainTex, i.uv) * _Tint;color= tex2D(_MainTex, i.uv *10);returncolor;

这样就产生了更细更小的网格。在网格看起来模糊之前,你现在要比前面能够靠得更近一些,也就是说没那么容易看得出来模糊了,也就是图像的分辨率变得更高了。

注意,到目前为止,我们表现了2张贴图,而最终只使用了他们中的一张。这看起来很浪费。是这样吗?让我们来看看编译后的代码,分别在 OpenGLCore 和Direct3D 11平台下。

uniformsampler2D_MainTex;invec2vs_TEXCOORD0;layout(location =0)outvec4SV_TARGET0;vec2t0;voidmain(){    t0.xy = vs_TEXCOORD0.xy *vec2(10.0,10.0);    SV_TARGET0 =texture(_MainTex, t0.xy);return;}

SetTexture0[_MainTex]2D0ps_4_0      dcl_sampler s0, mode_default      dcl_resource_texture2d (float,float,float,float) t0      dcl_input_ps linear v0.xydcl_output o0.xyzwdcl_temps10:mulr0.xy, v0.xyxx, l(10.000000,10.000000,0.000000,0.000000)1: sample o0.xyzw,r0.xyxx, t0.xyzw, s02:ret

硬编码的平铺

你发现没,在编译过后的代码中只有一张贴图在采样?对的。编译器替我们移除掉了不需要的代码。本质上来讲,编译器会以最后的结果为准,而舍弃掉任何对于结果无用的的事情。

当然话又说转来,我们并不是想替换掉原来的取样。我们想要的是合并两次取样。让我们把这两次取样的结果相乘起来,来实现我们想要的合并效果。

float4color= tex2D(_MainTex, i.uv) * _Tint;color*= tex2D(_MainTex, i.uv);returncolor;

那 shader 编译器是如何做的呢?

uniformsampler2D_MainTex;invec2vs_TEXCOORD0;layout(location =0)outvec4SV_TARGET0;mediumpvec4t16_0;lowpvec4t10_0;voidmain(){    t10_0 =texture(_MainTex, vs_TEXCOORD0.xy);    t16_0 = t10_0 * t10_0;    SV_TARGET0 = t16_0 * _Tint;return;}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/98172
推荐阅读
相关标签
  

闽ICP备14008679号