Unity3D直接渲染代码
通常Unity3D这种开发引擎是可视化编程,通过树形结构管理三维世界的节点,将实体模型绑定在节点,通过节点坐标组织三维模型的空间关系,通过摄像机节点进行透视投影计算,渲染可视化内容到2D屏幕空间。同时,摄像机也提供RenderToTexture的方法,让一部分三维世界渲染到贴图,再利用这个中间贴图渲染到目标空间,如实现汽车后视镜。
由于工作需要,要把以前的一个VC6工程移植到新版本*(VC6不支持64位编程,导致程序内存不足,目前应急处理办法是通过editbin /LARGEADDRESSAWARE xxx.exe编辑pe文件,突破win32程序2G内存限制,这种方法最多也就用到3G多内存)*,而VC6到任何一个版本的VS移植尝试,都需要处理非常多的编译错误和语法不兼容问题,索性不如直接移植到Unity3D,还可以享受可视化编程待遇。
要想用Unity3D实现C++的DirectX渲染管道代码功能,用引擎提供的节点和摄像机模式就太笨重了,需要更为底层的渲染方法。
C++实现的核心渲染代码:
Void CRenderToTextureWindow::OnUpdateSurface()
{
OnUpdateSurfaceBegin();
OnUpdateSurfaceDrawing();
OnUpdateSurfaceEnd(m_bDownloadToVideoTexture ? m_pDataTexture : Null);
CWindow::OnUpdateSurface();
}
OnUpdateSurfaceBegin实现渲染管道准备工作
Void CRenderToTextureWindow::OnUpdateSurfaceBegin(CTexture *pRenderTarget/* = Null*/, COLORREF color/* = 0x00*/, IDirect3DSurface9 *pD3DDepthStencilSurface/* =Null*/)
{
HRESULT hr = S_OK;
// Render video to texture
if (Null == pRenderTarget) {
pRenderTarget = m_pRenderTarget;
}
if (Null == pD3DDepthStencilSurface) {
pD3DDepthStencilSurface = m_pD3DDepthStencilSurface;
}
ASSERT(Null != pRenderTarget->GetSafeTexture());
m_pD3DTexture = pRenderTarget->GetSafeTexture();
m_pD3DTarget = Null;
m_pD3DBackSurface = Null;
m_pD3DBackDepthStencilSurface = Null;
D3D::GetD3DDevice()->GetRenderTarget(0, &m_pD3DBackSurface);
D3D::GetD3DDevice()->GetDepthStencilSurface(&m_pD3DBackDepthStencilSurface);
m_pD3DTexture->GetSurfaceLevel(0, &m_pD3DTarget);
D3D::GetD3DDevice()->SetRenderTarget(0, m_pD3DTarget);
D3D::GetD3DDevice()->SetDepthStencilSurface(pD3DDepthStencilSurface);
D3D::GetD3DDevice()->Clear(0, NULL, D3DCLEAR_TARGET/*|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL*/, color, 1.0f, 0);
D3D::GetD3DDevice()->BeginScene();
}
OnUpdateSurfaceEnd实现渲染管道结束后的扫尾工作
Void CRenderToTextureWindow::OnUpdateSurfaceEnd(CTexture *pDataTexture/* = Null*/)
{
HRESULT hr = S_OK;
D3D::GetD3DDevice()->EndScene();
D3D::GetD3DDevice()->SetDepthStencilSurface(m_pD3DBackDepthStencilSurface);
D3D::GetD3DDevice()->SetRenderTarget(0, m_pD3DBackSurface);
// download data target's data
if (Null != pDataTexture) {
LPDIRECT3DSURFACE pD3DDataSurface = Null;
pDataTexture->GetSafeTexture()->GetSurfaceLevel(0, &pD3DDataSurface);
if (FAILED(hr = D3D::GetD3DDevice()->GetRenderTargetData(m_pD3DTarget, pD3DDataSurface))) {
TRACE(DXGetErrorString(hr));
}
SAFE_RELEASE(pD3DDataSurface);
}
SAFE_RELEASE(m_pD3DTarget);
SAFE_RELEASE(m_pD3DBackSurface);
SAFE_RELEASE(m_pD3DBackDepthStencilSurface);
}
OnUpdateSurfaceDrawing实现子窗口遍历和渲染
Void CRenderToTextureWindow::OnUpdateSurfaceDrawing()
{
// RENDER CODE
this->SetRoot(True);
CWindow *pChild = FirstChild();
while (Null != pChild) {
if (pChild->IsVisibled() && pChild->GetRenderLevel() == GetRenderLevel()+1) {
GetApplication()->GetWindowsManager()->UpdateWindow(pChild);
}
pChild = NextChild(pChild);
}
this->SetRoot(False);
}
UpdateWindow函数进行窗口遍历和渲染
Void CWindowsManager::UpdateWindow( CWindow *pWindow )
{
...
pWindow->OnEraseBkgnd() ;
pWindow->OnUpdate() ;
// update child
CWindow * pChild = pWindow->FirstChild() ;
while ( Null != pChild ) {
CWindow *pNext = pWindow->NextChild( pChild ) ;
if ( pChild->IsVisibled()) {
UpdateWindow( pChild ) ;
}
pChild = pNext ;
}
pWindow->OnUpdateFrgnd() ;
pWindow->OnUpdateNcFrgnd() ;
}
CWindow::OnUpdate窗口渲染代码
Void CWindow::OnUpdate()
{
CRender *pRender = GetBkgndRender() ;
if ( Null != pRender ) {
pRender->SetAlpha( GetEnvironmentAlpha() ) ;
pRender->SetRenderOrigin( C2D(CPoint(0,0)) ) ;
pRender->Render() ;
}
}
C2DGridRender::Render渲染Mesh实体
Void C2DGridRender::Render()
{
if ( !IsVisibled() ) return; // donnot render if unvisibled
if (Null == m_pD3DVertexBuffer) {
return;
}
if (Null == m_pD3DIndexBuffer) {
return;
}
LPCUSTOMVERTEX pVertices;
if (SUCCEEDED(m_pD3DVertexBuffer->Lock(0, sizeof(CUSTOMVERTEX)*GetNumVertices(), (void **)&pVertices, 0))) {
memcpy(pVertices, &m_Vertices[0], sizeof(CUSTOMVERTEX)*GetNumVertices());
CMatrix4 mat = m_matRenderRect * m_matTransform;
// transform each vertices
for ( int i = 0 ; i < GetNumVertices() ; ++ i ) {
D3DXVec4Transform((LPD3DXVECTOR4)&pVertices[i].vector,
(LPD3DXVECTOR4)&pVertices[i].vector, mat);
pVertices[i].x += (float)m_ptOrigin.x;
pVertices[i].y += (float)m_ptOrigin.y;
}
m_pD3DVertexBuffer->Unlock() ;
}
CClipper *pClipper = GetApplication()->GetWindowsManager()->GetClipper();
OnBeginRender();
LPDIRECT3DDEVICE pD3DDevice = GetD3DDevice();
pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
pD3DDevice->SetTexture(0, m_pTexture1->GetSafeTexture());
pD3DDevice->SetStreamSource(0, m_pD3DVertexBuffer, 0, sizeof(CUSTOMVERTEX));
if (Null != m_pTexture2) {
pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE) ;
pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT) ;
pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE) ;
pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT) ;
pD3DDevice->SetTexture(1, m_pTexture2->GetSafeTexture());
}
// draw
pD3DDevice->SetIndices(m_pD3DIndexBuffer);
pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0,
0,
GetNumVertices(),
0,
GetNumFaces());
if (Null != m_pTexture2) {
pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
OnEndRender() ;
}
Unity3D引擎也提供了比较底层的渲染管道,可以通过渲染管道指令进行直接网格渲染。
移植后的渲染主逻辑
protected override void OnUpdateSurface()
{
base.OnUpdateSurface();
RenderTexture save = OnUpdateSurfaceBegin(targetTexture, Color.black);
OnUpdateSurfaceDrawing();
OnUpdateSurfaceEnd(save, null);
}
OnUpdateSurfaceBegin实现渲染管道准备工作
protected virtual RenderTexture OnUpdateSurfaceBegin(RenderTexture target, Color color)
{
GL.PushMatrix();
RenderTexture save = RenderTexture.active;
Graphics.SetRenderTarget(target);
GL.LoadPixelMatrix(0, target.width, 0, target.height);
CApplicationSetting.Instance.drawBuffer.Clear();
CApplicationSetting.Instance.drawBuffer.ClearRenderTarget(true, true, color);
Graphics.ExecuteCommandBuffer(CApplicationSetting.Instance.drawBuffer);
return save;
}
OnUpdateSurfaceEnd实现渲染管道结束后的扫尾工作
protected virtual void OnUpdateSurfaceEnd(RenderTexture save, Texture dataTexture)
{
GL.PopMatrix();
Graphics.SetRenderTarget(save);
// download data target's data
if (null != dataTexture)
{
}
}
OnUpdateSurfaceDrawing实现子窗口遍历和渲染
protected virtual void OnUpdateSurfaceDrawing()
{
// RENDER CODE
SetRoot(true);
for (int i = 0; i < transform.childCount; ++i)
{
CWindow child = transform.GetChild(i).GetComponent<CWindow>();
if (null != child && child.isActiveAndEnabled)
{
CApplicationSetting.Instance.UpdateWindow(child);
}
}
SetRoot(false);
}
UpdateWindow函数进行窗口遍历和渲染
public void UpdateWindow(CWindow window)
{
window.OnEraseBkgnd();
window.OnUpdate();
for (int i = 0; i < window.transform.childCount; ++i)
{
CWindow child = window.transform.GetChild(i).GetComponent<CWindow>();
if (null != child)
{
UpdateWindow(child);
}
}
window.OnUpdateFrgnd();
window.OnUpdateNcFrgnd();
}
OnUpdate窗口渲染代码
protected virtual void OnUpdate()
{
if (null != Backgnd)
{
Backgnd.Render();
}
}
Render渲染Mesh实体
public override void Render()
{
base.Render();
material.mainTexture = Texture;
material.SetPass(0);
if(Vector3.zero != m_Origin)
{
CApplicationSetting.Instance.drawBuffer.DrawMesh(mesh, Matrix4x4.Translate(m_Origin), material);
}
else
{
CApplicationSetting.Instance.drawBuffer.DrawMesh(mesh, Matrix4x4.identity, material);
}
Graphics.ExecuteCommandBuffer(CApplicationSetting.Instance.drawBuffer);
}
好像看起来没有Unity3D引擎的可视化编程了,其实不然,我们通过目录树和面板还是可以帮助我们理解运行过程的。
![可以查看运行数值,点击渲染贴图可以查看渲染结果](https://img-blog.csdnimg.cn/20210113224608321.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxMDQyMTQz,size_16,color_FFFFFF,t_70
后记:这个程序的功能很大一部分是通过窗口进行层混合操作,也就是大量的渲染到贴图,通过Unity3D引擎的摄像机和渲染到贴图很难进行节点可见范围管理,大量中间状态的可视化实体堆积在三维世界,效率也不高。