不积跬步无以至千里


  • Home

  • Tags

  • Archives

unity-shader-rendering-path

Posted on 2019-03-15

unity的光源

Posted on 2019-03-15
光源类型
  • 平行光
  • 点光源
  • 聚光灯 spot light 可以用于表示由一个特定位置出发、向特定方向延伸的光,锥形区域的半径由面板的Range属性决定,而锥形体的张开角度由spot angle属性决定
  • 面光灯 area light
光源属性
  • 位置 position
  • 方向 direction
  • 强度 instensity
  • 颜色 color
  • 衰减 attenuation 到某点的衰减,与该点到光源的距离有关
shader实现
1
2
3
4
5
6
7
8
9
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma multi_compile_fwbase
#pragma vertex vert
#pragma fragment frag
//保证在shader中使用光照衰减等光照变量可以被正确赋值
ENDCG
}
notes

如果场景中有多个平行光,那么unity会选择最亮的平行光传递给BasePass进行逐像素处理,其他平行光会按照逐顶点或在Additional Pass中按照逐像素的方式处理,如果场景中没有平行光,那么base pass会当成全黑的光源处理。basepass处理的逐像素光源类型一定是平行光。可以使用_WorldLightPos0来得到这个平行光的方向,可以使用 _LightColor0来得到它的颜色和强度,衰减值为1

hexo 操作笔记

Posted on 2019-03-15 | In Hexo , tech

参考资料

官方文档
troubleshooting
ask

目录

  • 1.基本用法
    • 1.1标题
    • 1.2变粗
    • 1.3斜体
    • 1.4中间划线
    • 1.5下划线
    • 1.6分割线
    • 1.7重点符号
    • 1.8加个框
    • 1.9加个x框
    • 1.10插入表格
  • 2.插入html
    • 2.1 html插入图片
    • 2.2 html并排插入图片
  • 3.插入link和图片
  • 4.插入流程图
  • 5.插入公式
  • 6.引用
  • 7.data files
  • 8.插入表格

1.1 标题 # ## ###


### 基本用法

1.2 变粗


1
利用** 这里是变粗的内容**


变粗

1.3 斜体


斜体

>

1.4 中间划线 ~~ ~~

中间划线

1.5 下划线不知道怎么搞


下划线 不知道怎么搞 ++我很好++
++22222++
==这个是区域==
==是多少==

1.6分割线


1.7 重点符号 -

  • 重点符号
  • 一条一条的

1.8 加个框框

  • 重点符号
  • 重点啊
  • 重点符号

1.9 加个x框框 - [x]

  • 未完成符号

1.10 插入表格

时间 地点 人物
1 2 3
4 5 6

2.1 插入html






Alt text
Alt text

2.2 并排插入












—

3.插入link 和 图片


