您的位置:首页 > 移动开发 > Unity3D

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

2014-12-03 12:36 531 查看


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 using
clip()
 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 directive
vertex: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原创,转载请说明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