Unity_TA美术向(庄懂)课程学习笔记


视频教程请看B站UP: 庄懂-BoyanTata

📚主旨

美术向TA基础能力培养,使大家可以用技术手段去表达美术诉求。

📚主要内容

📍.Unity 引擎基础;
📍.ShaderForge连连看;
📍.ShaderLab图形编程;
📍.渲染相关的C#脚本;

📚学习路径

根据某一个🍱技术专题进行🍳技术演示,我们再通过学习模仿🍛完成老师布置的作业。

📚HalfLambert卡通着色

在这里插入图片描述

💡实现思路

📍.先实现Lambert(兰伯特)光照模型:法线与光反方向的点乘即夹角cos值(-1~1)

float hLambert = dot(lDirWS,nDirWS) * 0.5 +0.5;

在这里插入图片描述
在这里插入图片描述
📍.然后把兰伯特转换(Lambert)成半兰伯特(HalfLambert):(-1~1) =>(0~1)
在这里插入图片描述

在这里插入图片描述
📍.最后用半兰伯特组装成一个uv坐标采样贴图就大功告成啦🍭

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

💡连连看

在这里插入图片描述

🍖.加个屏幕坐标UV点阵

💡效果

在这里插入图片描述

💡连连看

在这里插入图片描述

📚最最最简的shader

