Mar 17 2007
MD3DM: Onde foram parar meus Meshes?
Dando continuidade à série de posts sobre o meu Trabalho de Conclusão de Curso, vou escrever hoje sobre um erro muito comum que qualquer iniciante pode cometer quando for desenvolver utilizando o .NET CF 2.0 e o Managed Direct3D Mobile.
Para maiores informações sobre o assunto, veja meus outros posts aqui.
- O problema
Em todos os exemplos que desenvolvi até agora, sempre carreguei os objetos a serem desenhados dentro do método Render(), que é chamado no OnPaint() (saiba mais sobre esse conjunto de métodos aqui). Em outras palavras, quando era preciso desenhar, eu criava os objetos e desenhava. Ok, sem problemas à primeira vista, mas e a performance? E se os objetos forem gigantes, vindos de arquivos fonte, que é ainda mais demorado para ler e carregar todas as informações na memória do dispositivo?
Solução: carregar os objetos no início da aplicação e mantê-los em memória para que na hora da renderização não seja necessário carregar coisa alguma. Certo? Errado!
A implementação sugerida acima fica desta maneira:
- Inicialização do Device e do objeto a ser desenhado (Mesh)
private void InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Discard; // Device device = new Device( 0, DeviceType.Default, this, CreateFlags.None, presentParams); device.RenderState.CullMode = Cull.None; device.RenderState.Lighting = false; mesh = Mesh.Box(device, 1, 1, 0); } catch (Exception ex) { MessageBox.Show("Erro na inicialização: " + ex.Message); } }
- Renderização do Mesh
/// <summary> /// Render the data /// </summary> private void Render() { // Clear the device device.Clear(ClearFlags.Target, Color.White, 1.0f, 0); // Begin the scene device.BeginScene(); mesh.DrawSubset(0); // End the scene and present device.EndScene(); device.Present(); }
A princípio não há problema algum nessa implementação. Porém, ao executá-la a seguinte exception (System.ObjectDisposedException) é lançada na chamada do método mesh.DrawSubset(0):
- A Solução
Ao invés de criar o objeto Mesh logo após a criação do Device, devemos criá-lo quando o Device é reiniciado.
Por que hããm? Pois antes de renderizar as informações, o Device é reiniciado e perde todas as definições que o Mesh tinha quando foi criado.
Como resolver este problema? Simples:
- Alterar a criação do device (repare no evento OnDeviceReset)
private void InitializeGraphics() { try { PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Discard; // Device device = new Device( 0, DeviceType.Default, this, CreateFlags.None, presentParams); device.RenderState.CullMode = Cull.None; device.RenderState.Lighting = false; device.DeviceReset += new EventHandler(OnDeviceReset); } catch (Exception ex) { MessageBox.Show("Erro na inicialização: " + ex.Message); } }
- Criar o Mesh quando o Device for reiniciado
protected void OnDeviceReset(object sender, EventArgs e) { mesh = Mesh.Box(device, 1, 1, 0); }
Discretamente vou dar um palpite da origem do erro: todas as informações do Mesh (VertexBuffer, IndexBuffer, etc) ficam na memória do Device. Assim que é reiniciado essas informações são apagadas, conforme descrito em um post anterior.
É isso ae! Até +.







