Unity Native Rendering Scenario
3dimensions
This article is original content, reprint please indicate source.
The motive for doing this is to use Unity's material system to draw in native code, and to provide drawing data from the native code, eliminating the transfer of the dynamic model data "unmanaged memory → managed memory → unmanaged memory". For situations where there is a large number of dynamic model data generation, note that if you do not use Unity's material system, you do not need to do this. The plan was made by me at the suggestion of Miloyip.
First, the goal
In unity, the dynamic generation of three-dimensional models requires data to be filled into mesh objects, in which unity needs to allocate memory and make data transformations, which is inefficient. And if you want to write a unity native plugin to generate a three-dimensional model, the model data needs to pass through the "unmanaged memory → managed memory → unmanaged memory" transfer process, wasting a lot of memory bandwidth and time, especially every frame need to update the streaming data. So, we want to be able to bypass this data transfer process, direct native rendering. This article summarizes the native rendering scheme, with the goal of making the native plugin continue to use Unity's material system, and then generating the vertex data within the plug-in and submitting the Draw-call.
Second, the programme
The general idea is to have unity set up OpenGL drawing state, get these states in the native plugin and take advantage of them. This scenario does not take into account multi-threaded rendering and multi-step materials (Multi-Pass material) and is tested for open GL (Windows) and OpenGL ES (iOS and Android).
2.1 Time to enter native rendering--option a:gl.issuepluginevent
First we consider the use of Unity's gl.issuepluginevent, but this method still has problems, the test results on the PC show that through gl.issuepluginevent into the native rendering, some drawing resources (such as textures) have been unbound, The drawing state set in unity is broken. Therefore, this scenario is not feasible.
2.2 Time to enter native rendering-option B: Call native API directly
Another way is to set the material first in the unity script and then call the native plugin directly. First, call Material.setpass () in unity to set the material, but this command is not bound to be executed by unity immediately, and if you go directly into native rendering, you may find that the drawing state is incorrect. We found a viable way to draw a small grid immediately after calling Setpass (), and then the entire OpenGL drawing state was set correctly before invoking the native plug-in, the drawing state that was queried in the native renderer. Is the correct drawing state corresponding to the corresponding material.
2.3 How to leverage Unity's drawing state in native plugin
How to use Unity to set the drawing state, there are some differences between PC and Android:
- On a PC, after unity enters native rendering, the queried current shader name is 0, but this does not mean that the drawing state is broken and the correct results can still be drawn. We suspect that Drawmeshnow () has chosen to set the material to a fixed pipeline, which can only be exploited in a PC native rendering. The vertex properties of the OpenGL fixed pipeline are semantically, and the Gl*pointer interface is invoked in the native render to provide vertex data to submit the Draw-call.
- On Android, OpenGL ES 2.0 and later versions can use only programmable pipelines, and the semantics of vertex attributes are removed, and all vertex properties become generic. To provide vertex data for the current drawing state, query the current shader name in the native renderer and parse the shader's interface information. Unity has a relatively fixed naming format for vertex attributes that can be queried from the current shader to the location information based on these property strings. Call Glvertexattribpointer in the native renderer to provide the vertex data to the appropriate location, and then submit the Draw-call.
2.4 Participation in Unity's frustum cropping
In order for the native renderer to properly participate in the frustum clipping, we need the Gameobject setting in the native renderer and the same bounding box as the native geometry. The specific method is as follows. First, associate the renderer and Meshfilter on the gameobject that mount the native renderer. Then, at Monobehaviour.update (), the bounding box of the native geometry is read from the native renderer, and a mesh with the same bounding box is set to the Gameobject meshrenderer, and the mesh recalculates the bounding box Send Meshrenderer to recalculate the bounding box. Finally, when Onwillrenderobject () is recorded, the Gameobject is clipped by the frustum. At Onrenderobject (), the native renderer is called based on whether the crop was passed.
2.5 + cameras and multiple native calls
We tested the case of multiple cameras, and the native renderer was drawn correctly after Material.setpass (), which was followed by several primary calls.
2.6 Drawing Order
The rendering order of the native renderer is controlled by the layer of unity and the native renderer corresponds to a layer different from the scene's other objects, and the native renderer's layers correspond to separate cameras. The drawing order is determined between the cameras based on their depth properties.
Third, the performance of the native renderer
Tested a 4W particle's native particle system, the "Particles/alpha blended" built into unity. Test results:
Iv. Other Matters
4.1 Precautions
To give command-line argument-force-opengl when running unity on a PC, force the selection of OpenGL on the PC as the drawing API. The built-in material "particles/multipy" does not work correctly on the PC for reasons not specified. The OpenGL state is global and changes to the OpenGL state in the native renderer, except that the native renderer's own resources do not need to be released, and other changes such as Bind/unbind must revert back to unity when returning to the original state of the native renderer, which could cause a crash. Some problems encountered during the test, such as the Mali T604 driver will cause a memory leak after executing the draw-call, the driver will consume more than 1GB of memory after running for a period of time, leaving malloc with insufficient memory when allocating new space. This is not the case on other models and should be a driver problem.
4.2 Matters not considered
- The scheme summarized in this article does not consider the multi-step material (Multi-Pass material), the multi-step material situation is more complex, temporarily did not consider their participation in the native renderer method.
- Occlusion culling is not taken into account in this scenario.
- After you turn on multi-threaded rendering, this method may not get the correct results.
- Unity calls Drawmeshnow () to draw a network that needs to be hidden.
4.3 bu?er Object
Uploading data to the GPU there are some places to note that if Bu?er object is still being drawn when uploading new data, an implicit synchronization (implicit synchronization) may be thrown, waiting for the drawing to complete. By using multiple Bu?er objects, it is possible to reduce this overhead by looping between frames using a different Bu?er object. There are some performance gains when GPU loads are large, and the disadvantage is that it may increase the drive's memory footprint.
Unity Native Rendering Scenario