Shader "ZYF/Homework/Helloworld"
{
    Properties
    {
    }
    SubShader
    {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            struct VertexInput {
                float4 vertex : POSITION;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
            };

            VertexOutput vert (VertexInput v)
            {
                VertexOutput o = (VertexOutput)0;
                o.pos = UnityObjectToClipPos( v.vertex );
                return o;
            }

            fixed4 frag (VertexOutput i) : COLOR
            {
               
                return fixed4(1,0,0,1);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

📚 Shader技巧

💡面板参数声明格式

类型格式
数值_Name(“标签名”,Float) = 0
范围_Name(“标签名”,range(0,1)) = 0
位置、向量_Name(“标签名”,Vector) = (0,0,0,0)
颜色_Name(“标签名”,Color) = (1.0,1.0,1.0,1.0)
2D纹理_Name(“标签名”,2D) = “White”{}
3D纹理_Name(“标签名”,3D) = “White”{}
2D纹理_Name(“标签名”,Cube) = “_Skybox”{}

💡 参数属性

属性用途范围示例
[HideInInspector]在面板上隐藏该参数任何参数[HideInInspector] _FakeLightDir(“假光方向”,Vector)=(0,0,0,0)
[NoScaleOffset]禁用纹理的TilingOffset面板;不需要做TilingOffset的纹理,比如大部分角色纹理,防止美术误设置纹理参数[NoScaleOffset] _MainTex(“主贴图”,2D)=“White”{}
Normal标记该纹理参数为法线贴图,以激活自检测功能2D纹理参数[Normal] _NormalTex(“法线贴图”,2D)=“bump”{}
[HDR]用于设置高动态范围颜色值,如:灯光颜色、自发光颜色等颜色参数[HDR] _EmitCol(“自发光颜色”,Color) =(1.0,1.0,1.0,1.0,1.0)
[Gamma]用于颜色参数的色彩空间的转换;一般用于色彩空间为Linear的项目颜色参数[Gamma] _EmitCol(“自发光颜色”,Color) = (1.0,1.0,1.0,1.0)
[PowerSlider(2)]对范围参数做Power处理后再传入Shader;纠正部分参数调节手感;范围参数[PowerSlider(2)] _SpecPow(“高光次幂”,Range(1.90))=30
Header(xxx标签)]标签,用于排版单独使用[Header(Texture)]
Space(10)]空行,用于排版单独使用[Space(10)]
其它:[Toggle]、[Enum]、[Keyword]

💡 参数类型

💡 原则上优先使用精度最低的数据类型。
💡 世界空间位置和UV坐标:float
💡 向量、HDR颜色使用half;视情况升到float
💡 LDR颜色、简单乘子可使用fixed

不同平台对数据类型的支持情况不同,一般会自动转换,极少数情况下自动转换会带来问题。
部分平台上数据类型精度转换消耗也不小,fixed也要慎用。

类型位数范围精度
fixed11–2.0~2.01/256
half16-60000~600003位小数
float32-3.4e38~3.4e386,7位小数
Int32较少使用_
bool布尔型较少使用__
矩阵:float2x2,float3x3,float4x4___
sampler2D2D纹理__
sampler3D3D纹理__
samplerCUBECube纹理__

💡 可访问的顶点Input数据

标签含义类型
POSITION顶点位置float3 、float4
TEXCOORD0UV通道1float2、float3、float4
TEXCOORD1UV通道2float2、float3、float4
TEXCOORD2UV通道3float2、float3、float4
TEXCOORD3UV通道4float2、float3、float4
NORMAL法线方向float3
TANGENT切线方向float4
COLOR顶点色float4

💡常用的顶点Output数据

标签含义类型
pos顶点位置CS (ClipSpace)float4
uv0一般纹理UVfloat2
uv1LightmapUVfloat2
posWS顶点位置WS(WorldSpace)float3
nDirWS法线方向WShalf3
tDirWS切线方向WShalf3
bDirWS副切线方向WShalf3
color顶点色fixed4

📚 光照组成

光照
光源
环境光
漫反射:Lambert
镜面反射:Phong
遮挡:投影
漫反射:3ColAmbient
遮挡:AO贴图
结果
镜面反射:Fresnel+Matcap+Cubemap

🥠向量准备

📚法线(nDir)

🔄转世界空间法线

struct VertexInput {
	float3 normal :NORMAL;//模型顶点法线
};
struct VertexOutput {
	float3 worldSpaceNormal : TEXCOORD0;
};
VertexOutput vert (VertexInput v)
{
	VertexOutput o = (VertexOutput)0;
	o.normalDir = UnityObjectToWorldNormal(v.normal);//转世界空间法线
	return o;
}

🎞法线贴图采样TBN

💡 利用构造的矩阵TBN(模型)变换法线贴图法线(切线空间世界空间)。
💡 利用模型自带的法线和切线叉乘计算副切线(注意方向为:v.tangent.w * unity_WorldTransformParams.w)。
💡 v.tangent:值为-1或者1,由DCC软件中的切线自动生成,和顶点的环绕顺序有关。
💡 unity_WorldTransformParams.w:定义于unityShaderVariables.cginc中.模型的Scale值是三维向量,即xyz,当这三个值中有奇数个值为负时(1个或者3个值全为负时),unity_WorldTransformParams.w = -1,否则为1.

    Properties
    {
        _NormalMap("法线贴图",2D) ="bump"{}
    }
	uniform sampler2D _NormalMap;

    struct VertexInput {
         float4 vertex : POSITION;
         float2 texcoord :TEXCOORD0;
         float3 normal:NORMAL;
         float4 tangent :TANGENT;
     };
     struct VertexOutput {
          float4 pos : SV_POSITION;
          float2 uv :TEXCOORD0;
          float3 nDirWS :TEXCOORD1;
          float3 bDirWS :TEXCOORD2;
          float3 tDirWS:TEXCOORD3;
       };
     //采样法线贴图
	float3 NormalMapSamplerWS(float3 tDirWS,float3 bDirWS,float3 nDirWS,sampler2D normalMap,float2 uv) {
	      float3 nDirTS = UnpackNormal(tex2D(normalMap,uv));
          float3x3 tbn = float3x3(tDirWS,bDirWS,nDirWS);
          float3 normalWS = normalize(mul(nDirTS,tbn));
          return normalWS;
    }
    VertexOutput vert (VertexInput v)
    {
           VertexOutput o = (VertexOutput)0;
           o.pos = UnityObjectToClipPos( v.vertex );
           o.uv = v.texcoord;

           o.nDirWS = UnityObjectToWorldNormal(v.normal);
           o.tDirWS = UnityObjectToWorldDir(v.tangent.xyz);
           //副切线方向。v.tangent:值为-1或者1,由DCC软件中的切线自动生成,和顶点的环绕顺序有关。
           //unity_WorldTransformParams.w:定义于unityShaderVariables.cginc中.模型的Scale值是三维向量,
           //即xyz,当这三个值中有奇数个值为负时(1个或者3个值全为负时),unity_WorldTransformParams.w = -1,否则为1.
            fixed sign = v.tangent.w * unity_WorldTransformParams.w;
            o.bDirWS =normalize(cross(o.nDirWS,o.tDirWS)*sign);
            return o;
     }
     fixed4 frag (VertexOutput i) : COLOR
     {
          	float3 nDirWS = NormalMapSamplerWS(i.tDirWS,i.bDirWS,i.nDirWS, _NormalMap,i.uv);
			...
      }

📚光方向 (lDir)

📍._WorldSpaceLightPos0.w:用来区分平行光🌞和点光 💡
📍._WorldSpaceLightPos0.xyz:方向(平行光)or 位置(点光)

🚧注意啦 ~光方向是指向光的方向而不是从光源出发的方向👇
光方向

📚视线方向 (vDir)

🚧注意啦 ~视线方向是指向摄像机的方向而不是从摄像机出发的方向👇
在这里插入图片描述

struct VertexInput {
	float4 vertex : POSITION;
	...
};
struct VertexOutput {
	float4 posCS : SV_POSITION;
	float3 posWS : TEXCOORD0;
	...
};

VertexOutput vert(VertexInput v)
{
    VertexOutput o = (VertexOutput)0;
    o.posCS = UnityObjectToClipPos(v.vertex);
    o.posWS = mul(unity_ObjectToWorld,v.vertex);
    ...
    return o;
}

fixed4 frag(VertexOutput i) : COLOR
{
     float3 vDir = normalize(_WorldSpaceCameraPos.xyz-i.posWS.xyz);
     ...
}

📚顶点世界坐标 (posWS)

struct VertexInput {
   float4 vertex : POSITION;
};
struct VertexOutput {
   float4 pos : SV_POSITION;
   float3 posWS : TEXCOORD0;
};
VertexOutput vert(VertexInput v)
{
   VertexOutput o = (VertexOutput)0;
   o.pos = UnityObjectToClipPos(v.vertex);
   o.posWS = mul(unity_ObjectToWorld,v.vertex);
   return o;
}

📚光反射方向 (lrDir)

struct VertexInput {
	float4 vertex : POSITION;
	float3 normal : NORMAL;
	...
};
struct VertexOutput {
	float4 posCS : SV_POSITION;
	float3 nDirWS :TEXCOORD0;
	...
};

VertexOutput vert(VertexInput v)
{
    VertexOutput o = (VertexOutput)0;
    o.posCS = UnityObjectToClipPos(v.vertex);
    o.nDirWS = UnityObjectToWorldNormal(v.normal);
    ...
    return o;
}

fixed4 frag(VertexOutput i) : COLOR
{
     float3 lDir = _WorldSpaceLightPos0.xyz;
     float3 lrDir =normalize(reflect(lDir *-1,i.nDirWS));
     ...
}

📚半角方向 (hDir)

在这里插入图片描述
😱两个向量一加就是半角方向

struct VertexInput {
   float4 vertex : POSITION;
   float3 normal : NORMAL;
};
struct VertexOutput {
   float4 posCS : SV_POSITION;
   float3 posWS : TEXCOORD0;
};

VertexOutput vert(VertexInput v)
{
   VertexOutput o = (VertexOutput)0;
   o.posCS = UnityObjectToClipPos(v.vertex);
   o.posWS = mul(unity_ObjectToWorld,v.vertex);
   return o;
}

fixed4 frag(VertexOutput i) : COLOR
{
    float3 lDir = _WorldSpaceLightPos0.xyz;
    float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
    float3 hDir = normalize(lDir + vDir);
    ...
}

📚 贴图使用TilingOffset

📍. 在对应的贴图的下面声明一个相同名字+“_ST”的变量:如 uniform float4 _MainTex_ST。
📍.纹理采样时使用 TRANSFORM_TEX(uv0,_MainTex)

📚贴图采样

Properties
{
	_Tex("图图",2D) ="white"{}
}
Pass{
	...
	uniform sampler2D _Tex;
	uniform float4 _Tex_ST;
	struct VertexInput {
		float4 vertex : POSITION;
		float2 texcoord :TEXCOORD0;
	};
	
	struct VertexOutput {
         float4 pos : SV_POSITION;
         float2 uv :TEXCOORD0;
    };
    
	VertexOutput vert(VertexInput v)
	{
		VertexOutput o = (VertexOutput)0;
		o.pos = UnityObjectToClipPos(v.vertex);
		o.uv = v.texcoord;
		return o;
	}

	fixed4 frag (VertexOutput i) : COLOR
	{
		float2 uv = float2(0.5,0.5)
		float4 color = tex2D(_Tex,TRANSFORM_TEX(uv,_Tex));//采样贴图颜色
		return color;
     }
}

📚 漫反射与高光混合

🍤半兰伯特混合基础色(乘法),🥧高光完全反射颜色所以用加法

float3 finalCol = _MainCol * hlambert + blinnPhongPower;

🥗 光源

💡hLambert(漫反射)


fixed4 frag (VertexOutput i) : COLOR
{
	float lDirWS = _WorldSpaceLightPos0.xyz;
	float hLambert = dot(lDirWS,nDirWS) * 0.5 +0.5;
	...
}

💡Phong(高光)

fixed4 frag (VertexOutput i) : COLOR
{
     float3 lDirWS = _WorldSpaceLightPos0.xyz;
     float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
     float3 vrDirWS =normalize(reflect(-vDirWS,nDirWS));
     float phongPow = 20;
	 float phong = pow(max(0,dot(vrDirWS, lDirWS)),phongPow);
}

📚 光照投影

在这里插入图片描述

💡 LIGHTING_COORDS(1,2):这里的参数是需要根据当前已使用的TEXCOORD0来计算的,如果当前最大的已经使用了TEXCOORD2那么参数应该是LIGHTING_COORDS(3,4)
💡 FallBack "Diffuse":在光照投影时FallBack调用一个叫ShadowCaster的pass(也可以自己写这个pass)。

#include "AutoLight.cginc" //光照投影必备库
#include "Lighting.cginc"//光照投影必备库
struct VertexOutput {
	float4 pos : SV_POSITION;
	float3 posWS : TEXCOORD0;
	LIGHTING_COORDS(1,2)
};

VertexOutput vert(VertexInput v)
{
	VertexOutput o = (VertexOutput)0;
	o.pos = UnityObjectToClipPos(v.vertex);
	TRANSFER_VERTEX_TO_FRAGMENT(o)
	return o;
}

fixed4 frag(VertexOutput i) : COLOR
{
	float attenuation = LIGHT_ATTENUATION(i);
	...
}
ENDCG
}
}
FallBack "Diffuse"