插入链接
1
2
3
4
5
6
7
8
9
10
插入链接
[link](https://note.youdao.com/)
插入图片
![点击跳转](/images/cloudy.png "hexo 网站")
直接跳转
<a href="/Main"> 你在哪里</a>
代码插入图片
<a href="www.baidu.com">
<img src="/images/cloudy.png">
</a>


link
插入图片
点击跳转





### 直接跳转
你在哪里

4 插入流程图


1
npm install --save hexo-filter-flowchart


5 插入公式

6 引用

1
2
3
4
5
6
插入引用
{% youtube hY7M5jjJ9mM %}

{% blockquote %}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit lacus ut purus iaculis feugiat. Sed nec tempor elit, quis aliquam neque. Curabitur sed diam eget dolor fermentum semper at eu lorem.
{% endblockquote %}

adsfadsfasdfasdf

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit lacus ut purus iaculis feugiat. Sed nec tempor elit, quis aliquam neque. Curabitur sed diam eget dolor fermentum semper at eu lorem.

quote from an article on the web

Every interaction is both precious and an opportunity to delight.

Seth GodinWelcome to Island Marketing

7 data files

<% for (var link in site.data.menu) { %>
<%= link %>
<% } %>

unity shader 透明效果

Posted on 2019-02-25

实时渲染要实现透明效果,需要在渲染模型时控制它的透明通道,alpha channel
通常使用两种方法来实现透明效果:

透明度测试 alpha test

只要一个片元的透明度不满足条件(通常是小于某个阈值),那么它对应的片元就会被舍弃,被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响,否则就按普通不透明物体的处理方式处理

1
2
3
4
5
void clip(float4 x)
{
if(any ( x < 0))
discard;
}
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
Shader "My/AlphaTest"{
Properties{
_Color("Main Tint", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = "white" ()
_CutOff("Alpha CutOff", Range(0, 1)) = 0.5
}
SubShader{
Tags{"queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutOut"}
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"

fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _CutOff;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};

struct v2f{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(_Object2World, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}

fixed4 frag(v2f i) : SV_Target{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
clip(texColor.a - _Cutoff);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
return fixed4(ambient + diffuse, 1.0);
}

ENDCG
}
}
Fallback "VertexLit"
}
透明度混合alpha blending
深度缓冲 z-buffer
渲染队列 render queue
双面渲染原理

把双面渲染工作分成两个Pass:第一个pass只渲染背面,第二个pass只渲染正面,由于Unity会顺序执行Subshader中的各个Pass,因此我们可以保证背面总是在正面被渲染之前渲染,从而保证正确的深度渲染关系。

总结
  • 一共有两种方式可以实现,一个是控制透明度测试alphaTest 小于某个值就舍弃,简单粗暴,开启深度写入。
  • 透明度混合,可以有两个通道第一个把背面的渲染出来,第二个把正面渲染出来 然后颜色混合,需要关闭深度写入

unity 遮罩纹理

Posted on 2019-02-25
遮罩纹理

通过采样得到纹理的纹理像素值,然后使用其中某个或者某几个通道的值来与某种表面属性进行相乘,这样当该通道的值为0时,可以保护表面不受该属性的影响。

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
69
70
71
Shader "My/Mask"{
properties{
_Color("Color", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = "white"{}
_BumpMap("Normal Map", 2D) = "bump" {}
_BumpScale("Bump Scale", Float) = 1.0
_Specular("Specular", Color) = (1,1,1,1)
_SpecularScale("Specular Scale", Float) = 1.0
_SpecularMask("Specular Mask", 2D) = "white" {}
_Gloss("Gloss", Range(8.0, 256)) = 20
}

SubShader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
sampler2D _SpecularMask;
float _SpecularScale;
fixed4 _Specular;
float _Gloss;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0;
};

struct v2f{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
TANGENT_SPACE_ROTATION;
o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
return o;
}

fixed4 frag(v2f i) : SV_Target{
fixed3 tangentLightDir = normalize(i.lightDir);
fixed3 tangentViewDir = normalize(i.viewDir);
fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uv));
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
fixed specularMask = tex2D(_SpecularMask, i.uv).r * _SpecularScale;
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)) ,_Gloss) * specularMask;
return fixed4(ambient + diffuse + specular, 1.0);
}

ENDCG
}
}
}

unity 渐变纹理

Posted on 2019-02-25

纹理可以存储任何表面属性,一种常见的办法就是使用渐变纹理来控制漫反射光照的颜色。

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
Shader "My/RampTexture"{
Properties{
_Color("Color Tint", Color) = (1,1,1,1)
_RampTex("Ramp Tex", 2D) = "white" {}
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8, 256)) = 20
}

SubShader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _RampTex;
float4 _RampTex_ST;
fixed4 _Specular;
float _Gloss;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};

struct v2f{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(_Object2World, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _RampTex);
return o;
}

fixed4 frag(v2f i) : SV_Target{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 halfLambert = 0.5* dot(worldNormal, worldLightDir) + 0.5;
fixed3 diffuseColor = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb; //使用半兰伯特模型来构建一个纹理坐标,并用这个坐标对渐变纹理采样
fixed3 diffuse = _LightColor0.rgb * diffuseColor;
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)) ,_Gloss);
}

return fixed4(ambient + diffuse + specular, 1.0);

ENDCG
}
}
Fallback "Specular"
}

unity 凹凸映射

Posted on 2019-02-25
凹凸映射

凹凸映射的目的是使用一张纹理来修改模型表面的法线,让模型看起来凹凸不平。

高度纹理

存储的是强度值,它用于表示模型表面局部的海拔高度,颜色越浅表明该位置的表面越向外凸起,颜色越深表明该位置越向里凹,可以很直观的从高度图里明确的知道一个模型表面的凹凸情况。缺点是计算更加复杂,在实时计算中不能直接得到表面法线,而需要由像素的灰度值计算而得,需要消耗很多性能。

#####法线纹理

存储的是表面的法线方向,由于法线方向的分量范围在[-1, 1],而像素的分布范围是[0,1]因此需要做一个映射,pixel=(normal + 1)/2 反映射的过程就是norma=pixel x 2 - 1

模型空间的法线纹理

修改后的模型空间中的表面法线存储在一张纹理中,按照模型自带的坐标空间,模型空间
由于每个点存储的法线方向是各异的,所以看起来是五颜六色的。
优点:

  • 实现简单,更加直观
  • 在纹理坐标的缝合处和尖锐的边角部分,可见的缝隙较少,可以提供平滑的边界
