这一章节学习的较慢,呜呜呜呜泪目,但感觉战线拉长不利于掌握,后期尽快提升进度。
2 初级篇
2.5 开始Unity的学习之旅
2.5.1 本书使用的软件和环境
本书基于mac编写的
2.5.2 最简单的顶点/片元着色器
-
顶点片元着色器的基本结构
Shader"MyShaderName"{ Properties{ //属性 } SubShader{ Pass{ CGPROGAM ...... ENDCG } } fALLBACK"VertexLit" }
最重要的是pass语义快
这里做一个实例
分析代码块:
我们没有在shader里面设置任何tages和rendersetup,在pass里面也没有设置,采取的是默认tages和rendersetup,
#pragma vertex vert #pragma fragment frag
告诉unity哪一个函数包括顶点着色器或者片元着色器的代码
float4 vert(float4 v :POSITION) : SV_POSITION{ return UnityObjectToClipPos(v); //float4 m1 = UNITY_MATRIX_MVP; //return mul (m1,v); }
如上是vert即是顶点着色器的代码,逐顶点执行,这一句的含义是指把顶点坐标从模型空间转换到裁剪空间,float4类型的变量,position语义是指告诉unity把模型的顶点坐标输入到v中,而sv_position语义是指告诉unity顶点着色器函数是输出裁剪空间中的顶点坐标。
fixed4 frag() : SV_Target{ return fixed4(1.0,1.0,1.0,1.0); }
这里输出一个fixed4类型的变量,sv_target语义是指告诉渲染器把用户的输出颜色存储入一个渲染目标中,这里默认存储在帧缓存中,(0,0,0,0)表示黑色,(1,1,1,1)表示白色
Shader "Custom/Chapter5-SimpleShader" { SubShader{ Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag float4 vert(float4 v :POSITION) : SV_POSITION{ return UnityObjectToClipPos(v); } fixed4 frag() : SV_Target{ return fixed4(1.0,1.0,1.0,1.0); } ENDCG } } }
-
模型数据从哪里来
我们需要知道更多模型的数据,上述例子我们通过position得知模型的顶点坐标,我们现在定义结构体来实现多属性的访问。
Shader "Custom/Chapter5-SimpleShader" { SubShader{ Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag //用一个结构体来定义顶点着色器的输入 struct a2v { //告诉unity用模型空间的顶点坐标填充vertex变量 float4 vertex : POSITION; //告诉unity用模型空间的法线方向填充normal变量 float3 normal : NORMAL; //告诉unity用模型的第一套纹理坐标填充texcoord变量 float4 texcoord : TEXCOORD0; }; float4 vert(a2v v) : SV_POSITION{ return UnityObjectToClipPos(v.vertex); } fixed4 frag() : SV_Target{ return fixed4(1.0,1.0,1.0,1.0); } ENDCG } } }
我们定义结构体,利用结构体来访问模型空间内的相关属性,对于顶点着色器的输入,unity支持的语义有:position,tangent,normal,texcood0,texcood1,texcood2,texcood3,color等。
结构体的通项公式
struct structname{ type name : semantic; type name : semantic; ...... }
语义是不可以缺少的
a2v是什么意思?
a是指application,是指应用,v是指vertex shader,这里是指把数据从应用阶段传入到顶点着色器当中,这些数据是从哪里来的捏,是由mesh render提供的,每一帧调用draw call时候,mesh render会把负责渲染的模型数据发送给unity shader。
-
顶点着色器和片元着色器的通信
在实际操作中,我们希望顶点着色器可以把模型的法线,纹理坐标传递给片元着色器,这就涉及到了顶点着色器和片元着色器之间的通信。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/Chapter5-SimpleShader" { SubShader{ Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag //用一个结构体来定义顶点着色器的输入 struct a2v { //POSITION告诉unity用模型空间的顶点坐标填充vertex变量 float4 vertex : POSITION; //NORMAL告诉unity用模型空间的法线方向填充normal变量 float3 normal : NORMAL; //TEXCOORD0告诉unity用模型的第一套纹理坐标填充texcoord变量 float4 texcoord : TEXCOORD0; }; //使用一个结构体来定义顶点着色器的输出 struct v2f { //SV_POSITION告诉unity在pos中包含顶点在裁剪空间中的信息 float4 pos : SV_POSITION; //COLOR0用于存储颜色信息 fixed3 color :COLOR0; }; v2f vert(a2v v) { //声明输出结构 v2f o; o.pos = UnityObjectToClipPos(v.vertex); // v.normal 包含了顶点的法线方向,其分量范围在[-1.0,1.0] //下面的代码把分量范围映射到[0.0,1.0] //存储到o.color中传递给片元着色器 o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5); return o; } fixed4 frag(v2f i) : SV_Target{ return fixed4(i.color,1.0); } ENDCG } } }
注意,这里我们通过定义v2f来定义从顶点着色器到片元着色器的转换过程,同时也需要定义结构体来满足变量的语义要求,片元和顶点的区别在于片元把顶点的数据进行了插值。
-
如何使用属性
在properties中定义属性,并在pass中同样定义同名称同类型的属性
2.5.3 强大的援手:unity提供的内置文件和变量
unityCG.cginc包含许多结构体以及函数方便我们调用
2.5.4 unity提供的CG/HLSL语义
-
什么是语义
语义简单理解为让shader知道从哪里读取数据,并把数据输出到哪里,unity并不包含所有的shader
系统数值语义,以SV开头,这种语义是不能随便赋值,不同平台对语义存在不同的兼容性,这一点需要我们注意。
-
unity支持的语义
-
应用阶段传递数据给顶点着色器
-
position:模型空间顶点的位置:float4
-
normal:顶点法线:float3
-
tangent:顶点切线:float4
-
texcoordn:顶点纹理坐标:float2/float4
-
color:顶点颜色fixed4/float4
-
-
顶点着色器到片元着色器传递数据
-
sv_position:裁剪空间的顶点坐标
-
color0:通常用于输出第一组顶点颜色
-
color1:常用于输出第二组顶点颜色
-
texcoordn:通常用于输出纹理坐标
一般来说我们使用texcoord来存储自定义的变量
-
-
片元着色器输出语义
sv_target:输出值将会存储到渲染目标中,类似于color
-
-
如何定义复杂的变量模型
2.5.5 Debug
unity shader的调试方法
-
使用假彩色图像
通过将假彩色图像映射到(0,1),区间然后和真彩色逐像素进行对比,来实现debug
-
利用visual studio
Graphics debugger
-
帧调试器
2.5.6 渲染平台的差异
-
渲染纹理坐标差异
一般来说unity帮助我们处理了反转情况,但是当我们打开抗锯齿的时候,并且需要同时渲染多张图像的时候,我们需要自己在顶点着色器主动开启翻转技术
#if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) uv.y = 1-uv.y; #endif
噪声纹理一般不需要进行反转处理
2.5.7 shader的整洁之道
float:32位
half:16位 -6000到6000
fixed:11位 -2.0到2.0
PC端上GPU处理后的精度很难看出区别,所以我们一般通过观察移动端来判断精度,fixed和half基本相同目前来说,尽可能使用精度较低的模型,这样有助于优化shader的性能,一般使用fixed来存储颜色和单位矢量
我们要避免不必要的计算
谨慎使用循环选择语句
-
分支判断语句中使用条件变量最好是常数,在shader运行当中不会发生变化
-
分支当中包含的操作指令数尽量减少
-
分支的嵌套尽可能减少
不要 除于零
2.6 Unity中的基础光照
-
像素的可见性
-
像素的光照计算
2.6.1 如何看到世界
-
光线是从光源发射出来
-
光线和物体相交,一些被吸收,一些被反射
-
摄像机吸收一些光,产生图像
-
光源
辐照度:垂直于光线方向的单位面积上单位时间穿过的能量来描述
利用光源方向和面的法线方向的角度余弦值来描述
-
吸收和散射
散射改变光线的方向不改变光线的其他属性:包括折射以及反射
-
着色
根据材质属性以及光源信息等,使用一个等式来计算出射度过程,即为光照模型
-
BRDF模型
2.6.2 标准光照模型
-
自发光:不使用全局光照技术,自发光将不会照亮周围物体
-
高光反射:phong模型,通过计算高光的反射方向,结合高光反射颜色等性质计算高光反射。blinn phong模型改善phong,不用计算反射角度,通过计算入射光线和视线之合的1/2,来取代更复杂就计算。blinn模型适合静态计算,phong模型适合动态计算
-
漫反射:符合兰伯特定律:反射光线的强度和表面法线与光源方向的夹角的cos正比
-
环境光:描述所有间接光照
片元着色器:逐像素计算
顶点着色器:逐顶点计算,在顶点计算光照,渲染图元内部插值,是非线性的会容易出现棱角现象,因为图元内部的颜色一般会暗于顶点颜色
菲涅尔反射无法用blinn phong来表示,其次blinn phong模型是各项同性
2.6.3 unity中的环境光和自发光
2.6.4 在unity shader中实现漫反射光照模型
四个变量
入射光线的颜色和强度,材质的漫反射系数,表面法线以及光源方向
Cg提供了函数来实现漫反射
函数:saturate(x) 饱和的意思
参数:x:用于操作的标量或者矢量
描述:把x截取在[0,1]范围,如果x是一个矢量,那么会对它的每一个分量进行这样的操作
-
实践:逐顶点光照
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' Shader "Custom/Chapter6-DiffuseOixelLevel" { Properties { _Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0) } SubShader { Pass{ Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag # include "Lighting.cginc" fixed4 _Diffuse; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOOD0; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); fixed3 color = ambient + diffuse; return fixed4(color, 1.0); } ENDCG } } FallBack "Diffuse" }
-
实践:逐像素光照
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/Chapter6-Diffuse VertexLevel" { Properties { _Diffuse("Diffuse",Color) = (1,1,1,1) } SubShader { Pass{ Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag # include "Lighting.cginc" fixed4 _Diffuse; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; fixed3 color : COLOR; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight)); o.color = ambient + diffuse; return o; } fixed4 frag(v2f i) : SV_Target{ return fixed4(i.color, 1.0); } ENDCG } } FallBack "Diffuse" }
半勃兰特模型
Shader "Custom/333" { Properties { _Diffuse("Diffuse",Color) = (1,1,1,1) } SubShader { Pass { Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" //定义和properties语义块中属性类型相匹配的变量 fixed4 _Diffuse; struct a2v { float4 vertex : POSITION; //定义变量,并通过语义告知unity将法线信息存储到normal变量中 float3 normal : NORMAL; }; struct v2f { //SV_POSITION语义告诉Unity,pos 里包含了顶点在裁剪空间中的位置信息 float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex);//把顶点位置从模型空间转到裁剪空间 o.worldNormal = UnityObjectToWorldNormal(v.normal);//法线转换到世界空间 return o; } fixed4 frag(v2f i) : SV_Target { fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//获得环境光 fixed3 worldNormal = normalize(i.worldNormal);//法线转换到世界空间 fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//获得光源方向 fixed halfLambert = dot(worldNormal, worldLight) * 0.5 + 0.5; //使用半兰伯特模型计算光照 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;//saturate防止点积为负 fixed3 color = ambient + diffuse; return fixed4(color,1.0); } ENDCG } } Fallback "Diffuse" }
2.6.5 在unity shader 中实现高光反射光照模型
四个要素
入射光线的颜色强度,材质的高光反射系数,视角方向以及反射方向
逐顶点光照
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Custom/1" { properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) _Specular("Specular",Color) = (1,1,1,1) _Gloss("Gloss",Range(8.0,256)) = 20 } subshader{ pass{ Tags {"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; fixed3 color : COLOR; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); 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(unity_ObjectToWorld, v.vertex).xyz); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); o.color = ambient + diffuse + specular; return o; } fixed4 frag(v2f i) : SV_Target{ return fixed4(i.color,1.0); } ENDCG } } Fallback"Specular" }
逐像素光照
// Upgrade NOTE: replaced 'Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced 'World2Object' with 'unity_WorldToObject'
Shader "Custom/2" { properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) _Specular("Specular",Color) = (1,1,1,1) _Gloss("Gloss",Range(8.0,256)) = 20 }
subshader{ pass { Tags {"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 : TEXCOOD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o;
} fixed4 frag(v2f i) : SV_Target{ fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = normalize(i.worldNormal); 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 - i.worldPos.xyz); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); return fixed4 (ambient + diffuse + specular,1.0) ; } ENDCG } } Fallback"Specular" }
blinn phong光照模型
2.6.6 使用Unity内置函数
内置函数:
float3 WorldSpaceViewDir(float4 v):输入模型空间中顶点的位置,返回世界空间该点到摄像机观察的方向
float3 UnityWorldSpaceViewDir(float4 v):输入世界空间顶点位置,返回世界空间该点到摄像机观察的方向
float3 ObjSpaceViewDir(float4 v):输入模型空间顶点位置,返回模型空间该点到摄像机观察的方向
float3 WorldSpaceLightDir(float4 v):仅可以用于前向渲染当中。输入模型空间顶点位置,返回世界空间该点到光源的方向(没有归一化)
float3 UnityWorldSpaceLightDir(float4 v):仅可以用于前向渲染当中。输入世界空间顶点位置,返回世界空间该点到光源的方向(没有归一化)
float3 ObjSpaceLightDir(float4 v):仅可以用于前向渲染当中。输入模型空间顶点位置,返回模型空间该点到光源的方向(没有归一化)
float3 UnityObjectToWorldNormal:(float3 norma):把法线方向从模型空间转换到世界空间当中
float3 UnityObjectToWorldDir:(float3 dir):把方向矢量从模型空间转换到世界空间当中
float3 UnityWorldToObjectDir:(float3 dir):把方向矢量从世界空间转换到模型空间当中
2.7 基础纹理
纹理的含义就是我们希望用一张图片来贴在物体表面,逐纹素控制模型的颜色
利用纹理展开技术来把纹理坐标存储在每一个点上,纹理映坐标定义了该顶点在纹理中对应的2
d坐标(u,v)通常把纹理坐标称其为UV坐标,通常我们都会归一化纹理映射坐标,但不归一化有时十分好用,后续章节会详细讨论
2.7.1 单张纹理
使用blinn phong模型来计算光照
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/Chapter7" { Properties { _Color("Color Tint",Color) = (1,1,1,1) _Specular("Specular",Color) = (1,1,1,1) _Gloss("Gloss",Range(8.0,256)) = 20 _MainTex("MainTex",2D) = "white"{} } SubShader { Pass{ Tags{"LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Specular; float4 _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 = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.uv = v.texcoord.xy *_MainTex_ST.xy +_MainTex_ST.zw; return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(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); } ENDCG } } Fallback "Specular" }
2.7.2 凹凸映射
使用纹理来修改模型表面的法线,让模型提供更多细节
-
高度纹理
模拟表面位移,得到修改后的法线值,也称作高度映射 高度图存储强度值,表示模型表面的海拔高度:颜色越浅,向外凸起,颜色越深,向里凹。但是计算复杂
-
法线纹理
直接存储表面法线,法线映射
2.7.3 渐变纹理
略(已经看完)
2.7.4 遮罩纹理
略(已经看完)
2.8 透明效果
Shader "Custom/Chapter8-AlphaBlend" { Properties { _Color ("Main Tint",Color)=(1,1,1,1) _MainTex("Main Tex",2D)="white"{} _AlphaScale("Alpha Scale",Range(0,1))=1 } SubShader { Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"} Pass { Tags{"LightMode" = "ForwardBase"} Cull Front Zwrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "LIghting.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; fixed _AlphaScale; 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 = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, 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); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal,worldLightDir)); return fixed4(ambient + diffuse,texColor.a*_AlphaScale); ; } ENDCG } Pass { Tags{"LightMode" = "ForwardBase"} Cull Back Zwrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "LIghting.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; fixed _AlphaScale; 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 = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, 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); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal,worldLightDir)); return fixed4(ambient + diffuse,texColor.a*_AlphaScale); ; } ENDCG } } Fallback"Transparent/Vertexlit" }