
Lec5
做一下三ambient。直接莽就行~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| Shader "ZhuangDong/Lec5/TripleAmbient" { Properties { } SubShader { Pass { CGPROGRAM
#pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc"
struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; };
v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); return o; }
fixed4 frag(v2f i) : SV_TARGET { float3 worldNorm = normalize(i.worldNormal); fixed3 colorUp = unity_AmbientSky; fixed3 colorPara = unity_AmbientEquator; fixed3 colorDown = unity_AmbientGround; fixed3 upNorm = max(worldNorm.y, 0); fixed3 downNorm = max(-worldNorm.y, 0); fixed3 paraNorm = 1 - upNorm - downNorm; fixed3 color = colorUp * upNorm + colorPara * paraNorm + colorDown * downNorm; return fixed4(color, 0); }
ENDCG }
} FallBack "Diffuse" }
|
Lec6
一、散乱分布高光
遇到了一些奇奇怪怪的问题,基本思路就是xjb采样噪声纹理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| Shader "ZhuangDong/Lec6/MultipleGrapes" { Properties { _DiffuseColor ("Diffuse Color", Color) = (1,1,1,1) _NoiseTex ("Noise Texture", 2D) = "white" {} _SpecMaxRange ("Specular Range Max", Range (1, 200)) = 20 _AmbientStength ("Ambient Strength", Float) = .1 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 worldNorm : TEXCOORD1; float3 worldPos : TEXCOORD2; };
sampler2D _NoiseTex; float4 _NoiseTex_ST; float _AmbientStength; fixed4 _DiffuseColor; float _SpecMaxRange;
v2f vert (appdata_base v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _NoiseTex); o.worldNorm = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; }
fixed4 frag (v2f i) : SV_Target { float3 worldNorm = normalize(i.worldNorm); fixed3 colorUp = unity_AmbientSky; fixed3 colorPara = unity_AmbientEquator; fixed3 colorDown = unity_AmbientGround; fixed3 upNorm = max(worldNorm.y, 0); fixed3 downNorm = max(-worldNorm.y, 0); fixed3 paraNorm = 1 - upNorm - downNorm; fixed3 ambient = colorUp * upNorm + colorPara * paraNorm + colorDown * downNorm; ambient = ambient * _AmbientStength; float3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 texRGB = tex2D(_NoiseTex, i.uv); float3 diffuse = max(dot(worldNorm, lightDir), 0) * _DiffuseColor * texRGB; float3 halfDir = normalize(lightDir + viewDir); float specAmount = tex2D(_NoiseTex, viewDir.xz).r * _SpecMaxRange; float3 specular = pow(max(dot(halfDir, worldNorm), 0), specAmount); fixed3 col = saturate(ambient + diffuse + specular); return fixed4(col, 1.0); } ENDCG } } }
|
二、铁锈
基本思想就是根据噪声采样。先得到采样结果:
1
| fixed3 texRGB = tex2D(_NoiseTex, i.uv);
|
然后根据某个范围_RustRange
对texRGB的R通道进行step
1
| fixed texRC = step(_RustRange, texRGB.r);
|
再进行lerp
1
| diffuse *= lerp(ironColor, _RustColor, texRC);
|
就做完了。完整的shader:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| Shader "ZhuangDong/Lec6/IronRust" { Properties { _IronColor ("Diffuse Color", Color) = (1,1,1,1) _RustColor ("Rust Color", Color) = (1,1,1,1) _NoiseTex ("Noise Texture", 2D) = "white" {} _SpecMaxRange ("Specular Range Max", Range (1, 200)) = 20 _RustRange ("Rust Range", Range(0,1)) = .4 _FresnelPow ("Fresenel Power", Float) = 3.0 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc" struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 worldNorm : TEXCOORD1; float3 worldPos : TEXCOORD2; };
sampler2D _NoiseTex; float4 _NoiseTex_ST; fixed4 _IronColor; fixed4 _RustColor; float _SpecMaxRange; float _RustRange; float _FresnelPow;
v2f vert (appdata_base v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _NoiseTex); o.worldNorm = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; }
fixed4 frag (v2f i) : SV_Target { float3 worldNorm = normalize(i.worldNorm); float3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 texRGB = tex2D(_NoiseTex, i.uv); float3 diffuse = dot(worldNorm, lightDir) * .5 + .5; fixed texRC = step(_RustRange, texRGB.r); float3 halfDir = normalize(lightDir + viewDir); float specAmount = tex2D(_NoiseTex, viewDir.xz).r * _SpecMaxRange; float3 specular = pow(max(dot(halfDir, worldNorm), 0), specAmount); float3 ironColor = _IronColor + specular; diffuse *= lerp(ironColor, _RustColor, texRC); fixed3 col = saturate(diffuse); fixed fresnel = pow(1-dot(viewDir, worldNorm), _FresnelPow); col = lerp(col, fixed3(1.0,1.0,1.0), fresnel); return fixed4(col, 1.0); } ENDCG } } }
|
三、Shader Forge的叠加
对其讨论,我们都取颜色是$A, B$
(1)变暗系
Darken:取每个分量的较小值
$$
C=\min(A,B)
$$
1
| saturate(min(float4(Color1),float4(Color2))).rgb
|
Multiply:不用说,直接乘起来,雅名正片叠底
$$
C=AB
$$
1
| saturate((_Color1.rgb*_Color2.rgb))
|
Colorburn:颜色加深
$$
C = A - \frac{\overline{A}\cdot \overline{B}}{B} = 1-\frac{1-A}{B}
$$
效果上是颜色距离$.5$越大的点,偏离就越远,此时可能产生大量溢出。
1
| saturate((1.0-((1.0-_Color2.rgb)/_Color1.rgb)))
|
Linearburn:线性加深
$$
C=A+B-1
$$
1
| saturate((_Color1.rgb+_Color2.rgb-1.0))
|
(2)变亮系
Lighten:变亮
$$
C=\max(A,B)
$$
1
| saturate(max(_Color1.rgb,_Color2.rgb))
|
Screen:滤色
$$
C=1-(1-A)(1-B)
$$
绿色的作用是,原来比较暗的部分会变量。这个比较常用,我们举个例子,假设B是$(.5,.5,.5)$,那么$C=1-0.5(1-A)=0.5+0.5A$,也就是把$A$的范围扩张到了$(0.5,1)$。因此,滤色常用于增加亮度。
其实从另一个层面来说,Screen和Multiply正好是对偶的。
1
| saturate((1.0-(1.0-_Color1.rgb)*(1.0-_Color2.rgb)))
|
Color Dodge:颜色减淡
$$
C = \frac{1-A}{B}
$$
1
| saturate((_Color2.rgb/(1.0-_Color1.rgb)))
|
按照颜色1的三个通道,颜色2的通道都一定程度上的变大。一个极端是Color1为白色,那么Color2发生严重的溢出。结果和Color Burn互补。
Linear Dodge:就是Add,线性减淡
$$
C=A+B
$$
1
| saturate((_Color1.rgb+_Color2.rgb))
|
(3)综合系
Overlay:叠加
$$
C=\begin{cases}2AB&B\le0.5\1-(1-2(B-.5)(1-A))&B>0.5\end{cases}
$$
把两种东西综合,比较亮的部分让它更亮,比较暗的地方让它更暗。但是这里起决定作用的是B,所以黑白的区分比较明显。
1
| saturate(( _Color2.rgb > 0.5 ? (1.0-(1.0-2.0*(_Color2.rgb-0.5))*(1.0-_Color1.rgb)) : (2.0*_Color2.rgb*_Color1.rgb) ))
|
Hard Light:强光
$$
C=\begin{cases}2AB&B\le0.5\1-(1-2(A-.5)(1-B))&B>0.5\end{cases}
$$
其中$x$是B的$x$值。把两种东西综合,比较亮的部分让它更亮,比较暗的地方让它更暗。但这里起决定作用的是A,所以整体效果是变亮。相当于A这束强光打到了B上,发生一系列作用。
1
| saturate(( _Color2.rgb > 0.5 ? (1.0-(1.0-2.0*(_Color1.rgb-0.5))*(1.0-_Color2.rgb)) : (2.0*_Color2.rgb*_Color1.rgb) ))
|
Vivid Light:亮光
$$
C=\begin{cases}\dfrac{B}{2(1-A)}&B>0.5\1-\dfrac{1-B}{2A}&B\le 0.5\end{cases}
$$
会让饱和度很大幅度的增大.可以看成颜色加深和颜色减淡的组合。
1
| saturate(( _Color1.rgb > 0.5 ? (_Color2.rgb/((1.0-_Color1.rgb)*2.0)) : (1.0-(((1.0-_Color2.rgb)*0.5)/_Color1.rgb))));
|
Linear Light:线性光
$$
C=2A+B-1
$$
它原本是对$A$大小进行讨论的。当$x>0.5$,它会增加亮度;否则会减小亮度。但二者公式是统一的,因为$2A-1$的正负恰好以$A$为分水岭。可以看成线性加深和线性减淡的组合。
1
| saturate(( _Color1.rgb > 0.5 ? (_Color2.rgb + 2.0*_Color1.rgb -1.0) : (_Color2.rgb + 2.0*(_Color1.rgb-0.5))))
|
Pin Light:点光
$$
C=\begin{cases}\max(2A-1,B)&A>0.5\\min(2A, B)& A\le 0.5\end{cases}
$$
效果上,仍然是中间部分被替换了。感觉没什么用。
1
| saturate(( _Color2.rgb > 0.5 ? max(_Color1.rgb,2.0*(_Color2.rgb-0.5)) : min(_Color1.rgb,2.0*_Color2.rgb) ));
|
Hard Mix:实色混合
$$
C=\left[\dfrac{A+B}{2}\right]
$$
其中$[x]$表示$\operatorname{Round}(x)$。会将相加结果变得非常硬。
1
| saturate(round( 0.5*(_Color2.rgb + _Color1.rgb)))
|
(4)差系
Difference:差值
$$
C=|A-B|
$$
用来找差异,一般写shader妹人会把它当成混合模式。
1
| saturate(abs(_Color2.rgb-_Color1.rgb))
|
Exclusion:排除
$$
C=\frac{1-(2A-1)(2B-1)}{2}
$$
没差值模式那么激进,效果比较类似。
1
| saturate((0.5 - 2.0*(_Color2.rgb-0.5)*(_Color1.rgb-0.5)))
|
Substract:相减
$$
C=A-B
$$
…相煎何太急
1
| saturate((_Color2.rgb-_Color1.rgb))
|
Divide:相除
$$
C=\frac{A}{B}
$$
1
| saturate((_Color2.rgb/_Color1.rgb))
|
用基色进行划分。如果$A\ge B$,会划分出白色,否则让颜色变暗。