Unity Getting Started Essentials 02---Textures

Texture and material are inseparable

Knowledge structure of this section

Practice: Simply paste a texture onto the model

First add relevant attributes at the attribute

	Properties {
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_MainTex ("Main Tex", 2D) = "white" {}//加入纹理
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}

Then reference it at SubShader

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

Among them, the texture name_ST is used to store the scaling and offset of UV 

The scaling and offset of UV here can be changed by yourself.

The effect before changes is as follows

 

 A little bit disgusting (

 Then define the input and output structures

	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;//传递uv坐标
			};

 The most important piece of code invertex shader

				o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;

 Multiply the texture coordinates (two-dimensional) by the texture's scale + the texture's translation value

You can also use built-in macro commands

o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

 The most important piece of code involving textures in the fragment shader

fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;

Get the color of the pixel on the texture based on the UV coordinates of the model and multiply it by the ambient light.

Texture properties

·Texture Type, the mode of marking texture, you can mark it as default, normal map, GUI, 2DSprite

  Currently, the most commonly used ones for me are default, normal, light baked map, shadow mask, and single channel

  The purpose of the tag may be to allow Unity to automatically handle certain things...

 ·Wrap Mode

 

 It determines how texture coordinates will be tiled when they exceed the [0,1] range. The book only talks about two modes 

1.Repeat, when the texture coordinate exceeds 1, its integer part will be discarded, and the decimal part will be sampled directly, and the result will be repeated continuously.

2. Clamp, the excess part will be truncated and sampled according to the boundary pixels

  ·Filter Mode

 

 Point uses nearest neighbor filtering. When zooming in or out, the number of sampling pixels is only one, so the image has a pixel-style effect.

 Bilinear, uses linear filtering. For each pixel, 4 neighboring pixels are sampled, and then the linear difference is mixed to obtain the final pixel

 Looks a little better.

Trilinear filtering is almost the same as Biliear, except that this option will use mipmap technology for mixing. If a texture does not have mipmap, the result will be the same as Biliear.

Max Size, the texture size and texture quality of different platforms are different. If the imported texture size exceeds Max, Unity will scale it to this maximum resolution ( Try to use textures with a resolution size that is a power of 2, otherwise space and performance will be affected).

Format, determines which format Unity uses internally to store the texture. Some do not require very high-precision textures and try to use compressed formats.

 Bump mapping.

  ·Highly textured (feels rarely used)

    The advantage is that it is more intuitive, but the disadvantage is that the calculation is more complicated, because the normal map needs to be calculated from the grayscale image

   

 ·Normal texture

 Normally the normal texture is blue

 This is because the component range of the normal direction is [-1,1] and the component range of the pixel is [0,1], so we need to map according to a formula

 This map records the normal perturbation direction of each point in its respective tangent space, because the space of each point is different, and the normals mostly point outside the screen. According to the mapping relationship, such as the normal direction of 0,0,1 , after mapping, it is RGB(0.5,0.5,1) light blue.

There is also a case where the normal texture of the B channel is removed.

The advantage of this is that it can reduce the storage space, and the B channel of the normal can be calculated directly. 

The normal texture in world space is really rarely used.

 The book also compares the advantages and disadvantages of the two

 Practice of applying normal texture

 ·Calculation is performed by transmitting lighting and other information to the tangent space

			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(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(unity_ObjectToWorld, v.vertex).xyz;  
				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
				fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
				fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 
				
				// Compute the matrix that transform directions from tangent space to world space
				// Put the world position in w component for optimization
				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 {
				// Get the position in world space		
				float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
				// Compute the light and view dir in world space
				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
				
				// Get the normal in tangent space
				fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
				bump.xy *= _BumpScale;
				bump.z = sqrt(1.0 - saturate(dot(bump.xy, bump.xy)));
				// Transform the narmal from tangent space to world space
				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);
			}

 ·Convert the normal texture in tangent space to world space for calculation