📚 环境光

💡 漫反射:3ColAmbient(3向环境光)

💡 因为环境光方向不确定,为了简化我们把环境光分为三个不同方向:上、下、侧面
在这里插入图片描述

Properties
{
    _AmbientCol_Top("环境光_Top",Color) = (1.0,1.0,1.0,1.0)
    _AmbientCol_Bottom("环境光_Bottom",Color) = (1.0,1.0,1.0,1.0)
    _AmbientCol_Side("环境光_Side",Color) = (1.0,1.0,1.0,1.0)
    _AmbientScale("环境光强度",Range(0,1)) =0.5
    _AmbientOcclusion("环境光遮蔽",2D) = "White"{}
    ...
}
struct VertexInput {
	float4 vertex : POSITION;
	float3 normal:NORMAL;
	float2 texcoord :TEXCOORD0;
};
struct VertexOutput {
	float4 pos : SV_POSITION;
	float3 normalWS : TEXCOORD0;
	float2 uv : TEXCOORD1;
};

uniform float3 _AmbientCol_Top;
uniform float3 _AmbientCol_Bottom;
uniform float3 _AmbientCol_Side;
uniform float _AmbientScale;
uniform sampler2D _AmbientOcclusion;
uniform float4 _AmbientOcclusion_ST;

VertexOutput vert(VertexInput v)
{
	VertexOutput o = (VertexOutput)0;
	o.pos = UnityObjectToClipPos(v.vertex);
	o.normalWS = UnityObjectToWorldNormal(v.normal);
	o.uv = v.texcoord;
	return o;
}
fixed4 frag(VertexOutput i) : COLOR
{
	float3 normal = i.normalWS;
				
	//Ambient
	float mask_Top = max(0, normal.g);
	float mask_Bottom = max(0, -normal.g);
	float mask_Side = max(0, 1 - mask_Top - mask_Bottom);

	float3 ambientCol_Top = _AmbientCol_Top.xyz * mask_Top;
	float3 ambientCol_Bottom = _AmbientCol_Bottom.xyz * mask_Bottom;
	float3 ambientCol_Side = _AmbientCol_Side.xyz * mask_Side;

	float3 ao = tex2D(_AmbientOcclusion,TRANSFORM_TEX(uv, _AmbientOcclusion)).xyz;
	float3 ambientCol = (ambientCol_Top + ambientCol_Bottom + ambientCol_Side).xyz * _AmbientScale * ao.xyz;
	...
}

