Shader programming_ For the basic texture in unity, use Unity Shader to achieve the rendering effect of the basic texture

Learn how to render basic textures using Unity Shader

catalogue

Learn how to render basic textures using Unity Shader

Q1: describe the diffuse texture, height texture, normal texture, gradient texture and mask texture in detail?

Q2: what is model space, tangent space and world space?

Q3: what are the advantages and disadvantages of storing normals in normal texture in model space and tangent space respectively?

Q4: what is the difference between Repeat and Clamp in the Wrap Mode attribute in the detailed texture attribute?

Practical operation

Experiment 1: in Unity, a single texture is used to replace the diffuse color of the object, and the shader program code is written to achieve this effect.

Experiment 2: in Unity, diffuse texture and normal texture are used to realize the convex concave effect of the object. Pay attention to the lighting calculation in tangent space, and write shader program code to realize this effect.

Experiment 3: in Unity, diffuse texture and normal texture are used to realize the convex and concave effect of objects. Pay attention to lighting calculation in world space and write shader program code to achieve this effect.

Q1: describe the diffuse texture, height texture, normal texture, gradient texture and mask texture in detail?

Answer 1:

Diffuse texture: a texture is usually used to replace the diffuse color of an object. Declare a texture variable, and then use the tex2D function to sample.

 

Height texture: a height map is used to realize bump mapping. The height map stores the intensity value, which is used to represent the local altitude of the model surface. The lighter the color, the more convex the surface of the position is, and the darker the color, the more concave the position is.

Advantages: very intuitive, you can see the concave convex shape of the model surface at a glance;

Disadvantages: the calculation is more complex. In real-time calculation, the surface normal cannot be obtained directly, but the gray value of pixels needs to be calculated, which consumes more performance.


Normal texture: stores the normal direction of the surface. Since the component range in the normal direction is [- 1,1], while the component range of pixels is [0,1], a mapping is required. The usual mapping is:

pixel = (normal+1)/2

After we sample the normal texture in the shader, we also need to reflect the result once to get the original normal direction. The process of inverse mapping is actually to use the inverse function of the above mapping function:

Normal = pixel x 2 – 1

The normals of model vertices are defined in model space. The surface normals in the modified model space are stored in a texture, which is called object space normal map. However, in actual production, we often use another coordinate space, that is, the tangent space of model vertices to store normals.

 

Gradient texture: mainly used to control the result of diffuse lighting. Now it is mostly used for cartoon style rendering. Different gradient textures have different characteristics.

 

Mask texture: common in many commercial games. Masks allow us to protect certain areas from certain modifications; Or when making terrain materials, you need to mix multiple pictures, such as the texture of grass, the texture of stones, the texture of bare land, etc.

Process: get the texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture texture.

 

Q2: what is model space, tangent space and world space?

A2:

Model space: the coordinate space of all normals is the same coordinate space. The normal direction of each point is different. After mapping, it corresponds to various colors when it is stored in the texture.

Tangent space: the normal texture looks almost all light blue, because the coordinate space of each normal direction is different, that is, the tangent space of each point on the surface. This normal texture stores the normal disturbance direction of each point in its own tangent space.

World space: defined world standard space coordinate system.

 

Q3: what are the advantages and disadvantages of storing normals in normal texture in model space and tangent space respectively?

A3:

Advantages of storing in model space:

① The implementation is simple and more intuitive;

② There are few visible abrupt changes (gaps) at the stitches and sharp corners of texture coordinates, that is, smooth boundaries can be provided;

Advantages of storing in tangent space:

① The degree of freedom is very high. The normal texture in tangent space records the relative normal information. Even if the texture is applied to a completely different mesh, a reasonable result can be obtained;

② UV animation can be carried out, and a bump moving effect can be realized by moving the UV coordinates of a texture;

③ Normal texture can be reused. A normal texture can use bricks with 6 faces;

④ Compressible, the Z direction of the normal in each normal texture is always positive, so you can only store the XY direction and deduce the Z direction.

 

Q4: what is the difference between Repeat and Clamp in the Wrap Mode attribute in the detailed texture attribute?

Answer 4:

Repeat: using this mode, the texture will repeat continuously;

Clamp: in this mode, the part beyond the range will be intercepted to the boundary value to form a bar structure.

 

Practical operation

Experiment 1: in Unity, a single texture is used to replace the diffuse color of the object, and the shader program code is written to achieve this effect.

Shader "Unity Shaders Book/Chapter 7/Single Texture" {
//2 * in order to use texture, we need to add a texture attribute in the semantic block of primperties:
	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
	}
//3 * then a Pass semantic block is defined in the SubShader semantic block. In addition, the first line of the Pass indicates the lighting mode of the Pass:
	SubShader{
		Pass {
			Tags { "LightMode" = "ForwardBase" }
//4 * use CGPROGRAM and END to surround the CG Code slice to define the most important vertex shader and slice shader code. First, we use#

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			#include "Lighting.cginc"

			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed4 _Specular;
			float _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;
				// Or just call the built-in function
//				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));

				// Use the texture to sample the diffuse color
				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"
}


Experiment 2: in Unity, diffuse texture and normal texture are used to realize the convex concave effect of the object. Pay attention to the lighting calculation in tangent space, and write shader program code to realize this effect.

Shader "Unity Shaders Book/Chapter 7/Normal Map In Tangent Space" {
	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
		_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 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			float _BumpScale;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float4 uv : TEXCOORD0;
				float3 lightDir: TEXCOORD1;
				float3 viewDir : TEXCOORD2;
			};

			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;

				//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
				// float3×3 rotation = float3×3(v.tangent.xyz,binormal,v.normal);
				//Or just use the bulid-in macro
				TANGENT_SPACE_ROTATION;
				//Transform the light direction from object space to tangent space
				o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
				//Transform the view direction from object space to tangent space
				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);
				
				// 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)));
				
				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);
			}
			
			ENDCG
		}
	} 
	FallBack "Specular"
}

Experiment 3: in Unity, diffuse texture and normal texture are used to realize the convex and concave effect of objects. Pay attention to lighting calculation in world space and write shader program code to achieve this effect.

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unity Shaders Book/Chapter 7/Normal Map In Tangent Space" {
	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
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}
	SubShader {
		Pass { 
			Tags { "LightMode"="ForwardBase" }
		
			CGPROGRAM
// Upgrade NOTE: excluded shader from DX11; has structs without semantics (struct v2f members pos,uv,TtoW0,TtoW1,TtoW2)
#pragma exclude_renderers d3d11
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			float _BumpScale;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos: SV_POSITION;
				float4 uv: TEXCOORD0;
				float4 TtoW0: TEXCOORD1;
				float4 TtoW1: TEXCOORD2;
				float4 TtoW2: TEXCOORD3;
			};

			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 * _Bump_ST + _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 vie 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 normal from the tangent space to world space
				fixed3 normal = normalize(half3(dot(i.TtoW0.xyz,bump),dot(i.TtoW1.xyz,bump),dot(i.TtoW2.xyz,bump)));

				fixed3 tangentLightDir = normalize(i.lightDir);
				fixed3 tangentViewDir = normalize(i.viewDir);
				
				fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
				
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(normal, lightDir));

				fixed3 halfDir = normalize(lightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(normal, halfDir)), _Gloss);
				
				return fixed4(ambient + diffuse + specular, 1.0);
			}
			
			ENDCG
		}
	} 
	FallBack "Specular"
}

It's not easy to make. Let's encourage bloggers with one button three times!!

 

 

Keywords: C# Unity Unity3d Shader U3D

Added by Tokunbo on Thu, 10 Feb 2022 01:40:13 +0200