Unity3D Shader官方教程翻译(二十)----Shader语法,表面着色器示例

Surface Shader Examples

Here are some examples of Surface Shaders. The examples below focus on using built-in lighting models; examples on how to implement custom lighting models are in Surface Shader Lighting Examples.

这里有一些关于Surface Shaders表面着色器的示例。下面的例子主要聚焦于如何使用内置的光照模式。关于如何实现自定义光照模式,请参见:Surface Shader Lighting Examples

Simple 例子

We'll start with a very simple shader and build up on that. Here's a shader that just sets surface color to "white". It uses built-in Lambert (diffuse) lighting model.

我们将着手建立1个非常简单的表面着色器。这个例子仅仅设置了表面颜色为白色。它使用了内置的朗伯(漫射)材质光照模式。

  Shader "Example/Diffuse Simple" {
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float4 color : COLOR;
      };
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = 1; //设置反射率为1
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

Here's how it looks like on a model with two lights set up:

它看起来像一个模型使用了2个光照。
点击浏览下一页

Texture 纹理

An all-white object is quite boring, so let's add a texture. We'll add a Properties block to the shader, so we get a texture selector in our Material. Other changes are in bold below.

全白的物体看上去很单调,所以我们给它添加一个纹理。我们在Shader中添加一个属性块,这样做我们就可以在材质中选择纹理。代码的另外一些改变用加粗的字体在下面显示。

  Shader "Example/Diffuse Texture" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }
点击浏览下一页

Normal mapping 法线映射

Let's add some normal mapping: 我们添加一些法线映射

  Shader "Example/Diffuse Bump" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
        float2 uv_MainTex;
        float2 uv_BumpMap;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        o.Normal = IMUnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }
点击浏览下一页

Rim Lighting 边缘光照

Now, try to add some Rim Lighting to highlight the edges of an object. We'll add some emissive light based on angle between surface normal and view direction. For that, we'll use viewDir built-in surface shader variable.

现在我们试图添加一些边缘光照使物体的边缘高亮。我们要在表面法线和视图方向的角度的基础上添加一些散射光。为此我们使用viewDir 内置表面着色器变量。

  Shader "Example/Rim" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
      _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
      _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;
          float3 viewDir;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      float4 _RimColor;
      float _RimPower;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
          half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
          o.Emission = _RimColor.rgb * pow (rim, _RimPower);
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }
点击浏览下一页

Detail Texture 细节纹理

For a different effect, let's add a detail texture that is combined with the base texture. Detail texture uses the same UVs, but usually different Tiling in the Material, so we have to use different input UV coordinates.

为了产生一个不同的效果,我们添加一个细节纹理,这个纹理将会和基础纹理结合在一起。细节纹理使用同样的UV,但是通常在材质上以不一样的贴图方式呈现,所以我们要使用不同的UV坐标进行输入。

  Shader "Example/Detail" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
      _Detail ("Detail", 2D) = "gray" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;
          float2 uv_Detail;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      sampler2D _Detail;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Albedo *= tex2D (_Detail, IN.uv_Detail).rgb * 2;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

Using a checker texture does not make much practical sense, but illustrates what happens:

使用检查纹理并没有多大实际意义,但说明发生了什么:

点击浏览下一页

Detail Texture in Screen Space 在屏幕空间中的细节纹理

How about a detail texture in screen space? It does not make much sense for a soldier head model, but illustrates how a built-in screenPos input might be used:

如何在屏幕空间中使用细节纹理? 它对这个模型的头部没有多大影响,但是它表明了内置的screenPos输入如何使用:

  Shader "Example/ScreenPos" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Detail ("Detail", 2D) = "gray" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float4 screenPos;
      };
      sampler2D _MainTex;
      sampler2D _Detail;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
          screenUV *= float2(8,6);
          o.Albedo *= tex2D (_Detail, screenUV).rgb * 2;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

I removed normal mapping from the shader above, just to make it shorter:

我为了使这个Shader更简短就删除了法线映射
点击浏览下一页

Cubemap Reflection 立方图反射

