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. CSS入门级学习

    css入门学习1:认识CSS 1.1:css简介,css全称是层叠样式表,Cascading style sheets 1.2:css的作用,主要是用于定义html内容在浏览器内的显示样式,如文字大小 ...

  2. 如何管理和记录 SSIS 各个 Task 的开始执行时间和结束时间以及 Task 中添加|删除|修改的记录数

    开篇语 在这篇日志中 如何在 ETL 项目中统一管理上百个 SSIS 包的日志和包配置框架 我介绍到了包级别的日志管理框架,那么这个主要是针对包这一个层级的 Log 信息,包括包开始执行和结束时间,以 ...

  3. c++ const放置的位置

    标准中int const a 与 const int a 是完全等价的.正因为如此,会有很多各种不同的风格,同样的还有"*是跟类型还是变量?",比如char* p与 char *p ...

  4. 今天踩过的坑——structs和phpmyadmin

    phpmyadmin 错误:缺少 mcrypt 扩展解决mv -i /etc/php5/conf.d/mcrypt.ini /etc/php5/mods-available/sudo php5enmo ...

  5. iPhone开发视频教程 Objective-C部分 (51课时)

    第一.二章  OC基础语法 iPhone开发教程 第一章 OC基础语法  iPhone开发概述-必看(1.1)http://www.apkbus.com/android-102215-1-1.html ...

  6. [salesforce] standard button

    Use Case In Salesforce, when you click on the standard ‘New’ button on a Related List to create a ne ...

  7. SSD性能对比

    SSD性能测试顺序写 16k iops 85061.08顺序写 8k iops 146250.93顺序写 4k iops 239816.69顺序写 2k iops 294540.87顺序写 1k io ...

  8. 曲率已驱动了头发——深度分析谷歌AlphaGo击败职业棋手

    这篇是我们自开设星际随笔以来写得最长的一篇.我们也花了不少力气.包括把那5盘棋各打了两遍的谱,包括从Nature官网上把那篇谷歌的报告花了200元下载下来研究它的算法(后来发现谷 歌网站上可以免费下载 ...

  9. Jmeter调试工具---HTTP Mirror Server

    之前我介绍过Jmeter的一种调试工具Debug Sampler,它可以输出Jmeter的变量.属性甚至是系统属性而不用发送真实的请求到服务器.既然这样,那么HTTP Mirror Server又是做 ...

  10. 注入器和发布库--AngularJS学习笔记(三)

    AngularJS的一大特性就是Module的加载和依赖注入,本文将分析一下loader.js和最后这些代码文件是怎么组织和运行的. Loader.js 该文件中只有setupModuleLoader ...