If you meet the following conditions, I suggest you read this tutorial:
- You want to know how to process color in a surface shader (blend colour)
- You want to achieve a more realistic snow effect.
Introduction
I think there's a little abrupt transition from snow to snow-free areas, and it feels more like white paint on rocks than snow! In order to make our snow shader more perfect, the next step is to allow the snow and rock textures to be rendered at the same time, thus achieving a process color effect.
As long as we make some modifications to the pixel processing of the surface shader, we can achieve a good snow effect, and this will prove that the saturate function is very useful.
Preparatory work
The _snowlevel in the second part of the tutorial (a variable that represents the degree of snow) determines whether the pixel should be given the color of snow, and here we also use _snowlevel to make the edge color of the Snow White translucent. Instead of being completely white before. When the normal direction of the pixel is the same as that of the snow (i.e. the smaller the angle of the two), the higher the opacity of the pixel, in other words, the more snow is here, until it is completely opaque, where the pixel color value becomes white (in fact it becomes the color of snow).
Implement the shader
And the shader of the second part of the tutorial the biggest difference is that in the second part of the shader, the color value of each pixel is not the snow color, or the texture color, and this part shader the non-black or white judgment to improve the color value of the change process. This leads us to rewrite the logical part of the shader and use the mathematical calculation method instead of the if conditional judgment.
First we need a property value to indicate the degree to which we blend the snow color. We named the attribute value _wetness (wetting degree, if the value is larger, then the proportion of snow color in the process of color is lower, which indicates that the more moist snow, the less the color of snow, is turned into water):
_wetness ("wetness", Range (00.50.3
Then we need a variable to represent the property value in shader.
float _wetness;
We use the following formula to calculate the difference variable.
float difference = dot (Worldnormalvector (in, O.normal), _snowdirection.xyz)-Lerp (1,-1, _ Snow);
In fact, the second part of the code can also use the difference variable (for example, when the difference is greater than 0 to the area of snow color, less than 0 to use the original texture color), the key is to difference processing and application of different.
void Surf (Input in, InOut surfaceoutput o) { Half4 c = tex2d (_maintex, In.uv_maintex); O.normal = Unpacknormal (tex2d (_bump, in.uv_bump)); float difference = dot (Worldnormalvector (in, O.normal), _ SNOWDIRECTION.XYZ)-Lerp (1 ,-1 ,_snow);; Difference = saturate (difference/ _wetness); O.albedo = Difference*_snowcolor.rgb + (1 -difference) *C; O.alpha = C.A; }
We can see that after calculating difference, we first divide difference by _wetness (here we can get a glimpse of the specific uses of _wetness) and then use difference functions for saturate. The specific use of the saturate function is as follows:
- The saturate function regulates the given value between 0~1 (more than 1 is set to 1, less than 0 is set to 0, and the other is unchanged)
- So when difference is less than 0 o'clock, that is, there is no snow here, we use the saturate function to place difference to 0.
- If the default value of _wetness is 0.3, and the angle between normal and snowy direction is between 73 degrees ~90 degrees, then the value of difference is alive 0~1, greater than 90 degrees, 0, less than 73 degrees is 1.
The range of a cosine is 1 to-1, the gap is 2, represents a change of 0 degrees to 180 degrees (from the same direction to the reverse), so if difference between 0~1, then the result of the point multiplication (that is, the Cos value) must be between 0~0.3, so the corresponding angle is 73 degrees ~90 degrees (cos73 =0.3,cos90=1).
Then we multiply the difference by the snow color, difference represents the proportion of the snow color in the final color. We then set the color of the texture itself to 1-difference, add to get the final color. The area where the angle is less than 73 degrees will be filled with the snow color, between 73 degrees ~90 degrees (that is, the edge of snow) has a snow transition effect, greater than 90 degrees will use the original color of the texture.
O.albedo = Difference*_snowcolor.rgb + (1-difference) *c;
Correcting vertex data
If our snow is very moist (wet), then only using the original shader, we will find that the area of less snow, the model will be thickened, the fundamental reason is that our vertex change mode does not vary with the snow color process (mainly added _wetness parameters) change, the effect will not be true. So we should apply the parameter _wetness to the calculation, so that the thickening effect of the model changes with _wetness.
void Vert (inout appdata_full v) { if(dot (v.normal, _snowdirection.xyz) >= lerp (1,1 , ((1-_wetness) * _snow*2)/3)) { + = (_snowdirection.xyz + V.normal) * _snowdepth * _snow; }}
As you can see, we decide whether the thickening model is judged to be greater than
Lerp (1,-1, ((1-_wetness) * _snow*2)/3))
If _wetness is 0, then nothing has changed, and if _wetness has changed to its maximum range of 0.5, then _snow's proportion is no longer 2/3, but 1/3-increasing the model thickening range by 50%.
Here's the final:
Source
Shader"custom/realistic Snow"{Properties {_maintex ("Base (RGB)", 2D) =" White"{} _bump ("Bump", 2D) ="Bump"{} _snow ("Snow Level", Range (0,1) ) =0_snowcolor ("Snow Color", Color) = (1.0,1.0,1.0,1.0) _snowdirection ("Snow Direction", Vector) = (0,1,0) _snowdepth ("Snow Depth", Range (0,0.2)) =0.1_wetness ("wetness", Range (0,0.5)) =0.3} subshader {Tags {"Rendertype"="Opaque"} LOD $Cgprogram#pragmaSurface Surf Lambert Vertex:vertsampler2d _maintex; Sampler2d _bump; float_snow; FLOAT4 _snowcolor; FLOAT4 _snowdirection; float_snowdepth; float_wetness; structInput {float2 Uv_maintex; FLOAT2 Uv_bump; FLOAT3 Worldnormal; Internal_data}; voidVert (inout appdata_full v) {//convert _snowdirection to model local coordinate systemFLOAT4 sn =Mul (UNITY_MATRIX_IT_MV, _snowdirection); if(Dot (v.normal, sn.xyz) >= Lerp (1,-1, (_snow*2)/3) ) {v.vertex.xyz+ = (sn.xyz + v.normal) * _snowdepth *_snow; } } voidSurf (Input in, InOut surfaceoutput o) {half4 c=tex2d (_maintex, In.uv_maintex); O.normal=Unpacknormal (tex2d (_bump, in.uv_bump)); Half difference= Dot (Worldnormalvector (in, O.normal), _snowdirection.xyz)-Lerp (1,-1, _snow); Difference= Saturate (Difference/_wetness); O.albedo= Difference*_snowcolor.rgb + (1-difference) *C; O.alpha=C.A; } ENDCG} FallBack"Diffuse"}
Unity3d Shader Beginner's Tutorial (3/6)--More real snow