第1篇 初始庐山真面目 - unity 3D Shader - Unity 3D ShaderLab开发实践
2 Unity中Shader的形态
2.1 shader基本结构
Shader "Examples/ShaderSyntax"
{
CustomEditor = "ExampleCustomEditor"
Properties
{
// Material property declarations go here
//[optional: attribute] name("display text in Inspector", type name) = default value
}
SubShader
{
// The code that defines the rest of the SubShader goes here
//<optional: LOD>
//<optional: tags>
//<optional: commands>
//<One or more Pass definitions>
Tags { "ExampleSubShaderTagKey" = "ExampleSubShaderTagValue" }
LOD 100
Pass
{
//<optional: name>
//<optional: tags>
//<optional: commands>
//<optional: shader code>
// The code that defines the Pass goes here
Name "ExamplePassName"
Tags { "ExamplePassTagKey" = "ExamplePassTagValue" }
// ShaderLab commands that apply to this Pass go here.
// HLSL code goes here.
}
Pass
{
// The next pass
}
}
Fallback "ExampleFallbackShader"
}
Shader包含:
- 关于自己的信息;
- 可选的fallback的shader对象;
- 一个或多个subshader
subshader,不同的subshader可以用来针对不同的GPU设置,不同的硬件,不同的渲染管线,和不同的运行时设置,一个subshader,为了获取想要的渲染效果定制的一个完整的渲染过程,包含:
- 基本信息,包括硬件,渲染管线,运行时信息;
- 关于subshader的key-value pair信息;
- 一个或多个passes;
passes,一个pass指的是一次操作得到一次绘制结果的过程,就好比执行了一次顶点着色器,片段着色器,并输出了一张绘制结果,SubShader下的Pass会按照从上往下的顺序依次渲染。pass中包含:
- 关于pass的key-value tag信息;
- shader programs前需要设定的render state;
- shader programs;
2.3 Unity中shader的2中形态
2.3.1 vertex+fragment shader
需要实现顶点和片段着色器,可以定制平台编译目标相关的参数。
2.3.2 Surface Shader
编写与光照交互的着色器很复杂。有不同的灯光类型,不同的阴影选项,不同的渲染路径 (前向和延迟渲染),着色器应该以某种方式处理所有这些复杂性。
SurfaceOutput的结果如下:
struct SurfaceOutput {
half3 Albedo; //颜色纹理
half3 Normal; //法线,tangent space空间
half3 Emission; //自发光,不受照明的影响
half Specular; //高光指数,0..1范围
half Gloss; //光泽度
half Alpha; //Alpha通道
};
此处需要注意的是SurfaceShader中,支持的自定的函数常见的有:
#pragma surface surfaceFunction lightModel vertex:vert finalcolor:colorFunc
surfaceFunction对应的是surface函数,lightModel对应的是光照模型的函数(内置的有Standard ,StandardSpecular ,Lambert,BlinnPhong ),vert是自定义的顶点函数,colorFunc是自定义的最终颜色修改函数。
具体实例可以参见:Unity - Manual: Surface Shader examples (unity3d.com)
参见:Unity Shader - Writing Surface Shaders 编写表面着色器_Jave.Lin 的学习笔记-CSDN博客
2.4 属性和uniform变量
// in property
_MyColor ("Some Color", Color) = (1,1,1,1)
_MyVector ("Some Vector", Vector) = (0,0,0,0)
_MyFloat ("My float", Float) = 0.5
_MyTexture ("Texture", 2D) = "white" {}
_MyCubemap ("Cubemap", CUBE) = "" {}
// in hlsl
fixed4 _MyColor; // low precision type is usually enough for colors
float4 _MyVector;
float _MyFloat;
sampler2D _MyTexture;
samplerCUBE _MyCubemap;
Properties支持的类型
Type | Example syntax | Comment |
---|---|---|
Integer | _ExampleName ("Integer display name", Integer) = 1 |
This type is backed by a real integer (unlike the legacy Int type described below, which is backed by a float). Use this instead of Int when you want to use an integer. |
Int (legacy) | _ExampleName ("Int display name", Int) = 1 |
Note: This legacy type is backed by a float, rather than an integer. It is supported for backwards compatibility reasons only. Use the Integer type instead. |
Float | _ExampleName ("Float display name", Float) = 0.5 _ExampleName ("Float with range", Range(0.0, 1.0)) = 0.5 |
The maximum and minimum values for the range slider are inclusive. |
Texture2D | _ExampleName ("Texture2D display name", 2D) = "" {} _ExampleName ("Texture2D display name", 2D) = "red" {} |
Put the following values in the default value string to use one of Unity’s built-in textures: “white” (RGBA: 1,1,1,1), “black” (RGBA: 0,0,0,1), “gray” (RGBA: 0.5,0.5,0.5,1), “bump” (RGBA: 0.5,0.5,1,0.5) or “red” (RGBA: 1,0,0,1). If you leave the string empty or enter an invalid value, it defaults to “gray”. Note: these default textures are not visible in the Inspector. |
Texture2DArray | _ExampleName ("Texture2DArray display name", 2DArray) = "" {} |
For more information, see Texture arrays. |
Texture3D | _ExampleName ("Texture3D", 3D) = "" {} |
The default value is a “gray” (RGBA: 0.5,0.5,0.5,1) texture. |
Cubemap | _ExampleName ("Cubemap", Cube) = "" {} |
The default value is a “gray” (RGBA: 0.5,0.5,0.5,1) texture. |
CubemapArray | _ExampleName ("CubemapArray", CubeArray) = "" {} |
See Cubemap arrays. |
Color | _ExampleName("Example color", Color) = (.25, .5, .5, 1) |
This maps to a float4 in your shader code. The Material Inspector displays a color picker. If you would rather edit the values as four individual floats, use the Vector type. |
Vector | _ExampleName ("Example vector", Vector) = (.25, .5, .5, 1) |
This maps to a float4 in your shader code. The Material Inspector displays four individual float fields. If you would rather edit the values using a color picker, use the Color type. |
通过脚本控制属性:
矩阵不能定义到Property中,只能够通过脚本的方式进行设值。
3 Shader中用到的各种空间的概念
用到的空间包括:模型空间、世界坐标空间、视空间(相机空间)、视锥体、裁剪空间。
世界空间到模型空间的变换矩阵:transform.worldToLocalMatrix, shader中是_World2Object;
模型空间到世界空间的变换矩阵:transform.localToWorldMatrix, shader中是_Object2World;
世界空间到相机空间的变换为:camera.worldToCameraMatrix,Shader中对应的是UNITY_MATRIX_MV
,可以把向量从模型空间变换到相机空间;
视锥体,如下:
裁剪空间,就是将视锥体变换成为一个长方体。
camera.projectionMatrix, shader中对应的是UNITY_MATRIX_MVP,直接把物体上的点投影到屏幕上。
4 基本光照模型
LightingLambert计算漫反射光,Editor/Data/CGIncludes/Lighting.cginc
乘上了atten * 2是为了更容易达到过曝;
BlinnPhong计算:
具体参见:games101 - 2 - Shading - grassofsky - 博客园 (cnblogs.com)
其他
Unity - Manual: Built-in shader helper functions (unity3d.com)