💡镜面反射:Fresnel(菲涅尔)

在这里插入图片描述
在这里插入图片描述

📢 如果你站在湖边,低头看脚下的水,你会发现水是透明的,反射不是特别强烈;如果你看远处的湖面,你会发现水并不是透明的,但反射非常强烈。这就是菲涅尔效应。视线垂直于表面时,反射较弱,而当视线非垂直表面时,夹角越小,反射越明显。如果你看向一个圆球,那圆球中心的反射较弱,靠近边缘较强。不过这种过度关系被折射率影响。
📢 在真实世界中,除了金属之外,其它物质均有不同程度的“菲涅尔效应”。

Properties
{
    _FresnelPow("菲涅尔pow",Float)=1
}

uniform float _FresnelPow;
 
struct VertexInput {
     float4 vertex : POSITION;
     float3 normal : NORMAL;
};
struct VertexOutput {
     float4 pos : SV_POSITION;
     float3 nDirWS :TEXCOORD0;
     float3 posWS :TEXCOORD1;
};
VertexOutput vert (VertexInput v)
{
     VertexOutput o = (VertexOutput)0;
     o.pos = UnityObjectToClipPos( v.vertex );
     o.posWS = mul(unity_ObjectToWorld,v.vertex);
     o.nDirWS = UnityObjectToWorldNormal(v.normal);
     return o;
}
fixed4 frag (VertexOutput i) : COLOR
{
      float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
      //夹角越大菲涅尔越强,所以这里要“1-”
      float fresnel =pow(1-dot(vDirWS,i.nDirWS),_FresnelPow);
      return fresnel;
}

