Shader从入门到跑路:自定义纹理输入

作者:俊铭 2020-03-12

上文:Shader从入门到跑路:朴实无华的图形学基础

上节课后作业答案

只需要将返回颜色的蓝色通道更改为1,就可以得到课后作业的渲染结果

  1. float4 frag(v2f i) : SV_Target
  2. {
  3.         float4 color = float4(i.uv.r, i.uv.g, 1, 1);
  4.         return color;
  5. }
复制代码

课后作业渲染结果

前言

实在是手残,不小心把这篇文章删掉了,问了客服好像并没有解决办法,希望知乎以后可以提供恢复误删文章的功能...只能再手打一遍了,欲哭无泪。

正文

上一章我们都是指挥unity来获取渲染信息,那么接下来就介绍如何将图片输出到物体上。

背景为透明的我老婆

为了展示接下来的内容,我在PS内制作了一张带有透明通道的PNG图片,正确的渲染效果应该是显示人像,而背景部分则显示图片后面的场景物体(即应该为透明的)。

现于SubShader区块上面新增一个Properties区块,并在其中定义一个MainTexture的二维属性。

  1. Properties{
  2.         _MainTex("Main Texture", 2D) = "white" {}
  3. }
复制代码


注意,在属性区块内被定义的数据在CGPROGRAM内被使用之前都要预定义一遍,不然会报错。在CGPROGRAM内加入纹理的定义:

sampler2D _MainTex;

在这里的sampler2D是一个GLSL的类型,表示用来存储一个2D纹理

https://www.khronos.org/opengl/wiki/Sampler_(GLSL)

接下来,在frag函数中利用tex2D这个方法来获取纹理中的颜色,并直接使用颜色进行着色。这个方法其实就是在一张纹理中对一个点进行采样,我们要得到整个纹理的颜色,就需要所有像素对应的uv点,代码如下:

  1. float4 frag(v2f i) : SV_Target
  2. {
  3.         return tex2D(_MainTex, i.uv);
  4. }
复制代码

然而我们却得到了一些奇怪的渲染结果,来看一看为什么。


与预期不符的渲染结果,背景应该是透明的

可见得出的渲染结果并不符合我们的预期,本来在PNG里背景被设置为透明的图片,背景变成了白色。这是因为tex2D在处理纹理的时候会计算每一个对应uv点的像素颜色,但是本应是透明的内容是不会有”颜色“这一属性的,然而tex2D还是将它们视为待计算的颜色,这才出现了错误。

为了解决这个问题,我们需要一种叫Transparent Blend的技术。其实就是定义一下在shader里面,目前处理的像素如何与它后面像素混合。混合模式有很多种:

https://docs.unity3d.com/Manual/SL-Blend.html

我们这次用的是一种叫做Alpha Blend的东西,定义CGPROGRAM外面,它长这样:

Blend SrcAlpha OneMinusSrcAlpha

它的意思是将源颜色乘上源颜色的透明度,与目标颜色乘(1 - 原颜色的透明度)的结果相加,公式如下:

OutColor = SrcColor * ScrAlpha + DstColor * (1 - SrcAlpha)

或许这有些难以理解,但只要稍微思考一下就好了,将两个颜色的减淡后叠加在一起,便产生了一种中间色,看起来就好像透过目前的物体看到了后面的物体一样。

下一步则是要在SubShader的tag区块内设置shader的渲染通道,以确保在非透明的物体渲染结束后才渲染我们的透明物体。

  1. Tags
  2. {
  3.         "Queue" = "Transparent"
  4. }
复制代码

如果你跳过了这一步,那么就会出现一些奇怪的渲染效果。对于好奇心重的同学,欢迎跳过设置渲染通道来看看错误效果。

正确的渲染结果,可以透过透明部分看到后面的物体

完整的shader代码:

  1. Shader "Custom/ShaderLearning"
  2. {
  3.         Properties{
  4.                 _MainTex("Main Texture", 2D) = "white"
  5.         }
  6.         SubShader
  7.         {
  8.                 Tags
  9.                 {
  10.                         "Queue" = "Transparent"
  11.                 }
  12.                 Pass
  13.                 {
  14.                         Blend SrcAlpha OneMinusSrcAlpha
  15.                         CGPROGRAM
  16.                         #pragma vertex vert
  17.                         #pragma fragment frag
  18.                         sampler2D _MainTex;
  19.                         #include "UnityCG.cginc"

  20.                         struct appdata
  21.                         {
  22.                                 float4 vertex : POSITION;
  23.                                 float2 uv: TEXCOORD0;
  24.                         };

  25.                         struct v2f
  26.                         {
  27.                                 float4 vertex : SV_POSITION;
  28.                                 float2 uv: TEXCOORD1;
  29.                         };

  30.                         v2f vert(appdata v)
  31.                         {
  32.                                 v2f o;
  33.                                 o.vertex = UnityObjectToClipPos(v.vertex);
  34.                                 o.uv = v.uv;
  35.                                 return o;
  36.                         }

  37.                         float4 frag(v2f i) : SV_Target
  38.                         {
  39.                                 return tex2D(_MainTex, i.uv);
  40.                         }
  41.                         ENDCG
  42.                 }
  43.         }
  44. }
复制代码

作者:俊铭
专栏地址:https://zhuanlan.zhihu.com/p/86096949

最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多