Here's a shader that does cubemapped reflection using built-in worldRefl input. It's actually very similar to built-in Reflective/Diffuse shader:

做立方图反射要在输入结构体中使用内置的worldRefl。它与内置的Reflective/Diffuse着色器十分像似。

  Shader "Example/WorldRefl" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Cube ("Cubemap", CUBE) = "" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float3 worldRefl;
      };
      sampler2D _MainTex;
      samplerCUBE _Cube;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
          o.Emission = texCUBE (_Cube, IN.worldRefl).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

And since it assigns the reflection color as Emission, we get a very shiny soldier:

因为它指派了反射光颜色为散射光颜色(自发光颜色),我们看到了1个很有光泽的士兵

点击浏览下一页

If you want to do reflections that are affected by normal maps, it needs to be slightly more involved:INTERNAL_DATA needs to be added to the Input structure, and WorldReflectionVector function used to compute per-pixel reflection vector after you've written the Normal output.

如果你想要受到法线贴图影响的反射效果,就需要一些更复杂的东西:这需要在输入结构体中加入一个复杂点的INTERNAL_DATA并且在你输出结构体写入法线之后,WorldReflectionVector 函数会计算每个像素反射向量。

 

  Shader "Example/WorldRefl Normalmap" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
      _Cube ("Cubemap", CUBE) = "" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;
          float3 worldRefl;
          INTERNAL_DATA
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      samplerCUBE _Cube;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
          o.Emission = texCUBE (_Cube, WorldReflectionVector (IN, o.Normal)).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

Here's a normal mapped shiny soldier:

这里是法线映射的光泽的士兵
点击浏览下一页

Slices via World Space Position 通过世界空间位置产生的切片

Here's a shader that "slices" the object by discarding pixels in nearly horizontal rings. It does that by usingclip() Cg/HLSL function based on world position of a pixel. We'll use worldPos built-in surface shader variable.

“切割”物体是基于抛弃一部分接近水平的环状带的像素。它使用 Cg/HLSL 函数中的clip()函数,这个函数是基于像素在世界空间中的位置。我们将使用内置的表面着色器变量worldPos 。

  Shader "Example/Slices" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      Cull Off
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;
          float3 worldPos;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      void surf (Input IN, inout SurfaceOutput o) {
          clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }
点击浏览下一页

Normal Extrusion with Vertex Modifier

顶点修改器和法线挤压

It is possible to use a "vertex modifier" function that will modify incoming vertex data in the vertex shader. This can be used for procedural animation, extrusion along normals and so on. Surface shader compilation directivevertex:functionName is used for that, with a function that takes inout appdata_full parameter.

使用"vertex modifier" 函数可以在顶点着色器中修改传入的顶点数据。这个可以被用来控制动画过程,沿法线挤压等等。表面着色器通过编译vertex:functionName指令来使用它,这个函数的参数是inout appdata_full

Here's a shader that moves vertices along their normals by the amount specified in the material:

