Https://mp.weixin.qq.com/s/rtVJDt0m4aGbigWadEZgXA
For game developers, shaders have long been an important part of game development, and the process of writing and implementing shaders in unity is intuitive and efficient, and excellent shaders can create very beautiful gameplay images while guaranteeing high performance. Today, Unity's technical engineer, Zhang Chenxian, will share how to optimize the unity shader shader.
When we create the shader shader in unity, there are four options:
unlit Shader (no light shader): It is the most basic vertex Shader (vertex shader) and fragment Shader (fragment shader).
Image Effect Shader (Images effect shader): Vertex Shader (vertex shader) and fragment Shader (fragment shader) for screen effects.
Surface Shader: It's more abstract, hides the vertex and fragment functions, exposes surface functions as an alternative, and internally implements a complete lighting model.
Computer Shader (Compute shader): leverages the parallel features of the GPU to provide us with simple data calculations that are independent of the rendering pipeline.
In addition to computer shader, there are no essential differences between the other three species. While writing unity shader, there are some wording that can affect the efficiency of execution.
[Gamma] and [Linear] specify that when the color space is formulated as gamma, the attribute variable is specified as [gamma] and [Linear] are not valid, only if the color space is formulated as Linear. So when we need to use a vector as a color, in the Linear color space, it is more efficient to specify it as [Linear] than [Gamma], because if specified as [gamma],unity will do a conversion calculation on the CPU side.
[Noscaleoffset] can omit the allocation of a variable for us, if you do not need to use the texture tiling and offset, use [Noscaleoffset].
The property also has a perrenderdata, if there is an object, we render 100 times, is the same material, but we sometimes need these 100 objects to display a different color, then how to do? One way is to do the vertex color, but this method is not particularly good, and we also have a way to directly add a color to the material properties, and then set a different color for each material.
If you want to set a different color for each material, unity will help you create 100 such materials, the equivalent of you render 100 objects, each object color is not the same, so the direct setting will help you create 100 materials, which will affect the GPU, but more important is the memory aspect, There will be a memory overhead of 100 materials, which is one of the biggest bottlenecks. So we introduced Perrenderdata's control of such a property, it can help you to put this data. For example: color colors, we do not need to draw them into the material, but through the render can be set.
Now let's talk about tags,tags specifying the rendering order, telling the engine how and when to render it. Unity provides us with some default render queues, each corresponding to a unique value, to guide unity drawing objects to the screen. These built-in render queues are called background, Geometry, alphatest, and these queues are not created casually, they are designed to make it easier for us to write shader and handle real-time rendering.
The following is a description of the queue:
Background: Queues are usually first rendered.
Geometry: The default render queue. It is used for most objects. This queue is used by opaque geometry.
Alphatest: The geometry of the channel check uses the queue. Unlike the geometry queue, it is more efficient for objects that are inspected by the channel being rendered after all the stereoscopic objects have been drawn.
We optimize the time for opaque objects do not need to draw from the back, for example: very far from the mountain or background, as background, the front as a geometry, in fact, the foreground should be drawn first, and then draw background.
Sometimes unity is rough, and more often than not, you need to control yourself. Translucent must be drawn from behind, and there are not too many ways to optimize it. Disablebatching recommends that you do not open, the default is not to open the situation.
Forcenoshadowcasting, for example: when we draw an opaque object, we need to replace the translucent object, but the translucent object does not have a shadow, you can change the shader code so that it does not cast a shadow, directly add forcenoshadowcasting to it.
Grabpass, we need to grab the buffer graph in two ways, as shown in.
The difference between the two ways is very obvious, the first way is relatively inefficient, because the grabpass call when it is bound to crawl the operation, so no time is different. But the following is more efficient, one frame is executed at most once, that is, the first use will be executed, and will not be executed later. This is based on the actual application of everyone to choose.
Render state, the previous direct write graphics program may be more concerned about how to set the rendering status, when it changes when we need to set, there is no change when how to deal with it?
This is how the unity engine handles the rendering state cache, which is intended to avoid frequent switching, as it will determine if the current state is the same as the previous state. If it is the same, you do not need to call the interface of the graphics API, because the interface calls also have a certain consumption. Then this can lead to an optimization point, if the rendering state of frequent switching, then does not play the role of optimization.
So when we write shader, try not to let these continuous, do not have too much rendering state, as far as possible to ensure that is less, so that the role of optimization is large. For example: AAA continuous and BBB continuous painting, this is more efficient than the rendering of ab interpolation.
Alpha testing, we know that on the mobile side, this is limited to the hardware limitations, try not to open, on the mobile side, it performance will be relatively low.
Color Mask, we also try not to open on the mobile side, this is fixed, we must remember, because now by the mobile limit, the PC side does not have this limit.
Surface shader optimization is more difficult, and here's what we can do? We can basically do these things. By default, surface shader actually turns on all the calculations, and we need to close or simulate some calculations to achieve an optimization goal.
The first is Approxview, which moves from view Direction normalized to vertex shader for calculation.
The second is Halfasview, is the use of light direction and angle of view direction of the intermediate vector instead of a perspective direction, if you compare the effect, think two kinds of comparison down almost, you can choose the effect of optimization.
Noforwarddadd, if there is only one pixel light, you can turn this option on.
Finally, the ambient light, we can turn off an ambient light, because after the turn off some optimization of the calculation, where the intensity of the optimization is relatively large, but the light loss is relatively large, if the effect can be accepted, you can turn it off.
Variant optimization is a more important point because many people think that shader is very memory-intensive, and it is possible to occupy hundreds of megabytes. Small words more than 20 trillion, to reach the hundred trillion is definitely not, then we need to check the reason, in the end what causes our shader become so big.
Unity provides another keyword, shader Feature, that only compiles the usage into the package, not the useless compilation inside. Multi_compile will produce all variants. When collecting variants, it is important to note that, using shader feature, we need to create materials to collect variations and materials that need to be serialized into the scene.
Finally talk about shader code optimization, I personally think it can optimize the space is not big, where is the space? We think about optimizing these final effects and wondering if the data really should go into the rendering pipeline? That's the point. After we get into the data optimization of the rendering pipeline, we do shader optimization is the icing on the cake.
First of all, is our CPU software cut efficient and correct? Of course we'll use Unity's cut function, or we can write it ourselves. When there is over draw, the rendering order can be re-optimized. For example: Does the shadow in the distance really need to be turned on? Can the resolution be a little bit smaller, the last full-screen effect to do the number of times, we talk about the number of bloom a lot, can you reduce some? Or the other full-screen effects can be concentrated once to finish it. These things we have been thinking about has optimized a lot of efficiency.
Finally, we may need to optimize for the code. So the code optimization we need to use some tools to do, Nvidia tools, iOS we will use Xcode, Android has many or Qualcomm provided tools we can use.
We have several highlights in code optimization:
We want to guarantee the effect of the premise, try to put the calculation in vertex Shader.
We try not to write multiple pass subshader.
We use LOD, we mesh with LOD, Texture has mipmap,shader also have LOD. The GPU performs two float multiplication and performs the multiplication efficiency of the two Vector4 is the same.
With fewer branches, and some built-in functions that don't suggest a custom implementation, we can use the provided functions that are optimized.
Finally, the accuracy problem, fixed,half, Float, different devices on its performance is not the same, we try to move the end of the use of some low-precision data. The three kinds of PC-side are no different.
The key content that Unity shader shader optimization needs to focus on is introduced here, and hopefully every developer can create a high-impact shader.
More Unity shader related content at Unity's official Chinese forum (unitychina.cn)!
Unity Shader Shader optimization