v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(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;

				///
				/// Note that the code below can handle both uniform and non-uniform scales
				///

				// Construct a matrix that transforms a point/vector from tangent space to world space
				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
				fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
				fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 

				/*
				float4x4 tangentToWorld = float4x4(worldTangent.x, worldBinormal.x, worldNormal.x, 0.0,
												   worldTangent.y, worldBinormal.y, worldNormal.y, 0.0,
												   worldTangent.z, worldBinormal.z, worldNormal.z, 0.0,
												   0.0, 0.0, 0.0, 1.0);
				// The matrix that transforms from world space to tangent space is inverse of tangentToWorld
//实际上将法线从切线空间变换到世界空间应该是空间变换矩阵的转置矩阵的逆矩阵,因为切线副切线
//法线是正交的,因此直接用这三个坐标轴构成的矩阵作为变换矩阵是可行的
				float3x3 worldToTangent = inverse(tangentToWorld);
				*/
				
				//wToT = the inverse of tToW = the transpose of tToW as long as tToW is an orthogonal matrix.
				float3x3 worldToTangent = float3x3(worldTangent, worldBinormal, worldNormal);

				// Transform the light and view dir from world space to tangent space
				o.lightDir = mul(worldToTangent, WorldSpaceLightDir(v.vertex));
				o.viewDir = mul(worldToTangent, WorldSpaceViewDir(v.vertex));

				///
				/// Note that the code below can only handle uniform scales, not including non-uniform scales
				/// 

				// Compute the binormal
//				float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w;
//				// Construct a matrix which transform vectors from object space to tangent space
//				float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);
				// Or just use the built-in macro
//				TANGENT_SPACE_ROTATION;
//				
//				// Transform the light direction from object space to tangent space
//				o.lightDir = mul(rotation, normalize(ObjSpaceLightDir(v.vertex))).xyz;
//				// Transform the view direction from object space to tangent space
//				o.viewDir = mul(rotation, normalize(ObjSpaceViewDir(v.vertex))).xyz;
				
				return o;
			}
	fixed4 frag(v2f i) : SV_Target {				
				fixed3 tangentLightDir = normalize(i.lightDir);
				fixed3 tangentViewDir = normalize(i.viewDir);
				
				// Get the texel in the normal map
				fixed4 packedNormal = tex2D(_BumpMap, i.uv.zw);
				fixed3 tangentNormal;
				// If the texture is not marked as "Normal map"
//				tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;
//				tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
				
				// Or mark the texture as "Normal map", and use the built-in funciton
				tangentNormal = UnpackNormal(packedNormal);
				tangentNormal.xy *= _BumpScale;
				tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));//法线切线的z可以通过xy计算出来,因为我们方向进行了归一化,其模长为1
				
				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);
			}

 

When using normal texture, please set Texture Type to Normal map

After setting, Unity will compress the texture according to different platforms.

gradient texture

 Commonly used in NPR. This texture can be sampled on the texture according to the relative relationship between the normal and the lighting direction to control the overall color style of lighting and shadows, and is used to simulate the shadow color blocks in NPR.

 

 Import in properties

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.0, 256)) = 20
	}
			sampler2D _RampTex;
			float4 _RampTex_ST;

Vertex shader gets UV coordinates

o.uv = TRANSFORM_TEX(v.texcoord, _RampTex);

The fragment shader uses diffuse lighting information to construct a two-dimensional coordinate to find the corresponding pixel color in Ramp.

fixed4 frag(v2f i) : SV_Target {
	fixed3 worldNormal = normalize(i.worldNormal);
	fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				
	fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				
	// Use the texture to sample the diffuse color
	fixed 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);
}

Mask texture.

 There are many types of mask textures, ambient light mask, highlight mask...

The principle of masking can be summarized in one sentence as source pixels multiplied by mask pixels.

This book talks about highlight masking in detail.

First is the attribute

	Properties {
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_MainTex ("Main Tex", 2D) = "white" {}
		_BumpMap ("Normal Map", 2D) = "bump" {}
		_BumpScale("Bump Scale", Float) = 1.0
		_SpecularMask ("Specular Mask", 2D) = "white" {}
		_SpecularScale ("Specular Scale", Float) = 1.0
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}

 Reference properties in SubShader

fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float _BumpScale;
sampler2D _SpecularMask;
float _SpecularScale;
fixed4 _Specular;
float _Gloss;

 Here we only define one _MainTex_ST. If we modify the offset and scaling of the main texture, it will affect the sampling of three textures at the same time. It is possible to reduce the number of delta registers used in the vertex shader. This can be done when we do not need to scale and translate the texture or when many textures can use the same scaling and translation. In other words, multiple textures are used to modify the same texture.

v2f vert(a2v v) {
	v2f o;
	o.pos = UnityObjectToClipPos(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.0 - 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);
	// Get the mask value
	fixed specularMask = tex2D(_SpecularMask, i.uv).r * _SpecularScale;
    //不少游戏会将多种纹理(非颜色主纹理)放在多个通道中,因此使用的时候只需要取一个通道的值就可以了,但要知道每个通道具体的含义
	// Compute specular term with the specular mask
	fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)), _Gloss) * specularMask;
			
	return fixed4(ambient + diffuse + specular, 1.0);
}

 

 

     

 

Guess you like

Origin blog.csdn.net/qq_24917263/article/details/129332945