For a long time did not insist on blogging blog, it is a moment to start a wave of post! Learning Unity for a while, about shader's book also read a few "Unity Shader primer", "Unity 3D shaderlab Development Combat Detail", open a series to record the learning notes. The principle is not much to say, a practical shader example is good.
Looks like the beginning about shader's explanation are diffuse, however, I bright after the processing seems more simple, so the first one to a simple post-processing, screen simple color correction-adjust brightness, saturation, contrast.
I. Concept INTRODUCTION
We are playing games, although we now have unity and other engines, we do not have to deal with some of the tedious things, but in any case, the final display on the screen or some RGB pixel information, understand these basic concepts, certainly to our game has a greater help.
1. The concept of color models
Since it is the color of the correction screen, it is necessary to understand the concepts of the several properties that we want to correct. Here we have to mention our common color definitions, the RGB color model and the HSV color model.
1.1RGB color model
RGB color model is our most commonly used three primary colors, red and green blue. The RGB color model is an addition process color when it is mixed, and the higher the color value in RGB, the brighter the color. RBG is black at (0,0,0) and white when RGB is (255,255,255). When processing color information, the computer generally uses the RGB color model, which can be used to represent a color very precisely.
1.2HSV color model
The RGB color model is easy for computers to calculate, but not for human understanding, so there is the HSV color model, the so-called HSV represents
Hue (hue), saturation (saturation), Value (Hue )There is also a claim that the HSB model, b for the Brightness (lightness). Of course, there are other statements, such as the HSL model, where L stands for lightness (brightness). The HSV model uses a conical coordinate system with a V (value tint) of 1 for the top face, a lighter color, a value of 0 for the bottom, and a darker color, while the H (Hue) is given by the angle of rotation around the V axis, from red to counterclockwise, and red to 0 degrees, green corresponds to 120 degrees. , the blue corresponds to 240 degrees; S (saturation saturation) is represented by the radius of the model, the inward and outward saturation gradually increase, the center is 0, the edge is 1. is an illustration of the HSV color model:
Conversion of 1.3RGB color model and HSV color model
Since both color models can represent colors, there must be some kind of conversion relationship between the two.
RGB conversion to HSV Model: Assume that RGB is represented by (R,G,B), where r,g,b is a real number between 0-1, Max is the maximum of r,g,b, Min is the minimum, HSV is denoted by (h,s,v), and H is a real number between 0-360, While S and v are real numbers between 0-1, the conversion relationship is as follows:
The HSV model is converted to an RGB model:
2. The concept of brightness, saturation, contrast, grayscale
2.1 Brightness
The size of the RGB values in the image, the larger the RGB values, the brighter the brightness, the smaller the brightness, the darker. For example, if we want to increase the brightness, then directly increase the RGB value.
2.2 Saturation
It refers to the purity of the color. The degree of color deviation from the same luminance gray is generally characterized by the color divided by the lightness. Simply put, when the color is more biased to a certain value, that is, the more the deviation from the grayscale, the greater the saturation, when the color of the more gray, the smaller the saturation. Here is the Baidu encyclopedia on the definition of saturation: saturation refers to the color of the bright degree, also known as the purity of color. The saturation depends on the ratio of the color component and the color-dissipating component (gray) in the color. The greater the color content, the greater the saturation, and the greater the color-dissipating component, the less the saturation. Pure colors are highly saturated, such as scarlet, bright green. A mixture of white, gray, or other tonal colors, which are unsaturated colors such as reddish purple, pink, and brown. Completely unsaturated colors have no hue at all, such as various shades of gray between black and white
2.3 Contrast Ratio
Refers to a picture in the light and dark areas of the brightest white and the darkest between the different levels of brightness of the measurement, the larger the difference between the greater the contrast, the smaller the difference, the smaller the contrast. In general, the greater the contrast, the clearer the image, the more vivid the color, and the smaller the contrast, it will make the whole picture is gray.
2.4 Grayscale
Grayscale uses a black tone to indicate an object, that is, black as the reference color, different saturation of the black to display the image. Each grayscale object has a luminance value from 0% (white) to 100% (black).
Having learned some basic color concepts, we can begin to deal with them. First, let's look at the principles behind Unity's post-processing effects.
Two. Unity screen post-processing principle
The so-called screen post-processing, in short, is the final stage of the rendering pipeline, a picture generated by the entire scene processing, such as HDR, motion blur and so on, through the screen space after processing, can change the overall game style or effect. So, to make the screen post-processing, we need two things, one for the post-processing effect, and the other for the script that we need to invoke this rendering, but unity gives us the relevant functionality. Shader
1.OnRenderImage function
The function is provided in Monobehaviour, which is called after all rendering is complete, which is what we said above to generate a picture of the scene, the prototype of the function is as follows:
void Onrenderimage (Rendertexture sourcetexture,rendertexture desttexture);
Rendertexture represents rendering textures, and we render objects not just for screen space, but also for rendering objects to specific textures, that is, rendertexture. Sourcetexture is the scene image we render, and Desttexture is the target rendering texture. We can do the related post-processing effect in this function and re-render the scene content using a material with a post-processing effect shader.
2.graphics.blit function
The function is a graphics function that copies the source texture to the target texture, and the function prototype is as follows:
public static void Blit (Texture source,rendertexture dest); public static void Blit (Texture source,rendertexture dest, Material mat, int pass =-1); public static void Blit (Texture source,material mat, int pass =-1);
Source is the origin texture, dest is the target texture, when dest is null, the source texture is copied directly to the screen, the mat is the material used in the copy, which is the material we use after processing, and unity uses that material to copy the source texture to the target texture. Pass is the use of the material shader used by the pass, we know that a shader may have multiple passes, which pass for processing can be passed from this parameter, of course, the default is 1 indicates that all pass will be executed.
After understanding the untiy process, we can write our brightness contrast saturation adjustment after processing.
Three. Post-processing effect code
The post-processing effect requires two parts, namely the script section and the shader section, which we look at separately.
1. Script section
The post-processing script mainly does two things, the first is to get the required shader, to create the material, and the second is to use the material to process the screen effect through Onrenderimage. The first step has some universality, no matter what the post-processing effect, must have this same step, so we pull out the step out, create a post-processing effect of the base class Posteffectbase, the code is as follows:
Using unityengine;using system.collections;//non-runtime also triggers effects [executeineditmode]//screen post-processing effects generally need to be tied to the camera [Requirecomponent ( typeof (Camera))]//provides a post-processing base class that is primarily designed to be dragged into shader directly from the Inspector panel, generating shader corresponding material public class Posteffectbase: Monobehaviour {//inspector Panel, drag directly into public Shader Shader = null; Private Material _material = null; Public Material _material {get {if (_material = = null) _material = Generatema Terial (shader); return _material; }}//Create a material for screen effects based on Shader protected Material generatematerial (Shader Shader) {if (Shader = null) return null; You need to determine if shader supports if (shader.issupported = = false) return null; Material Material = new Material (shader); Material.hideflags = Hideflags.dontsave; if (material) return material; return null; } }
Then, after all of our post-processing effect scripts can inherit the class Posteffectbase, we automatically have the ability to process the material through shader generation.
Next is the brightness of our article, saturation, contrast adjustment of the script, the script is very simple, the main function is to set a few parameters, overwrite the Onrenderimage function after the parameters in real-time shader, and then through the Blit function to complete the processing effect, the code is as follows:
Using Unityengine;using system.collections;//inherits from Posteffectbasepublic class Coloradjusteffect:posteffectbase {//via RA Nge control the range of parameters that can be entered [range (0.0f, 3.0f)] public float brightness = 1.0f;//brightness [range (0.0f, 3.0f)] public float CONTR AST = 1.0f; Contrast ratio [Range (0.0f, 3.0f)] public float saturation = 1.0f;//saturation//overwrite onrenderimage function void Onrenderimage (Renderte Xture src, rendertexture dest) {//post-processing only when there is material, if _material is empty, do not post-process if (_material) { by Material.setxxx ("name", value) you can set the parameter values in the shader _material.setfloat ("_brightness", brightness); _material.setfloat ("_saturation", saturation); _material.setfloat ("_contrast", contrast); Using material processing texture,dest is not necessarily the screen, the post-processing effect can be superimposed! Graphics.blit (SRC, dest, _material); } else {//Draw graphics.blit directly (SRC, dest); } }}
In this way, our post-processing script is complete. The following knowledge points are involved: 1. You can control the values in the Inspector panel by using [range Min,max], limit its range, and provide slider control. The 2.OnRenderImage function executes after rendering all the contents of each frame, we set the parameters of material at each frame, and by Material.setxxx ("name", value) we can pass various parameters to shader. 3. Various post-processing effects can be superimposed, the dest here is not necessarily the screen. However, the post-processing is very cost-effective, on the one hand is pixel shader full screen overdraw, on the other hand, a rendertexture memory consumption is very large, especially on large-resolution phones, multiple post-processing effects may cause memory exhaustion, program crashes.
2.shader part
Finally entered the subject, the following look at the post-processing effect of the shader. Since the post-processing effect is for a scene of the rendering of the processing, so vertex shader basically nothing to say, most of the post-processing is based on pixel shader. First tidy up the idea: The simplest is the brightness, we can directly after sampling texture multiplied by a factor, to enlarge or reduce the RGB value, so you can adjust the brightness. Next is the saturation, the saturation is the larger deviation from the gray level, the greater the saturation, we can first calculate the same brightness conditions under the lowest saturation value, according to the formula: Gray = 0.2125 * r + 0.7154 * g + 0.0721 * B to find out the value (the formula should be an empirical formula), and then we With this value and the original image with a coefficient of difference, you can achieve the purpose of adjusting the saturation. The last is the contrast, the contrast indicates that the color difference is stronger contrast, when the color is pure gray, that is (0.5,0.5,0.5), the contrast is minimal, we through the smallest contrast of the image and the original image through the coefficient difference, to achieve the purpose of adjusting the contrast. The code is as follows:
The shader directory Shader "Custom/coloradjusteffect" {//attribute block, shader used property, can be adjusted directly in the Inspector panel properties {_maintex ("Albedo" ( RGB) ", 2D) =" White "{}_brightness (" brightness ", float) = 1_saturation (" saturation ", float) = 1_contrast (" contrast ", Floa T) = 1}//Each shader has Subshaer, each subshaer is a parallel relationship, only may run a subshader, mainly for different hardware subshader{//really work is pass, There may be different passes in a shader, you can perform several passpass{//to set some render states, which are not explained in detail ztest always cull Off zwrite offcgprogram// The content in the properties is only used for the Inspector panel, which is really stated here, notice the consistency with the above sampler2d _maintex;half _brightness;half _saturation;half _ Contrast;//vert and Frag functions #pragma vertex vert#pragma fragment frag#include "Lighting.cginc"//incoming vertex from shader pixel Shader parameter struct V2F{FLOAT4 pos:sv_position;//vertex position half2 uv:texcoord0; UV coordinates};//vertex shader//appdata_img: vertex shader input with position and one texture coordinate v2f vert (appdata_img v) {v2f o;//from self space to projection space O.pos = Mul (UNITY _MATRIX_MVP, V.vertex);//uv coordinates assigned to OUTPUTO.UV = V.texcoord;return o;} Fragment Shaderfixed4 Frag (v2f i): sv_target{//samples from _maintex based on UV coordinates fixed4 Rendertex = tex2d (_maInTex, I.UV);//brigtness brightness is multiplied by a factor, that is, the RGB overall zoom, adjust the brightness fixed3 finalcolor = Rendertex * _brightness;// Saturation saturation: First calculates the lowest saturation value in the same luminance case based on the formula: fixed Gray = 0.2125 * RENDERTEX.R + 0.7154 * rendertex.g + 0.0721 * rendertex.b;fixed 3 Graycolor = Fixed3 (Gray, Gray, gray);//Based on saturation the difference between the lowest saturation image and the original picture Finalcolor = Lerp (Graycolor, Finalcolor, _ saturation);//contrast contrast: First calculates the lowest contrast value fixed3 Avgcolor = fixed3 (0.5, 0.5, 0.5);//According to contrast in the lowest contrast between the image and the original picture difference Finalcolor = Lerp (Avgcolor, Finalcolor, _contrast);//return result, alpha channel unchanged return FIXED4 (Finalcolor, rendertex.a);} endcg}}//protection against shader failure fallback OFF}
Four. Effect display
After completing the shader and post-processing scripts, we can create a scene, hang the script on the Maincamera of the scene, and then assign the coloradjusteffect shader to the shader slot of the script, as shown in:
First, the brightness, contrast, and saturation are all set to 1, and the scene is as follows:
The image effect of adjusting brightness is as follows:
Adjust the contrast effect as follows:
The conditions for adjusting the saturation are as follows:
Unity shader-post-processing: Simple color adjustment (brightness, saturation, contrast)