自我介绍
广东双非一本的大三小白,计科专业,想在制作毕设前夯实基础,毕设做出一款属于自己的游戏!
渐变纹理
效果
代码没什么好说的,跟单张纹理类似
不过要注意的是:
- 渐变纹理是一维纹理,所以在vert中进行uv映射之后,在frag中进行采样的uv值中的v和u方向都用半兰伯特模型中的值即可(该半兰伯特模型中的值已被映射到 [0, 1] 中)
Shader "Unlit/014"
{
Properties
{
_RampTex("MainTex", 2D) = "white" {}
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(1,256)) = 5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _RampTex;
float4 _RampTex_ST;
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct v2f
{
float4 vertex : SV_POSITION;
fixed3 worldNormal: TEXCOORD0;
float3 worldPos: TEXCOORD1;
float2 uv : TEXCOORD2;
};
v2f vert (appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
fixed3 worldNormal = UnityObjectToWorldNormal( v.normal);
o.worldNormal = worldNormal;
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _RampTex); //v.texcoord.xy * _RampTex_ST.xy + _RampTex_ST.zw;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射
fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
fixed halfLambert = max(0,dot(worldLightDir,i.worldNormal))*0.5+0.5;
fixed3 diffuse = _LightColor0.rgb * tex2D(_RampTex, fixed2(halfLambert,halfLambert)) * _Diffuse.rgb;
//高光反射
//fixed3 reflectDir = normalize(reflect(-worldLightDir,i.worldNormal));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
//fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(i.worldNormal,halfDir)),_Gloss);
fixed3 color = ambient + diffuse + specular;
return fixed4(color,1);
}
ENDCG
}
}
}
但是在材质属性上需要进行一个小改动
Wrap Mode分别为Repeat和Clamp模式的效果对比
会有黑点是因为浮点精度造成的,比如 fixed2(halfLambert,halfLambert)
中,理论上他们的值在 [0,1] 之间浮动,但也有可能出现 1.00001,这时候如果是用的Reapeat模式,会舍弃掉整数部份,保留小数部份,得到0.00001,也就是黑色
遮罩纹理
这是非常有用的纹理,为了得到更加细腻的效果,需要用到遮罩纹理来控制光照,效果如下
流程:通过采样得到遮罩纹理的纹素值,然后使用其中某几个通道的值来与表面属性进行相乘(比如通道值为0,可以保护表面不受该属性影响)
可以看到下面我们只是用了这张遮罩纹理的一个分量值,其他值就被浪费了,实际制作中,要充分利用遮罩纹理中的每个颜色通道来存储不同的表面属性,后面会提到
Shader "Unlit/015"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BumpMap("BumpMap", 2D) = "bump" {}
_BumpScale("BumpScale", float) = 5
_SpecularMask("Specular Mask", 2D) = "white"{}
_SpecularScale("Specular Scale", float) = 1
_Diffuse("Diffuse", color) = (1,1,1,1)
_Specular("Specular", color) = (1,1,1,1)
_Gloss("Gloss", Range(1, 256)) = 2
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
sampler2D _SpecularMask;
float4 _SpecularMask_ST;
float _SpecularScale;
fixed3 _Diffuse;
fixed3 _Specular;
float _Gloss;
struct v2f
{
float4 vertex : SV_POSITION;
float4 TtiW0 : TEXCOORD0;
float4 TtiW1 : TEXCOORD1;
float4 TtiW2 : TEXCOORD2;
float4 uv : Texcoord3;
float2 maskUv : TEXCOORD4;
};
v2f vert(appdata_tan v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
o.maskUv = TRANSFORM_TEX(v.texcoord, _SpecularMask);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
float3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
o.TtiW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtiW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtiW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
return o;
}
fixed4 frag(v2f o) : SV_TARGET0
{
float3 worldPos = float3(o.TtiW0.w, o.TtiW1.w, o.TtiW2.w);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
fixed4 packedNormal = tex2D(_BumpMap, o.uv.zw);
fixed3 tangentNormal = UnpackNormal(packedNormal);
tangentNormal.xy *= _BumpScale;
fixed3 worldNormal = normalize(float3(dot(o.TtiW0.xyz, tangentNormal), dot(o.TtiW1.xyz, tangentNormal), dot(o.TtiW2.xyz, tangentNormal)));
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 albedo = tex2D(_MainTex, o.uv.xy).rgb;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * albedo * (dot(lightDir, worldNormal) * 0.5 + 0.5);
fixed3 specularMask = tex2D(_SpecularMask, o.maskUv).r * _SpecularScale;
fixed3 halfDir = normalize(viewDir + lightDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss) * specularMask;
fixed3 color = ambient + diffuse + specular;
return fixed4(color, 1);
}
ENDCG
}
}
}
书上的shader是 主纹理_MainTex
,法线纹理_BumpMap
和 遮罩纹理_SpecularMask
都用同一个纹理属性变量 _MainTex_ST
来控制
因为很多时候我们不需要对纹理进行平铺和位移操作,这样能节省需要存储的纹理坐标数目,空出顶点着色器中的插值寄存器
Shader "Unlit/015"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BumpMap("BumpMap", 2D) = "bump" {}
_BumpScale("BumpScale", float) = 5
_SpecularMask("Specular Mask", 2D) = "white"{}
_SpecularScale("Specular Scale", float) = 1
_Diffuse("Diffuse", color) = (1,1,1,1)
_Specular("Specular", color) = (1,1,1,1)
_Gloss("Gloss", Range(1, 256)) = 2
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float _BumpScale;
sampler2D _SpecularMask;
float _SpecularScale;
fixed3 _Diffuse;
fixed3 _Specular;
float _Gloss;
struct v2f
{
float4 vertex : SV_POSITION;
float4 TtiW0 : TEXCOORD0;
float4 TtiW1 : TEXCOORD1;
float4 TtiW2 : TEXCOORD2;
float2 uv : Texcoord3;
};
v2f vert(appdata_tan v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
float3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
o.TtiW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtiW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.TtiW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
return o;
}
fixed4 frag(v2f o) : SV_TARGET0
{
float3 worldPos = float3(o.TtiW0.w, o.TtiW1.w, o.TtiW2.w);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
fixed4 packedNormal = tex2D(_BumpMap, o.uv);
fixed3 tangentNormal = UnpackNormal(packedNormal);
tangentNormal.xy *= _BumpScale;
fixed3 worldNormal = normalize(float3(dot(o.TtiW0.xyz, tangentNormal), dot(o.TtiW1.xyz, tangentNormal), dot(o.TtiW2.xyz, tangentNormal)));
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 albedo = tex2D(_MainTex, o.uv).rgb;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * albedo * (dot(lightDir, worldNormal) * 0.5 + 0.5);
fixed3 specularMask = tex2D(_SpecularMask, o.uv).r * _SpecularScale;
fixed3 halfDir = normalize(viewDir + lightDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss) * specularMask;
fixed3 color = ambient + diffuse + specular;
return fixed4(color, 1);
}
ENDCG
}
}
}