Why use normal maps
In order to improve the model performance details without increasing the performance consumption, it is not a choice to increase the number of faces of the model, but rather to use the upper normal map (normal map) for the model's material shader, and to increase the detail of the model performance by changing the normal direction of the points on the model and increasing the shadow and smoothness effect. Using normal maps can make a triangular face appear to be a bump visual effect!
Normal mapping principle
Http://www.cnblogs.com/tekkaman/p/3992352.html
The above article explains a lot of questions:
- normals are stored in tangent spaces (Tangent space Normal), so the normal map looks blue, and if stored in world space, different color values are displayed in each direction.
- Why not choose to store the normals in world space or in model space (Object space Normal).
- When using a normal map, you can convert the light vector to tangent space, or you can convert the normal vector to world space and the light vector, and the result is the same, but why choose the previous method ? because the latter has a spatial coordinate transformation at each point, and since the light vector is a parallel light, the previous method only needs to be computed once.
Storage and use of normal maps
The normal (normal) values range from 1 to 1 for each axis, while the color values (Pixel) range from 0 to 1. So there is a simple computational conversion process when storage (normal orientation is stored as normal map) and used (the color of each point in the program is turned into a normal direction).
- Store normal Map Pixel = (normal + 1)/2
- Use normal map normal = Pixel * 2-1
Because normal maps use tangent space, the above transformations are also performed in tangent space. It is also important to pay attention to the space conversion problem in light direction.
Example
Now prepare the texture map and normal map, and write a simple shader example that uses the normal map.
Shader"Custom/13-rock Normalmap"{properties{_maintex ("Main Tex", 2D) =" White"{}//Texture Map_color ("Color", Color) = (1,1,1,1)//control the color of a texture map_normalmap ("Normal Map", 2D) ="Bump"{}//indicates that the normals of the model vertices are used when no normal map is specified at that location_bumpscale ("Bump Scale", Float) =1 //The bump parameter of the normal map. 0 means that the original discovery of the model is used, and the value in the normal map is used for 1. More than 1, the bump degree is greater. } subshader{Pass {//only the correct lightmode can be defined to get some unity's built-in illumination variables .tags{"Lightmode"="Forwardbase"} cgprogram//include Unity's built-in files before you can use some of the variables built into Unity#include"Lighting.cginc" //gets the color of the first direct light _lightcolor0 the position of the First direct light _worldspacelightpos0 (i.e. direction)#pragmaVertex vert#pragmaFragment Fragfixed4 _color; Sampler2d _maintex; FLOAT4 _maintex_st; //The name is fixed map name + suffix "_st", 4 values first two XY represents scaling, the latter two ZW represents offsetsampler2d _normalmap; FLOAT4 _normalmap_st; //The name is fixed map name + suffix "_st", 4 values first two XY represents scaling, the latter two ZW represents offset float_bumpscale; structa2v {float4 vertex:position; //tell Unity to populate the vertex property with vertex coordinates under model spaceFLOAT3 Normal:normal;//the normals that the model comes with are no longer used. This variable is retained because tangent space is determined by the normals (in the model) and tangent lines (in the model). FLOAT4 tangent:tangent;//The TANGENT.W is used to determine the direction of the axes in the tangent space. FLOAT4 texcoord:texcoord0; }; structv2f {float4 position:sv_position;//declares the coordinates used to store vertices under the clipping space//FLOAT3 worldnormal:texcoord0; //no longer uses the normal direction under World spaceFLOAT3 lightdir:texcoord0;//direction of parallel light under tangent spaceFLOAT3 Worldvertex:texcoord1; FLOAT4 Uv:texcoord2; //XY storage Maintex texture coordinates, ZW stores normalmap texture coordinates }; //calculate vertex coordinates from the model coordinate system to the clipping plane coordinate systemv2f Vert (a2v v) {v2f F; F.position= Mul (UNITY_MATRIX_MVP, V.vertex);//UNITY_MATRIX_MVP is a built-in matrix. This step is used to convert a coordinate from model space to the clipping space//The normal direction. Shift the normal direction from model space to world space//f.worldnormal = Mul (V.normal, (float3x3) unity_worldtoobject);//The reverse multiplication is from the model to the world, otherwise from the world to the modelF.worldvertex =Mul (V.vertex, unity_worldtoobject). xyz; //f.uv = v.texcoord.xy;//do not use scaling and offsetsF.uv.xy = v.texcoord.xy * _maintex_st.xy + _maintex_st.zw;//texture coordinates of the mapF.UV.ZW = v.texcoord.xy * _normalmap_st.xy + _normalmap_st.zw;//texture coordinates for normal mapstangent_space_rotation;//call this macro to get a matrix rotation, which is used to convert the direction of the model space under the tangent space//Objspacelightdir (V.vertex);//the direction of parallel light under model space is obtainedF.lightdir = Mul (rotation, Objspacelightdir (V.vertex));//direction of parallel light under tangent space returnF; } //all operations related to the normal direction are placed in the tangent space. Because the normal direction obtained from the normal map is under tangent space. fixed4 Frag (v2f f): sv_target {//Ambient LightFixed3 ambient =Unity_lightmodel_ambient.rgb; //The normal direction. Gets from the normal map. The color value of the normal map--normal direction//fixed3 Normaldir = normalize (f.worldnormal); //no longer use the model's own normalsFixed4 NormalColor = tex2d (_normalmap, F.UV.ZW);//The color values in the normal map//fixed3 tangentnormal = Normalize (NORMALCOLOR.XYZ * 2-1);//tangent space under the normal direction, found that the calculated normals are not correct! Fixed3 tangentnormal = Unpacknormal (NormalColor);//use Unity's built-in approach, from color-worthy to normal in tangent-space directionTangentnormal.xy = Tangentnormal.xy * _bumpscale;//control the degree of bumpTangentnormal =normalize (tangentnormal); //Light direction. Fixed3 Lightdir = normalize (F.lightdir);//direction of illumination under tangent space//The color of the points on the texture image corresponding to the texture coordinatesFixed3 Texcolor = tex2d (_maintex, F.uv.xy) *_color.rgb; //Diffuse diffuse color = direct light color * MAX (0, cos (angle of light direction and normal direction)) * Material itself color (the color of the point where the texture corresponds )FIXED3 diffuse = _lightcolor0 * MAX (0, Dot (Tangentnormal, lightdir)) * TEXCOLOR;//multiplication for color fusion//Final color = Diffuse reflection + ambient lightFixed3 Tempcolor = diffuse + ambient * texcolor;//Let the ambient light also blend with the texture color to prevent ambient light from making the texture look hazy returnFixed4 (Tempcolor,1);//Tempcolor is FLOAT3 already contains three values} ENDCG}} FallBack"Diffuse"}
The effect is that the normal map is used on the left (the bump parameter is 1, the normal direction in the normal map is fully used), and the normal map is not used on the right:
Note the point:
- Tangent_space_rotation the use of macros . Call this macro to get a matrix rotation, which is used to convert the direction of the model space under the tangent space.
- The Objspacelightdir () method is used to get the vector of the current point to the direction of the light source in the model space, that is, the directional direction.
- Use Mul (rotation, Objspacelightdir (V.vertex)); the direction of the parallel light in the tangent space is obtained.
- When converting from a color value to a normal direction under tangent space, it is found that the normal = Pixel * 2-1 is incorrect and the effect is very strange, such as. Instead, use the unity built-in Unpacknormal () method to calculate.
- Attribute _bumpscale is defined to control the degree of bump. When the property value is 0 o'clock, use the normal direction of the model's own, and when the property value is 1 o'clock, use the normal direction in the normal map entirely. Values between 0 and 1 are excessive in both directions, and you can visually see how the model changes by dragging and dropping the property value in the Editor monitor panel. When the property value is greater than 1, the bump level is more intense. Is the case when the value is set to 7 o'clock.
Learning materials:
- http://www.sikiedu.com/course/37/task/456/show#
- http://www.sikiedu.com/course/37/task/458/show#
"Unity Shader" uses the Shader of the normal map (normal map)