Unity3D直接渲染代码

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渲染代码实现的Windows编程风格好像看起来没有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
查看RenderToTexture渲染结果
后记:这个程序的功能很大一部分是通过窗口进行层混合操作,也就是大量的渲染到贴图,通过Unity3D引擎的摄像机和渲染到贴图很难进行节点可见范围管理,大量中间状态的可视化实体堆积在三维世界,效率也不高。

猜你喜欢

转载自blog.csdn.net/qq_31042143/article/details/112595272
今日推荐