材质球
Specular Highlights:镜面光 Reflection: 遮罩反射 一个Cubemap 一个texture来描述我们对象的那些部分是可以反射的,而哪些不可以。记住,黑色表示没有任何反射性,而白色表示可以完全反射。下面的图片是我们将会用到的texture
代码语言:javascript复制Shader "Custom/MaskedReflection" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
_ReflAmount ("Reflection Amount", Range(0, 1)) = 1
_Cubemap ("Cubemap", CUBE) = ""{}
_ReflMask ("Reflection Mask", 2D) = ""{}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
sampler2D _ReflMask;
samplerCUBE _Cubemap;
float4 _MainTint;
float _ReflAmount;
struct Input {
float2 uv_MainTex;
float3 worldRefl;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
float3 reflection = texCUBE(_Cubemap, IN.worldRefl).rgb;
float4 reflMask = tex2D(_ReflMask, IN.uv_MainTex);
o.Albedo = c.rgb * _MainTint;
o.Emission = (reflection * reflMask.r) * _ReflAmount;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
代码语言:javascript复制Shader "Custom/AlphaMask" {
Properties
{
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
_MaskTex ("Mask (A)", 2D) = "white" {}
_Progress ("Progress", Range(0,1)) = 0.5
}
Category
{
Lighting Off
ZWrite Off
Cull back
Fog { Mode Off }
Tags {"Queue"="Transparent" "IgnoreProjector"="True"}
Blend SrcAlpha OneMinusSrcAlpha
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
sampler2D _MaskTex;
fixed4 _Color;
float _Progress;
struct appdata
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
return o;
}
half4 frag(v2f i) : COLOR
{
fixed4 c = _Color * tex2D(_MainTex, i.uv);
fixed ca = tex2D(_MaskTex, i.uv).a;
c.a *= ca >= _Progress ? 0f : 1f;
return c;
}
ENDCG
}
}
SubShader
{
AlphaTest LEqual [_Progress]
Pass
{
SetTexture [_MaskTex] {combine texture}
SetTexture [_MainTex] {combine texture, previous}
}
}
}
Fallback "Transparent/VertexLit"
}
Forward Rendering
Forward Rendering是绝大数引擎都含有的一种渲染方式。要使用Forward Rendering,一般在Vertex Shader或Fragment Shader阶段对每个顶点或每个像素进行光照计算,并且是对每个光源进行计算产生最终结果。正向渲染一个基于着色器的渲染路径。在Unity中它支持逐像素计算光照(包括法线贴图和灯光Cookies)和来自一个平行光的实时阴影。在默认设置中,少数最亮的灯光在逐像素计算光照模式下渲染。其余的灯光计算对象顶点的光照。 下面是Forward Rendering的核心伪代码。
代码语言:javascript复制For each light:
For each object affected by the light:
framebuffer = object * light
在Unity3D 引擎中,对于下图中的圆圈(表示一个Geometry),进行Forward Rendering处理。
将得到下面的处理结果
也就是说,对于ABCD四个光源我们在Fragment Shader中我们对每个pixel处理光照,对于DEFG光源我们在Vertex Shader中对每个vertex处理光照,而对于GH光源,我们采用球调和(SH)函数进行处理。 Forward Rendering优缺点
很明显,对于Forward Rendering,光源数量对计算复杂度影响巨大,所以比较适合户外这种光源较少的场景(一般只有太阳光)。
但是对于多光源,我们使用Forward Rendering的效率会极其低下。因为如果在vertex shader中计算光照,其复杂度将是 ,而如果在fragment shader中计算光照,其复杂度为 。可见光源数目和复杂度是成线性增长的。
对此,我们需要进行必要的优化。比如
- 1.多在vertex shader中进行光照处理,因为有一个几何体有10000个顶点,那么对于n个光源,至少要在vertex shader中计算10000n次。而对于在fragment shader中进行处理,这种消耗会更多,因为对于一个普通的1024x768屏幕,将近有8百万的像素要处理。所以如果顶点数小于像素个数的话,尽量在vertex shader中进行光照。
- 2.如果要在fragment shader中处理光照,我们大可不必对每个光源进行计算时,把所有像素都对该光源进行处理一次。因为每个光源都有其自己的作用区域。比如点光源的作用区域是一个球体,而平行光的作用区域就是整个空间了。对于不在此光照作用区域的像素就不进行处理。但是这样做的话,CPU端的负担将加重,因为要计算作用区域。
- 3.对于某个几何体,光源对其作用的程度是不同,所以有些作用程度特别小的光源可以不进行考虑。典型的例子就是Unity中只考虑重要程度最大的4个光源。
自发光
Global Illumination 全局光照设置
- 自发光效果 很多人都会奇怪,为什么我选了自发光的颜色,强度也调整的很大,为什么出不来效果呢,其实可能是少了一步操作。 首先我们需要先把这个自发光物体,选中LightMap静态,然后再把周围物体也都选中LightMap静态,再进行烘焙即可。很简单的,但遗了一步就会没有任何效果。
- 镜面 在模拟一个diffuse surface时,使用的是光滑,无光泽的object。这种方法,对于场景中的大部分objects都是合适的,而且很多光照模型都基于此种方法。但是,有时也要模拟闪光的模型表面,比如抛光的金属或者大理石地板的表面。Specular highlights就是用于模拟这些带有光泽的object表面。 有两种方法可以模拟镜面反射。第一种是Phong反射模型中的镜面反射部分,Phong模型以它的发明者,来自Utah大学的Bui Tuong Phong命名。与diffuse shading不同的是,镜面光与观察者(即camera)相对于表面的位置有关。只要看向一个发光的object,就自己观察到这一点,注意观察从不同的方向看向object时,该object的光泽如何改变。Phong模型指出,镜面光由观察方向和光的反射向量之间的夹角确定。公式为:
其中,R为反射向量,V表示观察方向,s表示亮点(照亮的区域)的大小。Specular exponent(镜面指数)越大,产生的亮点越小。反射向量可以使用如下的公式计算:
代码语言:javascript复制R = 2*(N • L)*N-L