💡 Matcap(材质捕捉)

在这里插入图片描述

在这里插入图片描述请添加图片描述

📢 将BRDF渲染结果烘焙到贴图上,用View空间法线rg分量构成uv采样。能很真实地表现出各类材质信息。它不考虑光源信息,也就没有实际的光照计算。
📢 由于使用的法线向量是经过归一化的,因此r r + gg =1 即圆方程,所以采样的范围始终为一个圆。
📢 制作Matcap贴图(就是用Blender渲染一个球)。

Properties
{
    _MatcapTex("material capture",2D) = "white"{}
}
uniform sampler2D _MatcapTex; 
struct VertexInput {
   float4 vertex : POSITION;
   float2 texcoord :TEXCOORD0;
   float3 normal:NORMAL;
};
struct VertexOutput {
    float4 pos : SV_POSITION;
    float3 nDirWS :TEXCOORD0;
};
VertexOutput vert(VertexInput v)
{
     VertexOutput o = (VertexOutput)0;
     o.pos = UnityObjectToClipPos(v.vertex);
     o.nDirWS = UnityObjectToWorldNormal(v.normal);
     return o;
}
fixed4 frag(VertexOutput i) : COLOR
{
      float3 nDirWS = i.nDirWS;
      //世界=》视角空间 
      float3 nDirVS = mul(UNITY_MATRIX_V,nDirWS).rgb;
      //提取rg通道并重新映射作为uv采样matcap贴图(-1,1) =>(0,1),matcap即material capture 材质捕捉
      float2 uvVS = nDirVS.rg * 0.5 + 0.5;
      float3 finalCol = tex2D(_MatcapTex,uvVS).rgb;
      return fixed4(finalCol,1);
}

💡 Cubemap

在这里插入图片描述
请添加图片描述

下图配置是用于材质上的一个低分辨率的Cubemap
在这里插入图片描述

📢 CubeMap通常被用来作为具有反射属性物体的反射源。

Properties
{
    _Cubemap("Cubemap",Cube) = "_Skybox"{}
    _CubemapMip("CubeMap模糊程度",Range(0,7)) = 0.0
}
uniform float _CubemapMip;
uniform samplerCUBE _Cubemap;
struct VertexInput {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
};
struct VertexOutput {
     float4 pos : SV_POSITION;
     float3 posWS : TEXCOORD0;
     float3 nDirWS : TEXCOORD1;
};  

VertexOutput vert(VertexInput v)
{
     VertexOutput o = (VertexOutput)0;
     o.pos = UnityObjectToClipPos(v.vertex);
     o.posWS = mul(unity_ObjectToWorld,v.vertex);
     o.nDirWS = UnityObjectToWorldNormal(v.normal);
	 return o;
}