切线空间的法线纹理

对于模型的每一个顶点,它都有一个属于自己的切线空间,这个切线空间的原点就是该顶点本身,z轴是顶点的法线方向(n), x轴是顶点的切线方向(t),y轴可由法线和切线叉乘得到,也被称为副切线b。
切线空间下的法线纹理看起来几乎都是浅蓝色的,纹理其实是存储了各自的切线空间中的法线扰动方向。如果一个点的法线方向不变,那么在它的切线空间中,新的法线方向就是z轴方向(0,0,1)经过映射后存储在纹理中RGB(0.5,0.5,1)为浅蓝色。所以切线空间下的法线纹理看起来是一大片浅蓝色的

优点:

  • 自由度高。可以用在别的网格中。
  • 可以进行UV动画。可以移动一个纹理的UV坐标来实现一个凹凸移动的效果
  • 可以重用法线纹理。比如一个砖块可以用一张法线纹理就可以用到所有的6个面上
  • 可压缩。z总是法线方向,因此可以只存储xy方向的值。

#####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
69
70
71
72
73
74
Shader "My/bump"{
Properties{
_Color("Color", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = "white"{}
_BumpMap("Normal Map", 2D) = "bump" {}
_BumpScale("Bump Scale", Float) = 1.0
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8.0, 256)) = 20
}

SubShader{
Pass{
Tag { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
fixed4 _Specular;
float _Gloss;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tagent : TANGENT; //xyzw w来确定第三个坐标轴的副切线方向性
float4 texcoord : TEXCOORD0;
};
struct v2f{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//转换到切线空间
TANGENT_SPACE_ROTATION;
o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
return o;
}

fixed4 frag(v2f i) : SV_Target{
fixed3 tangentLightDir = normalize(i.lightDir);
fixed3 tagentViewDir = normalize(i.viewDir);

fixed4 packedNormal = tex2D(_BumpMap, i.uv.zw); //得到的是压缩过的法线
fixed3 tangentNormal;
tangentNormal = UnpackNormal(packedNormal); //得到正确的法线
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}

ENDCG
}

}
FallBack "diffuse"
}

世界空间下计算光照模型;需要在片元着色器中把法线方向从切线空间变换到世界空间下。
在顶点着色器计算从切线空间到世界空间的变换矩阵,并把它传递给片元着色器。变换矩阵的计算可以由顶点的切线、副切线和法线在世界空间下的表示来得到,最后在片元着色器中把法线纹理中的法线方向从切线空间变换到世界空间。

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
69
70
71
72
73
74
75
76
77
78
79
80
81
Shader "My/NormalMapWorldSpace"{
Properties{
_Color("Color", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = "white"{}
_BumpMap("Normal Map", 2D) = "bump" {}
_BumpScale("Bump Scale", Float) = 1.0
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8.0, 256)) = 20
}

SubShader{
Pass{
Tag { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
fixed4 _Specular;
float _Gloss;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tagent : TANGENT; //xyzw w来确定第三个坐标轴的副切线方向性
float4 texcoord : TEXCOORD0;
};
struct v2f{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 TtoW0 : TEXCOORD1;
float4 TtoW1 : TEXCOORD2;
float4 TtoW2 : TEXCOORD3;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex); //剪裁空间
o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
float3 worldPos = mul(_Object2World, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
fixed3 worldTangent = UnityObjectToWolrdDir(v.tangent.xyz);
fixed3 worldBinormal = cross(worldNormal, worldTagent) * v.tangent.w;

o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
return o;
}

fixed4 frag(v2f i) : SV_Target{
//得到顶点的世界坐标
float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

//得到切线空间的法线
fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
bump.xy *= _BumpScale;
bump.z = sqrt(1 - saturate(dot(bump.xy, bump.xy)));
bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(bump, lightDir));
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}

ENDCG
}

}
FallBack "diffuse"
}

unity-shader-texture

Posted on 2019-02-22
纹理采样

纹理名_ST,其中ST是缩放scale和平移translation的缩写。
_MainTex_ST可以让我们得到该纹理的缩放和平移(偏移)值。
_MainTex_ST.xy存储的是缩放值, _MainTex_ST.zw存储的是偏移值。
在unity中可以在材质面板中调节纹理的平铺tiling(缩放)和偏移offset{平移}
TRANSFORM_TEX将会根据纹理计算变换后的纹理坐标
tex2D函数进行纹理采样

#####纹理的属性

属性调整面板设置纹理类型 wrap mode repeat和clamp

滤波模式FilterMode

