关于shader:高级纹理映射

2次阅读

共计 2988 个字符,预计需要花费 8 分钟才能阅读完成。

立方体纹理

立方体纹理是环境映射的一种实现办法。立方体纹理就是将沿着世界空间下察看失去的上下左右前后六个方向的图像存储在立方体的六个面上。它能够实现反射和折射的成果。
能够通过 3D 方向矢量对立方体纹理进行采样,从立方体核心登程,沿着矢量方向延长就能够和立方体的六个纹理之一产生相交,交点就是须要采样的纹理。

天空盒子

天空盒子用于模仿背景。它是一个盒子,应用 skybox 时,整个场景被突围在一个立方体内。立方体的每个面应用立方体纹理映射技术。

  1. 创立一个材质,并抉择 skybox/6 sided,并将六张纹理图赋值给材质,将纹理的 WrapMode 设置为 Clamp, 避免在接缝处呈现不匹配。
  2. 将材质赋给摄像机,或者在 Lighting 中将材质赋值给 Skybox 选项(这个办法会将所有摄像机的 skybox 设置为同一个 ).
创立立方体纹理

创立立方体纹理的办法有三种,第一种应用非凡纹理,官网举荐,参照第 18 章。第二种办法创立一个 Cubemap(Create,Legacy,Cubmap), 而后将 6 张纹理拖拽到它的面板中。第三种办法应用程序生成纹理,它能够依据物体在场景中的地位的不同,生成它们各自不同的立方体纹理,通过 Unity 提供的 Camera.RenderToCubemap 函数来实现。
第三种办法创立立方体纹理的步骤如下:

  1. 筹备好程序脚本。
  2. 创立一个空的 GameObject, 将以这个 GameObject 的地位信息来渲染立方体纹理。
  3. 创立一个 Cubemap 用于存储立方体纹理,并将 Readable 勾选。
  4. 应用脚本将以 GameObject 为核心察看到的世界空间下的 6 张图渲染到立方体纹理中。

Cubemap 的 facesize 越大,分辨率越大,成果越好,占用的内存也越大。

反射

应用立方体纹理使得物体具备反射成果。如图,就像镀了一层金属。

步骤如下:

  1. 调整模型的地位,将其与生成立方体纹理的 GameObject 的地位一样。而后将立方体人纹理赋给模型。
  2. 给 Shader 的 properties 增加属性_Cubemap(类型为 Cube)
  3. 在顶点着色器中用 reflect 函数取得物体的反射方向 o.worldRefl = reflect(-o.worldViewDir,o.worldNormal);
  4. 在片元着色器中利用反射方向对立方体纹理_Cubemap 进行采样。fixed3 reflection = texCUBE(_Cubemap,i.worldRefl).rgb * _ReflectColor.rgb;
  5. 最初将反射色彩和漫反射色彩线性混合并和环境光相加后返回。
折射

应用斯涅耳定律,n1sino1=n2sino2 来计算折射方向。
步骤如下:

  1. 调整模型的地位,并赋给材质。
  2. 在 Shader 中申明透射比和立方体纹理
  3. 在 顶点着色器中计算折射方向,须要将入射光线和外表法线归一化。o.worldRefl = refract(-normalize(o.worldViewDir),normalize(o.worldNormal),_RefractRatio);
  4. 在片元着色器中利用折射方向对立方体纹理进行采样。fixed3 reflection = texCUBE(_Cubemap,i.worldRefl).rgb * _RefractColor.rgb;
  5. 混合漫反射色彩和折射色彩并和环境光相加后返回。
菲涅尔反射

菲涅尔反射形容这样一种光学景象,即照射到物体外表的光线,一部分被折射一部分被反射,并且折射的光和反射的光存在比例关系。比方在湖边能够分明的看到脚边的水底,却看不到远处的水下情景。
菲涅尔反射与视角方向无关,近似等式为:F(v,n)=F0+(1-F0)(1-v*n)^5。F0 是反射系数。

步骤如下:

  1. 调整模型的地位,并赋给材质。
  2. 在 Shader 中申明菲涅尔反射系数和立方体纹理。
  3. 在顶点着色器中计算反射方向。o.worldRefl = reflect(-o.worldViewDir,o.worldNormal);
  4. 在片元着色器中计算菲涅尔反射。fixed fresnel = _FresnelScale + (1 – _FresnelScale)*pow(1-dot(worldViewDir,worldNormal),5);
  5. 利用菲涅尔反射混合漫反射和反射色彩。fixed3 color = ambient + (lerp(diffuse,reflection,saturate(fresnel))+specular)*atten;

渲染纹理

渲染纹理就是利用一个摄像机,将其看到的图像渲染到一个两头缓冲中,这个两头缓冲就是渲染指标纹理。利用渲染纹理,咱们能够实现镜子成果,和玻璃成果。

镜子成果

步骤如下:

  1. 创立一个材质。
  2. 创立一个立方体将其作为镜子,并调整其地位和大小,将第一步创立的材质赋值给它。
  3. 创立一个渲染纹理(create,render texture)
  4. 创立一个摄像机,调整其地位,裁剪立体,视角等,而后将摄像机看到的图像渲染到渲染纹理(将第三部创立的渲染纹理拖拽到摄像机的 target texture 上)。
  5. 在 shader 的顶点着色器中翻转纹理坐标的程度坐标,对渲染纹理进行采样。

总的来说渲染纹理,就是将摄像机看到的图渲染到一张两头图中,将其作为纹理贴图,而后将纹理贴图渲染到物体外表。

玻璃成果

除了应用一个额定的摄像机获取屏幕图像,还能够在 unity shader 中定义一个 GrabPass,而后 unity 会将以后屏幕的图像绘制在一张纹理中供咱们在后续的 pass 中拜访。GrabPass 能够用来模仿通明材质,然而与简略的应用通明混合不同,其能够对物体前面的图像进行更简单的解决。然而要额定小心渲染队列设置,将其设置为 Transparent,保障所有不通明物体先被渲染。

步骤如下:

  1. 在 shader 的 properties 中定义玻璃的材质纹理,法线纹理,立方体纹理等。
  2. 在 SubShader 中定义 GrabPass。GrabPass {“_RefractionTex”}。unity 会将以后屏幕图像绘制在_RefractionTex 中,供后续 Pass 拜访。
  3. 在 Pass 中定义_RefractionTex 和_RefractionTex_TexelSize 变量,_RefractionTex_TexelSize 是文素大小。
  4. 在顶点着色器中获取顶点的屏幕坐标,o.scrPos = ComputeGrabScreenPos(o.pos);
  5. 在片元着色器中利用法线等信息计算偏移量,而后用偏移量对屏幕图像_RefractionTex 进行采样,以此来模仿折射成果。

          fixed2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
             i.scrPos.xy = offset + i.scrPos.xy;
             fixed3 refrCol = tex2D(_RefractionTex,i.scrPos.xy/i.scrPos.w).rgb;
         

而后计算反射方向,用反射方向对 Cubemap 进行采样。最初将反射色彩和折射颜色混合返回。

总的来说,这个办法就是,利用反射那一节的 办法来计算物体外表的反射色彩,而后利用 GrabPass 获取到的屏幕图像,对其采样来模仿折射(采样坐标通过了偏移,这样失去的纹理看上去就像扭曲了一样),失去折射色彩,最初将反射和折射颜色混合。

程序纹理

程序纹理就是利用 c# 脚本来生成纹理图像。

正文完
 0