Surface Shader:
  (1)必须放在SubShdader块,不能放在Pass内部;
  (2)#pragma sufrace surfaceFunction lightModel [optionalparams]
  (3)格式
  CG规定了声明为表面着色器的方法(就是我们这里的surf)的参数类型和名字,因此我们没有权利决定surf的输入输出参数的类型,只能按照规定写。这个规定就是第一个参数是一个Input结构,第二个参数是一个inout的SurfaceOutput结构。
  struct SurfaceOutput {
    half3 Albedo; //像素的颜色
    half3 Normal; //像素的法向值
    half3 Emission; //像素的发散颜色
    half Specular; //像素的镜面高光
    half Gloss; //像素的发光强度
    half Alpha; //像素的透明度
  };
  sampler2D就是GLSL中的2D贴图的类型,相应的,还有sampler1D,sampler3d,samplerCube等等格式。而具体地想知道像素与坐标的对应关系,以及获取这些数据,我们总不能一次一次去自己计算内存地址或者偏移,因此可以通过sampler2D来对贴图进 行操作。
  在CG程序中,我们有这样的约定,在一个贴图变量(在我们例子中是_MainTex)之前加上uv两个字母,就代表提取它的uv值(其实就是两个代表贴图上点的二维坐标 )。

  Input 这个输入结构通常拥有着色器需要的所有纹理坐标(texture coordinates)。纹理坐标(Texturecoordinates)必须被命名为“uv”后接纹理(texture)名字。(或者uv2开始,使用第二纹理坐标集)。
  可以在输入结构中根据自己的需要,可选附加这样的一些候选值:
  float3 viewDir - 视图方向( view direction)值。为了计算视差效果(Parallax effects),边缘光照(rim lighting)等,需要包含视图方向( view direction)值。
  float4 with COLOR semantic -每个顶点(per-vertex)颜色的插值。
  float4 screenPos - 屏幕空间中的位置。 为了反射效果,需要包含屏幕空间中的位置信息。比如在Dark Unity中所使用的 WetStreet着色器。
  float3 worldPos - 世界空间中的位置。
  float3 worldRefl - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。 请参考这个例子:Reflect-Diffuse 着色器。
  float3 worldNormal - 世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
  float3 worldRefl; INTERNAL_DATA - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector (IN, o.Normal))。
  float3 worldNormal; INTERNAL_DATA -世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的法线向量(normal vector)需要使用世界法线向量(WorldNormalVector (IN, o.Normal))。

vertex shader modifier:Surface Shader还可以单独指定一个vertex shader,用于做一些运算,vertex函数拥有固定的输入参数 inout appdata_full 。下面的例子通过vertex shader对顶点在发现方向上做了一些偏移:

    #pragma surface surf Lambert vertex:vert
void vert (inout appdata_full v)
{
v.vertex.xyz += v.normal * _Amount;
}

  也可在vertex shader中计算自定义变量(Input中的这些变量不能以uv开头,否则会出错),这个计算结果会逐像素的传递到surface shader, 如下: 

Shader "James/Surface/CustomData"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
#pragma surface surf Lambert vertex:vert sampler2D _MainTex; struct Input
{
float2 uv_MainTex;
float3 customColor; // 自定义数据
}; void vert(inout appdata_full, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input, o);
o.customColor = abs(v.normal); // 在vs中计算自定义数据
} 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 * IN.customColor;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
FallBack "Diffuse"
}

final color modifier: 编译指令为finalcolor:functionName,函数接收三个参数 Input IN, SurfaceOutput o, inout fixed4 color 
  final color会影响渲染的最终颜色,它在所有的计算的最后进行影响,比如lightmap、lightprobe等产生的颜色也会受此函数影响。
  final color可以用来实现fog,fog只影响渲染的rgb,而不影响alpha,fog的原理是让物体在最终的rgb和fog.color之间根据距离进行过度。