支持三种模式Point Bilinear Trilinear得到的图片滤波效果依次提升,性能消耗越大,会影响
放大或缩小时得到的图片质量。比如把64x64纹理贴在512x512大小平面时,需要放大纹理。

  1. Point模式使用最近邻滤波nearest neighbor,在放大或者缩小时,它的采样像素数目通常只有一个
  2. Bilinear滤波使用了线性滤波,对于每个目标像素,它会找到四个邻近像素,然后进行线性插值混合后得到最终像素,因此图像看起来模糊了
  3. Trilinear
放大纹理
缩小纹理
多级渐远纹理mipmapping

在一个很小空间里有很多东西。是提前用滤波处理得到很多更小的图像,随着远离摄像机,使用较小的纹理。这样可以通过增加空间提高性能。如果在导入纹理时设置了这个GenerateMipMaps,将会生成多级渐远纹理。

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
//普通纹理采样
Shader "shader/texture"{
Properties{
_MainTex("MainTex", 2D) = "white"{}
_Color("MainColor", Color) = (1,1,1,1)
_Specular("Specular", Color) =(1,1,1,1)
_Gloss("Gloss", Range(8,256)) = 20
}
SubShader{
Pass{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"

fixed4 _Color;
sampler2D _MainTex;
fixed4 _Specular;
float _Gloss;
float4 _MainTex_ST;

struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float4 uv : TEXCOORD2;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(_Object2World, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}

float4 frag(v2f i) : SV_Target
{
//归一化
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldLightDir(i.worldPos));
//
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}

CGEND
}
FallBack "Specular"
}
}

光 光照模型 漫反射

Posted on 2019-02-21

[TOC]

光

  1. 方向 l表示方式
  2. 辐射度 irradiance, 垂直于l的单位面积上单位时间内穿过的能量就是辐射度
  3. 颜色
吸收absorption

不改变 方向
改变 光的密度和颜色

散射scattering

改变光的方向
不改变光的颜色和密度

  1. 折射 refraction(透射transmission) 通过漫反射diffuse来模拟,有多少光线被折射、吸收、和散射出表面
  2. 反射 reflection 通过高光反射来反应模拟specular
出射度

辐射度和出射度之间满足一定线性关系,这个比值就是材质的漫反射和高光反射属性

标准光照模型

通常光有以下四部分组成

  1. 自发光emissive $c_{emissive}$ 直接用了该材质的颜色 $c_{missive}=m_{emissive}$
  2. 高光反射specular $c_{specular}​$
  3. 漫反射diffuse $c_{diffuse}$ 是那些被物体表面随机散射到各个方向的辐射度,各个位置都有完全随机,用兰伯特定律来模拟:反射光线的强度和表面法线和光源方向之间的夹角的余弦值成正比$c_{diffuse}=(c_{light}·m_{diffuse})max(0,n·I)$ n为表面法线,I是指向光源的单位矢量,m_diffuse漫反射颜色,c_light光源颜色
  4. 环境光ambient $c_{ambient}$ 近似模拟间接光照 $c_{ambient}=g_{ambient}$ 内置变量UNITY_LIGHTMODEL_AMBIENT可以得到环境光的颜色和强度信息
Phong模型泊松模型
  1. 表面法线 n

  2. 入射角 I

  3. 反射角 r

  4. 视角方向 v

这是模型基础,只要知道一个就可以求得其他a·b=|a||b|cosa

r+I=2n(n·I) 所以r=2n(n·I)-I

泊松模型 :

$C_{specular} = C_{light}m_{specular}max(0, v·r)^{m_{gloss}}​$

其中m_gloss为光泽度也被成为反光度,用于控制高光区域的亮点,m_gloss越大,亮点越小
m_specular是材质的高光反射颜色用于控制该材质对于高光反射的强度和颜色
c_light是光源的颜色和强度

Blinn模型

思路是避免求反射角引入 视角和入射角相加再归一化h=(v+I)/|v+i|,然后使用n和h的夹角来计算高光
$C_{specular} = C_{light}m_{specular}max(0, v·h)^{m_{gloss}}$

半兰伯特模型

适用于漫反射光照模型,在平面某点漫反射光的光强与该反射点的法向量和入射光角度的余弦值成正比,这样在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化,是去了模型细节表现,为了改善这种情况,加了两个参数
cdiffuse = clight mdiffuse (a(ni) + b), 当a和b都等于0.5时候就是半兰伯特光照模型

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
Shader "My/specular-pixel_level"
{
Properties {
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8,256)) = 20
}

