Gráficos 3D com DirectX: Modelagem e Renderização de Objetos

Modelagem de Objetos

Para desenhar objetos tridimensionais em um espaço plano, é necessário primeiro obter o modelo do objeto nos eixos coordenados X, Y e Z. Isso significa que cada ponto na superfície do objeto deve ser definido por coordenadas específicas. Idealmente, seria necessário definir infinitos pontos na superfície do objeto para manter a qualidade durante o zoom. Na prática, a modelagem 3D é feita utilizando malhas compostas por polígonos. Quanto mais pontos extremos um polígono possui, mais detalhada é a malha e mais realista o modelo se torna. No entanto, calcular e renderizar modelos e gráficos 3D assim requer mais recursos computacionais.

Gráficos de computação antigos precisavam funcionar em placas gráficas mais fracas, o que levou à divisão de polígonos em triângulos há muito tempo. Triângulos podem descrever com precisão a posição de pequenas superfícies e calcular parâmetros relacionados, como iluminação e reflexão de luz. Uma coleção desses pequenos triângulos pode criar imagens tridimensionais realistas de objetos. A partir de agora, polígonos e triângulos serão tratados como sinônimos, pois é mais fácil visualizar triângulos do que polígonos com N vértices.

A criação de um modelo tridimensional de um objeto é feita definindo as coodrenadas de cada vértice do triângulo. Dessa forma, mesmo que o objeto se mova ou a posição do observador mude, é possível calcular as coordenadas de cada ponto do objeto. Portanto, lidamos com vértices, as arestas que os conectam e as superfícies formadas por essas arestas. Se a posição do triângulo for conhecida, podemos usar as leis da álgebra linear para criar normais de superfície (uma normal é um vetor perpendicular à superfície). Assim, podemos calcular como a superfície é iluminada e como a luz é refletida por ela.

Criação de Modelos

Vamos escrever um programa simples para criar um cubo. Usaremos a classe CCanvas3D da biblioteca de gráficos 3D.

A classe CCanvas3DWindow para renderizar a janela 3D possui membros e métodos mínimos. Gradualmente adicionaremos novos métodos e explicaremos os conceitos de gráficos 3D implementados nas funções DirectX.


//+------------------------------------------------------------------+
//| Classe de formulário de aplicação                                 |
//+------------------------------------------------------------------+
class CCanvas3DWindow 
{
protected:
    CCanvas3D m_canvas;  // Canvas
    //--- Dimensões do canvas
    int m_width;
    int m_height;
    //--- Cubo
    CDXBox m_box;
    
public:
    CCanvas3DWindow(void) {}
    ~CCanvas3DWindow(void) {m_box.Shutdown();}
    
    //--- Criação da cena
    virtual bool Create(const int width,const height){}
    //--- Cálculo da cena
    void Redraw(){}
    //--- Resposta a eventos do gráfico
    void OnChartChange(void) {}
};

A criação da cena começa com a criação do canvas. Em seguida, definimos os seguintes parâmetros para a matriz de projeção:

  1. Visão de 30 graus (M_PI/6), de onde observamos a cena 3D
  2. Proporção (taxa de largura para altura)
  3. Distância do plano de corte próximo (0.1f) ao distante (100.f)

Isso significa que apenas partes do objeto que estão entre duas paredes fictícias (0.1f e 100.f) serão renderizadas na matriz de projeção. Além disso, o objeto deve estar dentro do ângulo de visão horizontal de 30 graus. Observe que distâncias e todas as coordenadas em gráficos de computação são fictícias. O importante é a relação relativa entre distâncias e tamanhos, não os valores absolutos.


//+------------------------------------------------------------------+
//| Método de criação                                                |
//+------------------------------------------------------------------+
virtual bool Create(const int width,const int height) 
{
    //--- Salvar dimensões do canvas
    m_width = width;
    m_height = height;
    
    //--- Criar canvas para renderização de cena 3D
    ResetLastError();
    if(!m_canvas.CreateBitmapLabel("Exemplo 3D",0,0,m_width,m_height,COLOR_FORMAT_ARGB_NORMALIZE)) 
    {
        Print("Erro ao criar canvas: ",GetLastError());
        return(false);
    }
    
    //--- Definir parâmetros da matriz de projeção - visão, proporção, distância dos planos de corte próximos e distantes
    m_canvas.ProjectionMatrixSet((float)M_PI/6,(float)m_width/m_height,0.1f,100.0f);
    
    //--- Criar cubo - passando coordenadas de dois vértices opostos, gerenciador de recursos e parâmetros de cena
    if(!m_box.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),DXVector3(-1.0,-1.0,5.0),DXVector3(1.0,1.0,7.0))) 
    {
        m_canvas.Destroy();
        return(false);
    }
    
    //--- Adicionar cubo à cena
    m_canvas.ObjectAdd(&m_box);
    
    //--- Atualizar cena
    Redraw();
    
    //--- Sucesso
    return(true);
}

Após a criação da matriz de projeção, podemos prosseguir com a construção do objeto 3D - um cubo baseado na classe CDXBox. Para criar um cubo, basta especificar dois vértices opostos do cubo. Ao observar a criação do cubo no modo de depuração, você pode ver o que acontece na função DXComputeBox(): todos os vértices do cubo são criados (suas coordenadas são gravadas na matriz "vértices") e as arestas do cubo são divididas em triângulos, listadas e salvas na matriz "índices". O cubo tem um total de 8 vértices, 6 faces divididas em 12 triângulos, esses índices de vértices do triângulo são listados como 36 índices.

Embora o cubo tenha apenas 8 vértices, 24 vértices são criados para descrevê-los porque é necessário especificar um conjunto separado de vértices para cada normal das 6 faces. A direção da normal afeta o cálculo da iluminação de cada face. A ordem de listagem dos vértices do triângulo nos índices determina as bordas visíveis do triângulo. O código em DXUtils.mqh mostra a ordem de preenchimento de vértices e índices:


//--- Normais para as faces inferiores
for(int i=20; i<24; i++)
    vertices[i].normal=DXVector4(0.0,-1.0,0.0,0.0);

No mesmo código, as coordenadas de textura são definidas para o mapeamento de textura de cada face:


//--- Coordenadas de textura
for(int i=0; i<faces i="" vertices=""></faces>

Cada um dos 4 vértices da face tem 4 coordenadas de mapeamento de textura definidas. Isso significa que cada face do cubo, ao renderizar a textura, mapeará uma pequena estrutura. Claro, isso só é necessário quando uma textura é definida.

Tags: DirectX gráficos 3D modelagem 3D renderização programação C++

Publicado em 6-27 07:27