Tags{ "Queue"="AlphaTest" }
在Unity中有两种方式可以实现透明效果:一是使用透明度测试(Alpha Test)、一个是透明度混合(Alpha Blending)。要实现透明的效果就需要注意渲染的顺序了,在没有透明物体的时候,渲染顺序是不重要的,因为有一个深度测试,就是离摄像机的远近程度,深度值小的颜色值就会覆盖深度大的buff,反之直接舍弃了,所以无论怎么渲染都是对的。但是如果有透明物体后,透明物体就应该在不透明的物体后面渲染,在渲染透明物体时要关闭深度写入(更新深度值buff)。对于透明物体需要注意重叠的情况,尽量细分模型。
常用的办法是:
先渲染所有不透明物体,并开启它们的深度测试和深度写入。
把半透明物体按它们距离摄像机的远近进行排序,然后按照从后往前的循序渲染这些半透明物体,并开启他们的深度测试,但关闭深度写入。
遮罩纹理是为了具体的控制某些光照的影响,也就是可以逐像素的控制表面的属性。比如说,一张纹理有4个通道RGBA,我们可以利用A通道存储高光反射的强度,G通道存储边缘光照的强度,B通道存储高光反射的指数,A通道存储自发光的强度。这样,使用遮罩纹理就能很好的控制每一个顶点受到的光照影响。
Shader "Unlit/jianbian" { Properties { _Color ("Color",Color) = (1,1,1,1) _RampTex ("Texture", 2D) = "white" {} } SubShader { Tags { "LightMode"="ForwardBase" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" struct appdata { float4 vertex : POSITION; float3 normal:NORMAL; }; struct v2f { float4 vertex : SV_POSITION; float3 worldNormal:TEXCOORD1; float3 worldPos:TEXCOORD2; }; fixed4 _Color; sampler2D _RampTex; float4 _RampTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed z = 0.5 * dot(worldNormal, worldLightDir) + 0.5; //利用光照影响因子构建uv来取样渐变纹理,从而影响漫反射 fixed3 diffuse = tex2D(_RampTex, fixed2(z, z)).rgb * _Color.rgb * _LightColor0.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; return fixed4( diffuse.rgb + ambient.rgb,1); } ENDCG } } }
在法线贴图导入到Unity后,可以设置为Normal map类型,这一步操作Unity会根据平台来看看是否对法线贴图进行压缩,随后中需要使用UnpackNormal函数来映射为法线。
inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal) { fixed3 normal; normal.xy = packednormal.wy * 2 - 1; normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));//根号(1-(x^2 + y^2)) return normal; } inline fixed3 UnpackNormal(fixed4 packednormal) { #if defined(UNITY_NO_DXT5nm) return packednormal.xyz * 2 - 1; #else return UnpackNormalDXT5nm(packednormal); #endif }
法线可以压缩,只用两个通道就可以的原因在于:
一、法线是一个单位向量,也就是x^2+y^2+z^2=1
二、法线是一个只有正方向的向量
a2v中的数据,传入的就是顶点的法线和切线都是模型空间中的,但是切线空间是顶点为中心的,那么可以说这些顶点的法线和切线就是切线空间x,z轴在模型空间的表达,那么就很好求出切线空间到模型空间的变换矩阵了,只需要使用这几个轴构建变换矩阵就行了。那么模型到切线的变换矩阵就可以通过求逆来得到了,切到模只有旋转和平移,那么就可以通过转置来直接获取得到了。
//计算副切线的方向,v.tangent.w记录了副切线的方向 float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; //转置构建变换矩阵 float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);
也可以使用Unity内置的宏来计算出rotation
TANGENT_SPACE_ROTATION; //rotation
Wrap Mode主要有两种:Repeat为平铺模式,uv超过1范围后会截去整数部分。Clamp为限制模式,当uv超过范围后,就会限制在最小或最大值。
Fiter Mode有三种模式:Point为直接取样最接近的纹理坐标颜色,Bilinear为取样附近4个像素进行线性插值混合,Trilinear和Bilinear再没有使用Mipmapping技术时是一样的。
使用Minmapping前提下,不同的滤波:
struct appdata_full { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; #if defined(SHADER_API_XBOX360) half4 texcoord4 : TEXCOORD4; half4 texcoord5 : TEXCOORD5; #endif fixed4 color : COLOR; };
在PC平台,GPU也许会将这三种类型都会当成最大精度的来处理,但是在移动平台可能就不会了。尽量使用小的类型来存储可以提升性能,例如可以用fixed来存储颜色信息和单位矢量等!