SubShader{
Pass{
Tag{"LightMode"="ForwardBase"}

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "Lighting.cginc"

fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;

struct a2v{
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};

v2f vert(a2v v){
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.worldNormal = mul(v.normal, _World2Object);
o.worldPos = mul(_Object2World, v.vertex).xyz;
return o;
}

fixed4 frag(v2f i) : SV_Target{

fixed3 ambient = UNITY_LIGHTMODE_AMBIENT.xyz;

//计算法线
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)_World2Object));
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//计算漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
//计算高光反射
fixed3 reflectDir = normalize(reflect(-WorldLightDir, worldNormal));
//得到观察视角
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(_Object2World, v.vertex).xyz);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
o.color = ambient + diffuse + specular;


return fixed4(i.color, 1.0);
}

ENDCG
}
}
Fallback "specular"
}

unity-shader-variables

Posted on 2019-02-20

Unity 内置的变换矩阵

变量名 描述
UNITY_MATRIX_MVP 当前的模型观察投影矩阵,用于将顶点/矢量从模型空间变换到剪裁空间
UNITY_MATRIX_MV 当前的模型观察投影矩阵,用于将顶点/矢量从模型空间变换观察空间
UNITY_MATRIX_V 当前的观察矩阵,用于将顶点矢量从世界空间变换到观察空间
UNITY_MATRIX_P 当前的投影矩阵,用于将顶点矢量从观察空间变换到投影空间
UNITY_MATRIX_VP 当前的观察投影矩阵用于将顶点矢量从世界空间转换到剪裁空间
UNITY_MATRIX_T_MV UNITY_MATRIX_MV的转置矩阵
UNITY_MATRIX_IT_MV UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可以用于得到UNITY_MATRIX_MV的逆矩阵
_Object2World 当前的模型矩阵,用于将顶点方向矢量从模型空间变换到世界空间
_World2Object _Object2World的逆矩阵,用于将顶点方向矢量从世界空间变换到模型空间

​ unity内置的摄像机和屏幕参数

变量名 类型 描述
_WorldSpaceCameraPos float3 摄像机在世界空间中的
unity_CameraProjection float4x4 摄像机的投影矩阵
unity_CameraInvProjection float4x4 摄像机的投影矩阵的逆矩阵
… … …

Unity提供的CG/HLSL语义

语义

语义是CG/HLSL提供的语义semantics,实际上是赋值给shader的一些字符串,这些字符串表达了这个参数的含义,通过这种标记,让shader知道从哪里读取数据,并把数据输出到哪里

系统数值语义 system-value

例如用SV_POSITION语义去修饰顶点着色器的输出变量pos,那边就表示pos包含了可用于光栅化的变换后的顶点坐标(即齐次剪裁空间中的坐标),用这些语义修饰的变量是不可以随便赋值的,因为流水线需要他们来完成特定的目的,例如渲染引擎会把用SV_POSITION修饰的变量经过光栅化后显示在屏幕上。

#####unity支持的语义

从应用阶段传递模型数据给顶点着色器时unity支持的语义

语义 描述
POSITION 模型空间的顶点位置,通常是float4类型,
NORMAL 顶点法线,通常是float3类型
TANGENT 顶点切线,通常是float4类型
TEXCOORDn 顶点的纹理坐标,0表示第一组纹理,通常是float2或者float4类型
COLOR 顶点颜色,通常是fixed4或float4类型

从顶点着色器传递数据给片元着色器时的语义

语义 描述
SV_POSITION 裁剪空间中的顶点坐标,结构体中必须包含一个用该语义修饰的变量。等同于dx9中的POSITION
COLOR0 通常用于输出第一组顶点颜色,但不是必需的
COLOR1 通常用于输出第二组顶点颜色,但不是必需的
TEXCOORD0~TEXCOORD7 通常用于输出纹理坐标,但不是必需的

从片元着色器输出时支持的语义

语义 描述
SV_Target 输出值将会存储在渲染目标rendertarget中,等同于dx9的color语义,

定义复杂的变量类型

1
2
3
4
5
6
7
struct v2f{
float4 pos : SV_POSITION; //float最高精度浮点值,通常用32位来存储,
fixed3 color0 : COLOR0; //fixed最低精度浮点值,通常用11位来存储,范围是-2.0~2.0
fixed4 color1 : COLOR1;
half value0 : TEXCOORD0; //half中等精度的浮点值,通常用16位来存储,范围是-60000~60000
float2 value1 : TEXTCOORD1;
}

一个语义可以用的寄存器只能处理4个浮点值(float),如float3X4需要使用更多的空间,可以拆分为多个变量,每个变量存储了矩阵中的一行数据。

123

Jiaq

21 posts
4 categories
16 tags
© 2019 Jiaq
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4