上篇已經能在VR中畫出來了, 但是還存在兩個問題:
1. 透明物體會被Native畫的東西擋住
2. VR中Native畫的東西透視關係有點問題, 跟Unity繪製的場景不能很好地融合在一起
先來解決一個透明排序的問題, 這個問題有兩個思路去解決:
雙Camera
雙Camera的思路就是, 一個Camera只畫不透明物體, OnPostRender中回調Native Renderer, 另一個Camera只畫透明物體. 這樣Native的繪製就能在兩者之間進行, 有幾個細節:
- 先保證兩個Camera的參數一樣
- 第一個Camera的Culling Mask把TransparentFX去掉
- 第二個Camera的Culling Mask只保留TransparentFX
- 所有透明物體設置layer爲TransparentFX
- 第二個Camera的Clear Flags設置爲Don’t Clear, 這樣兩個Camera的畫面才能結合到一起
- 第二個Camera的Depth設置成比第一個Camera大, 代表後畫
插入CommandBuffer
Unity5.2在CommandBuffer入加入了調用NativeRenderPlugin的支持, 這就可以讓我們可以在渲染管線的各個階段之前插入我們想要的效果. 具體到我們的需求, 可以簡化爲:
private CommandBuffer commandBuffer;
void Start()
{
SetUnityStreamingAssetsPath(Application.streamingAssetsPath);
commandBuffer = new CommandBuffer();
commandBuffer.IssuePluginEvent(GetRenderEventFunc(), 1);
camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);
GetComponent<MeshFilter>().mesh.bounds = new Bounds(Vector3.zero, Vector3.one * 1000);
}
void OnWillRenderObject()
{
// Set time for the plugin
SetTimeFromUnity(Time.timeSinceLevelLoad);
if (Camera.current != null)
{
var viewMatrix = Camera.current.worldToCameraMatrix;
var projectionMatrix = GL.GetGPUProjectionMatrix(Camera.current.projectionMatrix, VRSettings.enabled);
SetCameraMatrix(viewMatrix.toFloatArray(), projectionMatrix.toFloatArray(), VRSettings.enabled);
}
}
一個細節, OnWillRenderObject必須在有Mesh時纔會調用, 所以這裏掛了個Box到NativeRender的GameObject上, 並把包圍盒設置成非常大, 一方面保證了SetCameraMatrix可以一直調用到, 另一方面也能”隱藏”掉這個Box(內部看經過back face culling是不可見的).
相對於雙Camera的做法省去了爲透明物體設置layer mask的工作, 也更爲靈活和高效.