顶点沿着法线移动一定的量,这个量在材质中被设置。

  Shader "Example/Normal Extrusion" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Amount ("Extrusion Amount", Range(-1,1)) = 0.5
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert vertex:vert
      struct Input {
          float2 uv_MainTex;
      };
      float _Amount;
      void vert (inout appdata_full v) {
          v.vertex.xyz += v.normal * _Amount;
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

Moving vertices along their normals makes a fat soldier:

沿着它们的法线移动顶点使士兵变胖。
点击浏览下一页

Custom data computed per-vertex 自定义数据计算每个顶点

Using a vertex modifier function it is also possible to compute custom data in a vertex shader, which then will be passed to the surface shader function per-pixel. The same compilation directive vertex:functionName is used, but the function should take two parameters: inout appdata_full and out Input. You can fill in any Input member that is not a built-in value there.

使用顶点修改函数可以在顶点着色器中计算自定义的数据,这些数据将被传递到表面着色器函数处理每个像素。使用同样的编译指令 vertex:functionName 来使用它,但是这个函数要有2个参数inout appdata_full 和 out Input。你可以填充任何输入成员,没有任何内置的值在其中。

Example below defines a custom float3 customColor member, which is computed in a vertex function:

下面的例子定义了1个自定义的float3 customColor 成员,这个将在顶点函数中被计算:

  Shader "Example/Custom Vertex Data" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert vertex:vert
      struct Input {
          float2 uv_MainTex;
          float3 customColor;
      };
      void vert (inout appdata_full v, out Input o) {
          o.customColor = abs(v.normal);
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Albedo *= IN.customColor;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

In this example customColor is set to the absolute value of the normal:

在这个例子中customColor设置的是法线的绝对值。

点击浏览下一页

More practical uses could be computing any per-vertex data that is not provided by built-in Input variables; or optimizing shader computations. For example, it's possible to compute Rim lighting at object's vertices, instead of doing that in the surface shader per-pixel.

这样做可以有更多的用途,比如说可以计算每个顶点的数据,部分数据内置的输入变量是不提供的。或者用来优化Shader的计算。可以根据物体顶点计算边缘光照,而不用在表面着色器上面逐像素计算它,这样效率会快很多。

Final Color Modifier 最终颜色修改器

It is possible to use a "final color modifier" function that will modify final color computed by the shader. Surface shader compilation directive finalcolor:functionName is used for that, with a function that takes Input IN, SurfaceOutput o, inout fixed4 color parameters.

final color modifier函数将修改Shader计算的最终颜色。表面着色器使用finalcolor:functionName 指令编译它,这个函数的参数有Input IN, SurfaceOutput o, inout fixed4 color 。

Here's a simple shader that applies tint to final color. This is different from just applying tint to surface Albedo color: this tint will also affect any color that came from lightmaps, light probes and similar extra sources.

下面是一个简单的着色,适用于色彩的最终颜色。这与色彩运用到表面反照率的颜色的方法不同:这个色调也会影响任何颜色的光照贴图,光探测器和类似的额外来源。

  Shader "Example/Tint Final Color" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _ColorTint ("Tint", Color) = (1.0, 0.6, 0.6, 1.0)
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert finalcolor:mycolor
      struct Input {
          float2 uv_MainTex;
      };
      fixed4 _ColorTint;
      void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
      {
          color *= _ColorTint;
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }
点击浏览下一页

Custom Fog with Final Color Modifier 与自定义雾一同使用的最终颜色修改器

Common use case for final color modifier (see above) would be implementing completely custom Fog. Fog needs to affect the final computed pixel shader color, which is exactly what the finalcolor modifier does.

通常使用的情况下最终颜色修改器(见上文)将实现完全自定义的雾。雾影响最终计算的像素着色器的颜色,这是finalcolor修正器做的事是一样的。

 

Here's a shader that applies fog tint based on distance from screen center. This combines both the vertex modifier with custom vertex data (fog) and final color modifier. When used in forward rendering additive pass, Fog needs to fade to black color, and this example handles that as well with a check for UNITY_PASS_FORWARDADD.

这是一个着色器适用于调整雾色调,这个调整是基于与屏幕中心的距离的。这里结合了自定义顶点数据(雾)的顶点修改器和最终颜色修改器。当在正向渲染的额外通道中,雾将淡入黑色,在这个例子中还要检测UNITY_PASS_FORWARDADD。

  Shader "Example/Fog via Final Color" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _FogColor ("Fog Color", Color) = (0.3, 0.4, 0.7, 1.0)
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert finalcolor:mycolor vertex:myvert
      struct Input {
          float2 uv_MainTex;
          half fog;
      };
      void myvert (inout appdata_full v, out Input data)
      {
          float4 hpos = mul (UNITY_MATRIX_MVP, v.vertex);
          data.fog = min (1, dot (hpos.xy, hpos.xy) * 0.1);
      }
      fixed4 _FogColor;
      void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
      {
          fixed3 fogColor = _FogColor.rgb;
          #ifdef UNITY_PASS_FORWARDADD
          fogColor = 0;
          #endif
          color.rgb = lerp (color.rgb, fogColor, IN.fog);
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }
点击浏览下一页
 
 
www.J2meGame.com原创,转载请说明。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值