In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail how Unity uses Fast Shadow Receiver to optimize rendering efficiency. The content of the article is of high quality, so the editor will share it with you for reference. I hope you will have some understanding of the relevant knowledge after reading this article.
1. cause
There have been many posts about dynamic shadows in Unity.
Whether it is the simplest scheme based on Planar projection or slightly "old-fashioned" Projector scheme, and even the current mainstream ShadowMap scheme actually has its own advantages and disadvantages and corresponding application scenarios, the principles and differences between them are not the focus of this article, interested students can easily find relevant papers or blogs to see.
Our project insists on using Unity's native ShadowMap to make dynamic shadows with the idea of not repeating the wheel. And UWA has also done some dynamic shadow program efficiency comparison, their own wheels can do better than the official source code is not much, not to mention our surface ups and downs, high-end need to support multi-character dynamic shadow of the "large" MMORPG game, ShadowMap is already the most suitable solution.
However! There will always be however, otherwise it will be too insipid and tasteless, isn't it?
About a month ago, I discovered this problem-"the conflict between static batch and Shadowmap macro settings in Unity". To put it simply, static batch first sorts scene objects to ensure correct results, but when dynamic shadows are introduced, macros that accept shadows are modified (this is also an optimization, because of the consumption of sampling and shadow calculation, it is more efficient to turn off the drop macro shader) As a result, the originally sorted objects can not be grouped normally, because the macros of the shaders are different, resulting in a lot of increase in the Batch value that can be very low in theory after the static batch, which greatly reduces the efficiency of scene rendering.
After thinking clearly about the reason, I felt that there was no particularly simple optimization solution on the premise that I still wanted to use Unity's ShadowMap, so I shelved it for the time being until last week when I made a quantitative test on the frame rate of the various effects of the game on the real machine, I found that the problem was far more serious than expected.
Quantitative test results of the effect of each effect on frame rate
The above test is carried out on the middle-equipped Xiaomi Max2, we can see that whether the shadow is on or off or not leads to a difference in the time consumption of a frame with or without 9.5ms, which has the greatest impact of all the effects! However, the rendering consumption of ShadowMap itself should not be so different. After observing the difference in the number of Batch, the number of Batch in simple scenes will increase from 25 to about 150, which is a bit beyond our previous art specifications.
Under the matching effect, only the protagonist turns on dynamic shadows, so the initial idea is to introduce another shadow rendering scheme, such as Dynamic Shadow Projector, to draw shadows specifically for the protagonist. Although I personally dislike using two sets of technical solutions at the same time, it seems that this is the only option without reducing the effectiveness.
2. Dynamic Shadow Projector plug-in
This simple Unity asset provides a few components to render a shadow onto a render texture so that the render texture can be used with Blob Shadow Projector. Blob Shadow Projector is usually used for dropping a round blurry shadow which is not suitable for a skinned mesh object. This asset enables a projector to drop a dynamic shadow which is perfect for skinned mesh objects.
The principle of the Dynamic Shadow Projector plug-in is relatively simple: draw the character's shadow onto a rt, then use the Projector component of Unity to use the rt as the drawing input, and draw the object that accepts the shadow again. The rt of shadows is updated every frame, which makes it possible for animated characters to change their shadows in real time.
Try it, or relatively easy to use, several components can be correctly set up to see the effect, because it is for a single role, so the use of smaller rt can do more fine than shadowmap effect, but if you want a projector to deal with multiple roles, once you expand the scope of projector, the shadow effect quality decline is even more severe than the shadowmap method.
Rt utilization and shadow quality in the case of 128-128 rt projecting only one Cube
512-512 rt projection of three Cube in the case of rt utilization and shadow quality
The above two figures show the comparison of the effects of using a Projector to project a single character and multiple characters. In the following figure, the distance between the three Cube is not far apart, but even with the use of 512-512 rt, you can obviously see that the shadow has a sense of aliasing, and the aliasing is more serious when the distance is greater.
So why am I obsessed with wanting to use one Projector for dynamic shadow rendering of multiple characters? Because for each Projector, when drawing shadows, you need to completely reproduce the model that accepts shadows. From the screenshot below, you can see that the three Cube use three different Projector, and the surface plane needs to be drawn three times. In fact, this is why Projector's method is not suitable for dynamic shadow rendering of multiple objects on mobile devices.
Draw frame capture screenshots of the surface that receives shadows when using multiple Projector
Our surface is made of Terrain, and the number of triangles converted to Mesh is generally at the level of several thousand, and the increase in the overall number of faces is still considerable, although in our matching, only the protagonist accepts the dynamic shadow, so we only need to draw the surface model once more, and it is cost-effective enough in theory to exchange the consumption of Draw Call and thousands of faces for the reduction of 100 + Batch, but I am not reconciled to it. So I want to try the Fast Shadow Receiver plug-in recommended by Dynamic Shadow Projector with "taking".
3. Trial of Fast Shadow Receiver
The Fast Shadow Receiver plugin is a plugin that I followed a long time ago, and Qian Kanglai also mentioned it in his blog. I have always maintained a far-away mentality, first, because from experience, ShadowMap did not accept the shadow side of the need to redraw the problem, but macro changes, efficiency should be quite high (did not expect to affect the Static Batching); second, for the run-time violent reconstruction of mesh has been skeptical, worried about the additional pressure on CPU and memory.
I bought the plug-in, introduced it into my own local project project, and after playing Demo, I tried to use it with Dynamic Shadow Projector. Like the comments on AssetStore about this plug-in, the documentation of this plug-in is indeed somewhat obscure. It took about three or four hours to officially run through the whole process in the game. Without going into details, a few potholes are recorded:
It may be that the official complained that the document is too difficult to read, so I made a set of Wizard to teach you how to configure it step by step, but I didn't get the correct result after I followed the steps. Instead, because Wizard hides some of the setting steps behind it, I can't understand the process correctly, so it's hard to find out the reason. And Wizard is aimed at specific needs, not necessarily the effect I want. In the end, I will configure the results one by one according to the components in the Demo project.
LayerMask setting should be noted that in order to optimize efficiency, there is an Igore Layers setting on the Projector component, and on Draw Target Object, there is also a LayerMask setting to identify which Layer will be drawn under the node to be drawn, and the final ShadowReceiver component will also belong to a certain Layer, such as the default Default. If there is something wrong with the setting of these Layer, it will cause no shadow to be drawn eventually. I spent an extra hour debugging various parameters because of the mistake here. If you encounter strange problems in use, you can comb through the various Layer you have set up to ensure logical correctness. One of my problems at the time was that the GameObject where ShadowReceiver was located was classified as Default Layer, while Projector Igore lost Default Layer, resulting in incorrect results.
It is estimated that the plug-in makers of Fast Shadow Receiver have not experienced the baptism of Chinese art, and apart from the obscure documentation, the compatibility of fault tolerance in the code has not been fully considered. There are thousands of objects in our scene. During the initial test, we didn't try to mark all the objects that accepted shadows on the surface. We simply tagged all the objects. As a result, there has been a problem in the generation of MeshTree. We checked it because there is a GameObject in our scene where the Mesh object is in the state of miss. Just do some compatibility. Of course, basically we need art to fix the problem of mesh miss.
In short, after a series of attempts, we finally use formal art resources to run through the whole process in our own project, and we also have a deeper understanding of the principle of Fast Shadow Receiver: it uses MeshTree, a class inherited from Scriptable, to precalculate and store the surface grid information that needs to accept shadows in the offline phase, and provides three types of BinaryMeshTree, OctMeshTree and TerrainMeshTree to deal with different scenarios. At run time, it provides components such as MeshShadowReceiver, which calculates the patches that need to be covered where the shadow is accepted in real time according to the settings of Projector, and generates a new mesh as the mesh object of the shadow receiver to render, so that the original model of thousands of faces can be drawn with only dozens of faces, because after all, only part of the area in front of the lens needs to be drawn with dynamic shadows.
Screenshot of the example in Demo of Fast Shadow Receiver
4. Integration and integration with ShadowMap
The original idea was to use Projector-style dynamic shadows for individual protagonists, and then optimized with Fast Shadow Receiver. I didn't think much about it when I saw Fast Shadow Receiver supporting ShadowMap in Demo. Later, when discussing this issue with my colleagues, I talked about the advantages and disadvantages of Projector's dynamic shadow scheme and ShadowMap's dynamic shadow scheme. I was asked if it was possible to make a combination of the two schemes, and then remembered that I saw an example of using Fast Shadow Receiver to optimize ShadowMap in Demo. It is also entangling the effect in the medium configuration in our pull-out battle. If we use Projector, whether it is cost-effective to draw more rt, then if we can use Fast Shadow Receiver combined with the previous Shadow Map scheme, the change to the current structure is minimal, and there is no need to introduce a second set of dynamic shadow generation scheme, which is only equivalent to using a new plug-in to solve the static batch problem of the scene. This seems to be a very ideal scheme.
Along this line of thinking, I learned the example of ShadowMap in Fast Shadow Receiver, which also looks very simple. In the case of understanding the principle, just change the Receive Shadow attribute of other Render components in the scene to false, and then only let a patch generated by Fast Shadow Receiver read the generated ShadowMap to draw shadows, thus adding an additional Draw Call and dozens of faces to render consumption, you can achieve a similar effect as before, and the switching logic of medium-to-high configuration is more concise.
Let's first take a look at the final revised production steps, and then talk about some of the design details.
Uniformly place Mesh-related components in the scene under the same GameObject. Originally, there is no rigid rule. It all depends on the consciousness of the field editor. In fact, after finishing, the Hierarchy panel in Unity will also be more clean and tidy.
The scene Mesh is uniformly placed under the ArtRoot root node.
Mark objects that accept shadows. This step is a bit of a trivial task, which requires art to mark which objects receive shadows. BinaryMeshTree preprocesses the mesh based on these marked objects. Too few marked objects will appear that the objects that should accept shadows have no shadow effect, while too much will lead to too much data content in BinaryMeshTree, slow loading, reduced retrieval speed, and high memory consumption. Since we are currently only used in this part, only the surface and obvious objects are required to be added to the mark. Fast Shadow Receiver only supports Layer and RenderType filtering methods, and some objects in our scene have been marked with other logical Layer, so I modified this point by adding Tag filtering and Mask Layer take-OR processing, and provided convenient shortcut keys for quick tagging for art. I tested it myself, and the time required for tagging and verification for our in-game scenarios ranges from about half an hour to two hours.
Provide Tag of FastReceiver for annotation
Create a BinaryMeshTree. We finally chose to use the BinaryMeshTree structure, and the difference between it and OctMeshTree is shown in the figure below. In fact, more tests are needed to compare this step, because officials also specify exactly what the boundary between small and large is.
Comparison of two different MeshTree
The process of creating a BinaryMeshTree is also simple, and the plug-in provides support for right-click Create menus:
Create BinaryMeshTree
Generate Mesh Tree. After tagging the objects that receive shadows, you can select the created BinaryMeshTree, fill in its Root Object as the root node of the scene, and set the Layer for build. We recommend that the build information given after the final creation of the art check should take up less than 2m of memory, which is an empirical value after editing several scenarios, and more verification is needed.
Configuration of Layer when Mesh Tree is generated
Mesh Tree Information Statistics after Build
Configure Projector and Mesh Tree information. In this part, in order to simplify the configuration of art, most of the configuration logic is written in the code. You only need to copy a copy of prefab and set the newly created Mesh Tree information correctly. It is important to note that this prefab is not retained in the scene and will be deleted from the scene after editing the Apply.
Create BinaryMeshTree
Only two components are used here, one is the LightProjector component on the LightProjector object in the figure, which is used to set the directional light object used by the shadow and some Projector parameters, such as the following Target object and the extended Bound range, etc. The other is the MeshShadowReceiver component, which associates Mesh Tree data, the root node and Projecter object of the scene rendering object, and some attributes such as Fast ShadowReceiver clipping and updating can also be set here.
Add and configure the Shadow Receiver Controller component on the resource root node. This component is implemented by ourselves and is used to control the switch of Fast Shadow Receiver. It will set Fast Shadow Receiver in the logic of scene loading and game configuration switching according to the game configuration. And based on this component, the lazy loading function of Mesh Tree is realized.
Shadow Receiver Controller component configuration
Test in the running state of the game. After the above configuration is completed, you can see the optimized shadow effect under the medium configuration of the game logic, and you can test the running game.
Most of the details have been described in the above steps, and here are the following:
A) Projector and MeshShadowReceiver components are not placed in the scene by default. This is because when there are many surface objects, there is time to load Mesh Tree (encountered a test example, the size of Mesh Tree is about 18m, need more than 5s on PC, the specific reason is not examined in detail), there will also be additional memory consumption, so on the one hand, it is recommended that art ensure that the file is not very large, on the other hand, through Lazy Load, it is only loaded when needed. To ensure that in the case of high and low configuration, there is no need for any additional CPU and memory overhead.
B) provide more convenient tools for art to mark information. As marking the surface is a relatively trivial task, it takes a lot of time and effort to verify whether the marking is reasonable. In addition to the previously mentioned shortcut keys can be marked with one button, it is also recommended to quickly check and locate the problem through the explicit and hidden function of Layer and the explicit and hidden function of Tag developed by ourselves.
Native Layer filtering capabilities of Unity
5. Optimization result and cost
Using the same test method, compare the frame rate and time consumption of the game before and after optimization:
Comparison of performance consumption before and after optimization
As you can see, there is about an improvement in 7.2ms performance on Xiaomi Max2 using Fast Shadow Receiver, with the frame rate rising from 26 to 33, thanks to the reduction in the number of Batch, and there should also be scene objects that do not need to sample ShadowMap maps to improve rendering performance, and more specific data are not tested. The remaining time consumption of 1.5ms includes the rendering of ShadowMap and the update consumption of Fast Shadow Receiver, which is the subsequent optimization object, but this optimization has been greatly improved. The overall efficiency of the configuration has been improved by 20%, which is a rare "magic optimization". Of course, this is based on the premise that the scene can reduce the large number of Batch by turning off the macros received by Shadow.
The benefits of this optimization are great, but it is not all a lossless optimization, and the costs are as follows:
The workload of art. Art students are required to label the surface receiving shadow objects for the scene, although it provides a quick tool, but it still takes some time and cost.
Some objects are no longer affected by dynamic shadows. In the previous ShadowMap-based scheme, almost all objects can be marked to receive shadows, and the correctness of the effect can be guaranteed, but at present, if this is to be done, Mesh Tree will take up more memory and will not adapt to the external big-world scene, so there will be some problems that objects such as small stones will not receive character shadows, which is a reduction of some effects. But at present, it seems to be within the acceptable range.
The fusion of and static shadows is different from ShadowMap's scheme. ShadowMap's scheme is processed when the scene is drawn. Lightmap and shadowmap maps are sampled in the process of pixel shading, which can determine whether the pixel is in a static shadow, so that in static shadows such as under eaves or trees, the character's real-time shadow can be well integrated with static shadow, as shown in the following figure.
Fusion effect of dynamic Shadow and static Shadow based on ShadowMap
After using the Fast Shadow Receiver scheme, it is more difficult to do the fusion effect, unless the uv2 information of the previous mesh and the lightmap mapping information used are saved in the newly generated mesh, and then the lightmap is sampled again. But this is troublesome and cost-effective, so the effect of the dynamic shadow of a character in static invisibility becomes as shown in the following figure.
The effect of using Fast Shadow Receiver scheme
In addition to these, the price is that it took more than half a week for the program to learn and integrate this solution, but from the optimization results, it is still very rewarding and worthwhile.
6. One Projector handles dynamic shadows of multiple characters at the same time
Because we are similar to the turn system of pull-out combat, that is, after the player enters the battle, the whole battle will occur in a small fixed area, here is actually a very suitable application scenario for ShadowMap combined with Fast Shadow Receiver-you only need to generate a shadow receiving patch before entering the battle, and there is no need to modify or change it throughout the battle!
We locked LightProjector's Target as the central area of the battle, and then expanded its projection to the entire battlefield by modifying the Bound. One of the problems discussed earlier in the dynamic shadow scheme based on Projector is that when the projector is large, the utilization rate of rt is low, which leads to a sharp drop in shadow quality, but because we are using ShadowMap's shadow scheme, expanding the scope of Projector will not affect the shadow accuracy, and there is no need to deal with the number of rt and the increase of draw call caused by multiple Projector.
A scheme in which multiple characters share a single LightProjector in a battlefield
7. Summary and prospect
Fast Shadow Receiver, which uses real-time computing of CPU in exchange for the rendering performance of GPU, just solves the problem that our scene is interrupted by dynamic shadows, greatly improves the frame rate of our game, and is the most effective one of the recent optimizations, so record the detailed process and share it here.
The feeling of this plug-in has changed from skepticism to sincere admiration in the process of getting familiar with, applying and modifying this week. At present, there are not many magic changes for this plug-in, in addition to the aforementioned increase of Tag support, the lack of some wrong compatibility for resources when establishing Mesh Tree, only some of the default parameters of Component have been modified, which is more suitable for the settings of our project, so that art and programs can be used more easily. We are also satisfied with the memory allocation and CPU performance consumption at runtime, so here is also an advertisement for this plug-in-don't be intimidated by its documentation and usage process. After using it, your game efficiency can be greatly improved.
As for the future, after the effect and efficiency have been verified to be acceptable, you may consider optimizing some of its effects and applying it to high configuration, of course, for places such as decals that need to deal with uneven ground effects, you can also consider using this plug-in for efficiency optimization.
PS: think about the problem that the static combination of scenes is interrupted from the inspiration of Fast Shadow Receiver. In fact, another idea is to make your own judgment about which objects need to be shaded. There must be such decision logic in Unity to set the macros of each scene Render. Because the distance setting of Shadow is relatively large, and the scope of Unity decision is too wide, although we only have characters to render shadows in the configuration, there are too many objects that receive shadows, resulting in frequent interruptions of Batch. Mimic Fast Shadow Receiver, using a projection that follows the character and intersects the scene objects to determine which objects need to be set to receive shadows, and since there may be only a few objects under the character's feet, the number of Batch will only increase by a few. At present, one of the reasons why we do not follow this idea is that the number of faces of surface objects is a little too large, and the reduction of the number of faces in Fast Shadow Receiver is also one of the optimizations we want.
So much for sharing about how Unity uses Fast Shadow Receiver to optimize rendering efficiency. I hope the above content can be of some help and learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
Procedure TForm1.WebBrowser1BeforeNavigate2 (ASender: TObject;const pDisp: IDispatch; var URL, Flags
© 2024 shulou.com SLNews company. All rights reserved.