fixed4 frag(VertexOutput i) : COLOR
{
     float3 vDirWS = normalize(i.posWS.xyz - _WorldSpaceCameraPos.xyz);
     float3 vrDirWS= reflect(vDirWS,i.nDirWS);
     float3 final = texCUBElod(_Cubemap, float4(vrDirWS, _CubemapMip)).rgb;
     return fixed4(final,1);
}

🥓混合模式

AB(Alpha Blend)、AC(Alpha Cutoff)、AD(Alpha Add) 是混合模式中常用的几种。
在这里插入图片描述

🥞混合原理

💡 Src * SrcFactor op Dst*DstFactor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

🥙 Alpha Cutoff

    Properties {
        _MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Cutoff ("透切阈值", range(0.0, 1.0)) = 0.5
    }
    SubShader {
        Tags {
            "RenderType"="TransparentCutout"    // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }
	}
	Pass{
			// 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Cutoff;
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输出结构
            struct VertexOutput {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                    o.pos = UnityObjectToClipPos( v.vertex);    // 顶点位置 OS>CS
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                return o;
            }
            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                clip(var_MainTex.a - _Cutoff);                  // 透明剪切
                return var_MainTex;                             // 返回值
            }
	}

🌮 Alpha Blend

Properties {
        _MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Opacity ("透明度", range(0, 1)) = 0.5
    }
    SubShader {
        Tags {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }
        Pass {
        	Blend One OneMinusSrcAlpha          // 修改混合方式One/SrcAlpha OneMinusSrcAlpha
            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Opacity;
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输出结构
            struct VertexOutput {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                    o.pos = UnityObjectToClipPos( v.vertex);    // 顶点位置 OS>CS
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                return o;
            }
            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                half3 finalRGB = var_MainTex.rgb;
                half opacity = var_MainTex.a * _Opacity;
                return half4(finalRGB * opacity, opacity);                // 返回值
            }
        }

Alpha Add

Alpha Blend差不多,只需要改混合模式为:Blend One One

Properties {
        _MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}
        _Opacity ("透明度", range(0, 1)) = 0.5
    }
    SubShader {
        Tags {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }
        Pass {
        	Blend One One          // 修改混合方式
            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform half _Opacity;
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输出结构
            struct VertexOutput {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                    o.pos = UnityObjectToClipPos( v.vertex);    // 顶点位置 OS>CS
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);       // UV信息 支持TilingOffset
                return o;
            }
            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR {
                half4 var_MainTex = tex2D(_MainTex, i.uv);      // 采样贴图 RGB颜色 A透贴
                half3 finalRGB = var_MainTex.rgb;
                half opacity = var_MainTex.a * _Opacity;
                return half4(finalRGB * opacity, opacity);                // 返回值
            }
        }

📚 屏幕UV

  • 计算顶点在ViewSpace位置,其xy轴即对应屏幕UV坐标;
  • 除以屏幕深度校正畸变;
  • 计算模型原点在ViewSpace位置,取Z轴深度即距离;
  • 乘以screenUV 以固定屏幕纹理Tiling尺寸;
  • 启用_ScreenTex 的ST功能,乘以ScreenTex_ST.xy以支持缩放;
  • 加强Offset功能为flow动画,参照15课内容;
struct VertexInput{
	float4 vertex :POSITION;//顶点位置 OS
	float2 uv : TEXCOORD0; //uv信息
};
struct VertexOutput{
	float4 pos : SV_POSITION; //顶点位置 CS
	float2 uv : TEXCOORD0; //UV信息
	float2 screenUV : TEXCOORD1; //屏幕uv
};
VertexOutput vert(VertexInput v){
	VertexOutput o = (VertexOutput) o;
	o.pos = UnityObjectToClipPos(v.vertex);
	o.uv = v.uv;
	float3 posVS =UnityObjectToViewPos(v.vertex).xyz; //顶点位置 OS > VS
	float originDist = UnityObjectToViewPos(float3(0.0,0.0,0.0)).z;//原点位置 OS > VS
	o.screenUV = posVS.xy / posVS.z; //VS空间畸变校正
	o.screenUV *= originDist; //纹理大小按距离锁定
	o.screenUV = o.screenUV * _ScreenTex_ST.xy - frac(_Time.x * _ScreenTex_ST.zw);//启用屏幕纹理ST
	return o;
}
half4 frag(VertexOutput i):COLOR{
	half4 var_MainTex = tex2D(_MainTex,i.uv);//采样 基本纹理 RGB颜色 A透贴
	half var_ScreenTex = tex2D(_screenTex,i.screenUV).r; //采样 屏幕纹理
	//FinalRGB 不透明度
	half3 finalRGB = var_MainTex.rgb;
	half opacity = var_MainTex.a * _Opacity * var_ScreenTex;
	return half4(finalRGB * opacity,opacity);
}