Shader "James/Surface Shader/Final Color Fog Liner" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
#pragma surface surf Lambert finalcolor:mycolor vertex:myvert sampler2D _MainTex;
uniform half4 unity_FogColor;
uniform half4 unity_FogStart;
uniform half4 unity_FogEnd; struct Input {
float2 uv_MainTex;
half fog;
};
// 顶点着色函数
void myvert (inout appdata_full v, out Input data) {
UNITY_INITIALIZE_OUTPUT(Input,data);
float pos = length(mul (UNITY_MATRIX_MV, v.vertex).xyz);
float diff = unity_FogEnd.x - unity_FogStart.x;
float invDiff = 1.0f / diff;
data.fog = clamp ((unity_FogEnd.x - pos) * invDiff, 0.0, 1.0);
}
// final color处理函数
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color) {
fixed3 fogColor = unity_FogColor.rgb;
#ifdef UNITY_PASS_FORWARDADD
fogColor = 0;
#endif
color.rgb = lerp (fogColor, color.rgb, IN.fog);
} void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

  uniform:用于指定变量的数据初始化方式。 Uniform inputs,表示一些与三维渲染有关的离散信息数据,这些数据通常由应用程序传入,并通常不会随着图元信息的变化而变化,如材质对光的反射信息、运动矩阵等。Uniform 修辞一个参数,表示该参数的值由外部应用程序初始化并传入。
  使用Uniform 修辞的变量,除了数据来源不同外,与其他变量是完全一样的。需要注意的一点是:uniform 修辞的变量的值是从外部传入的,所以在Cg 程序(顶点程序和片段程序)中通常使用uniform 参数修辞函数形参,不容许声明一个用uniform 修辞的局部变量!

Lighting model:光照模式,在编写surface shader时,我们只需要描述各种属性即可,真正的光照计算是Lighting mode负责的。
  内置光照模式:Lambert(diffuse lighting)、BlinnPhong(specular lighting),源码在unity install path}/Data/CGIncludes/Lighting.cginc目录。
  Lighting model其实就是按照指定规范编写的一堆cg/hlsl,我们也可以定义自己的Lighting model。

  自定义光照模式:
  Surface Shader Lighting Models其实就是一些函数,这些函数我们也可以自己来写。
  下面的例子就是一个自定义的Lambert光照模式,并在此基础上实现的Toon效果:

Shader "James/Surface Shader/Diffuse" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_RampTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD CGPROGRAM
#pragma surface surf SimpleLambert sampler2D _RampTex; half4 LightingSimpleLambert(SurfaceOutput s, half3 lightDir, half atten)
{
half NdotL = dot(s.Normal, lightDir);
// [-1, 1] --> [0, 1]
half diff = NdotL *0.5 + 0.5;
half3 ramp = tex2D(_RampTex, float2(diff, 0.5)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * );
// c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
c.a = s.Alpha;
return c;
} sampler2D _MainTex; struct Input {
float2 uv_MainTex;
}; void surf (Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D (_MainTex, IN.uv_MainTex);
}
ENDCG
}
FallBack "Diffuse"
}

  下面的代码表示了一个简单的BlinnPhong的模式:

Shader "James/Surface Shader/SimpleBlinnPhong" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD CGPROGRAM
#pragma surface surf SimpleSpecular half4 LightingSimpleSpecular(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
half3 h = normalize(lightDir + viewDir);
half diff = max(, dot(s.Normal, lightDir)); float nh = max(, dot(s.Normal, h));
float spec = pow(nh, 48.0); half4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * );
c.a = s.Alpha;
return c;
} sampler2D _MainTex; struct Input {
float2 uv_MainTex;
}; void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

  再下面是关于lightmap的光照模式代码,并在光照贴图的基础是添加了一个自定义颜色的实现:

Shader "James/Surface Shader/SimpleLightmap" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_SelfColor("SceneCooor", Color) = (0.5, , , )
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM #pragma surface surf Standard half4 _SelfColor; half4 LightingStandard (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * );
c.a = s.Alpha;
return c;
} // 给lightmap乘一个自定义颜色
inline half3 ColorLight (half3 i) {
return _SelfColor.rgb * i;
} inline fixed4 LightingStandard_SingleLightmap (SurfaceOutput s, fixed4 color) {
half3 lm = ColorLight(DecodeLightmap (color));
return fixed4(lm, );
} inline fixed4 LightingStandard_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) {
half3 lm = ColorLight(lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade));
return fixed4(lm, );
} inline fixed4 LightingStandard_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) {
UNITY_DIRBASIS half3 lm = ColorLight(DecodeLightmap (color));
half3 scalePerBasisVector = DecodeLightmap (scale); if (surfFuncWritesNormal)
{
half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal));
lm *= dot (normalInRnmBasis, scalePerBasisVector);
} return fixed4(lm, );
} 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"
}