📚 GrabPass获取背景纹理

方便、消耗大。其它方式获取背景纹理:1.CommandBuffer:前Srp时代管线自定义方法。2.LWRP/URP:后Srp时代管线自定义方法(推荐)

SubShader{
	GrabPass{
		"_BGTex"
	}
	Pass{
		uniform sampler2D _BGTex;//取到背景纹理
		struct VertexInput{
			float4 vertex:POSITION;
			float2 uv:TEXCOORD0;
		};
		struct VertexOutput{
			float4 pos:SV_POSITION;
			float2 uv:TEXCOORD0;
			float4 grabPos:TEXCOORD1;
		};
		VertexOutput vert(VertexInput v){
			VertexOutput o = (VertexOutput)0;
			o.pos = UnityObjectToClipPos(v.vertex);
			o.uv= v.uv;
			o.grabPos= ComputeGrabScreenPos(o.pos);
			return o;
		}
		half4 frag(VertexInput i):COLOR{
			half3 var_BGTex =tex2Dproj(_BGTex,i.grabPos).rgb;
			...
		}
	}
}

📚 走位走位

💡 透贴阴影问题

计算投影必须要有一个ShadowCastPass(有的FallBack:Diffuse 包含了ShadowCastPass),所以可以FallBack到一个支持AlphaCutout的Shader上比如:Legacy Shaders/Transparent/Cutout/VertexLit,需要注意必须包含Shader中透明相关的所有面板属性!!!

💡 透贴双面问题

关闭剔除背面,在声明BlendMode的地方加入Cull Off即可;

💡绕Y轴旋转

请添加图片描述

Properties
{
    _RotateSpeed("RotateSpeed",Float) = 1
    _Rotation("InitAngle", Range( 0 , 360)) = 0
    _RotateCenterPos("RotateAxisPos", Vector) = (0,0,0,0)
}

uniform float _RotateSpeed;
uniform float _Rotation;
uniform float3 _RotateCenterPos;

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

struct VertexOutput {
    float4 pos : SV_POSITION;
    float3 posWS : TEXCOORD0;
    float3 nDirWS : TEXCOORD1;
};  

VertexOutput vert(VertexInput v)
{
    VertexOutput o = (VertexOutput)0;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.posWS = mul(unity_ObjectToWorld,v.vertex);
    o.nDirWS = UnityObjectToWorldNormal(v.normal);
	return o;
}
//posWS:顶点世界坐标,rotateCenterPosWS:旋转轴世界坐标,一般设置成模型在场景中的世界坐标
//返回的是经过旋转的顶点世界坐标
float3 RotateAroundYInDegrees (float3 posWS,float3 rotateCenterPosWS, float degrees)
{
      posWS = posWS - rotateCenterPosWS;
      float alpha = degrees * UNITY_PI / 180.0;
      float sina, cosa;
      sincos(alpha / 2, sina, cosa);
      float3x3 m = float3x3(cosa, 0, sina, 0, 1, 0, -sina, 0, cosa);
      float3 r = float3(mul(m, posWS.xyz) ).rgb;
      return r;
}

 fixed4 frag(VertexOutput i) : COLOR
{
      float degree =_Rotation + _RotateSpeed * _Time.y ;
      //旋转坐标
      float3 posWS= RotateAroundYInDegrees(i.posWS,_RotateCenterPos,degree);
      ...
}

💡Cginc

封装库

#ifndef zyf_cginc
#define zyf_cginc
float3 calculate(){
	return float3(0,0,0);
}
#endif

🥡使用库复用函数

#include "库相对shader文件路径"
例:#include "../xxx/zyf.cginc"

📝待待待待待待待待待待待待待待待待待待待续🚩

🍗大作业

第11课

帖子看我👈
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
💡 金属度会让漫反射的金属部分变暗。
在这里插入图片描述

💡 镜面反射颜色
在这里插入图片描述

  • 8
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牙膏上的小苏打2333

哟,哟,切克闹,煎饼果子来一套

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值