还有一些相关的编译选项:

  #pragma debug  查看生成的代码
  #pragma only_renderers: d3d9 只支持特定平台
  noforwardadd
  nolightmap
  exclude_path:prepass 不支持deferred模式

Surface Shader的更多相关文章

  1. Surface Shader简单向导

    Surface Shader 表面着色器 描述 当你的Material要处理光照,则一般使用Surface Shader.Surface Shader隐藏了光照的计算,你只需要在surf函数里设置好反 ...

  2. Unity Shader——Writing Surface Shaders(3)——Surface Shader Lighting Examples

    Surface Shader 光照例子 这里有一些自定义光照模型和Surface Shaders的例子.通常的Surface Shader例子在这里. 由于延迟光照在某些自定义的逐材质光照模型中表现得 ...

  3. Unity Shader——Writing Surface Shaders(1)——Surface Shader Examples

    这里有Surface Shader的一些例子.下面的这些例子关注使用内建的光照模型:关于如何使用自定义光照模型的例子参见Surface Shader Lighting Examples. 简单 我们将 ...

  4. 【Unity Shaders】初探Surface Shader背后的机制

    转载请注明出处:http://blog.csdn.net/candycat1992/article/details/39994049 写在前面 一直以来,Unity Surface Shader背后的 ...

  5. unity, surface shader access world position and localposition

    一,surface shader中访问worldposition 在surface shader中访问世界坐标,只需在Input结构体中声明float3 worldPos即可,如下:  struct  ...

  6. 【Unity Shaders】Shader学习资源和Surface Shader概述

    写在前面 写这篇文章的时候,我断断续续学习Unity Shader半年了,其实还是个门外汉.我也能体会很多童鞋那种想要学好Shader却无从下手的感觉.在这个期间,我找到一些学习Shader的教程以及 ...

  7. 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  8. Vertex Modifier of Surface Shader

    [Vertex Modifier of Surface Shader] Surface shader compilation directive vertex:functionName  可以用于指定 ...

  9. unity, unlit surface shader (texColor only surface shader)

    要实现双面透明无光照只有纹理色的surface shader. 错误的写法:(导致带有曝光) Shader "Custom/doubleFaceTranspTexColor" { ...

随机推荐

  1. Javascript实现计数器,定时警告和停止

    <html> <head> <meta charset="utf-8"> <title>定时警告</title> < ...

  2. java封装性

    原先是class Person{ public string name; public  int age } public void main{ Person person=new person(); ...

  3. C++与C#的时间转换

    1.C++中的时间:(1) time_t其实是一个64位的long int类型(2) time函数:函数简介: 函数名:  time     头文件:  time.h     函数原型:time_t ...

  4. Cocos2d中使用颜色混合:加算,减算

    转自http://blog.sina.com.cn/s/blog_7a2ffd5c0100xtid.html CCSprite有一个ccBlendFunc类型的blendFunc_结构体成员,可以用来 ...

  5. Scala 深入浅出实战经典 第81讲:Scala中List的构造是的类型约束逆变、协变、下界详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-97讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. 表单验证Jquery扩展方法类

    /** 表单数据验证 **/ $.fn.Validform = function () { var Validatemsg = ""; var Validateflag = tru ...

  7. dubbo通信协议之对比

    对dubbo的协议的学习,可以知道目前主流RPC通信大概是什么情况,本文参考dubbo官方文档 http://dubbo.io/User+Guide-zh.htm dubbo共支持如下几种通信协议: ...

  8. 关于在mac 配置eclipse c开发

    新建一个c 项目,如下 勾选hello world ANSL project ,勾选右边的MacOSX GCC 安装插件CDT - http://download.eclipse.org/tools/ ...

  9. [iOS Xcode8]上传AppStore 无法构建版本 没有➕号

    最近iOS10出来了 Xcode也跟着升级到了8 想着App做个更新 于是修改好了代码打算上传新包 ,无奈总是发现构建不了新版本 经过各种蛋疼的查找.我列一下我的经验 1.如果是收费的App,那么是要 ...

  10. C#3.0新特性之扩展方法介绍

    C#3.0扩展方法是给现有类型添加一个方法.现在类型即可是基本数据类型(如int,String等),也可以是自己定义的类.以下是引用片段: //Demo--1 //扩展基本类型 namespace T ...