| 
         Written by Robert
        Dunlop 
        Microsoft DirectX MVP  | 
        | 
     
   
  
 
  
Setting up the Landscape
  
Measuring Height at Arbitrary Locations
For purposes such as collision detection and terrain following, it is 
necessary to be able to determine the height (Y) for a given point (X,Z) on the 
terrain.  Rather than having to perform a mesh intersection test, getting 
the height at an arbitrary point is simply a matter of determining which quad 
the point is in, then calculating the height at that point in the quad: 
  
  
    | 
     See
    Listing 4 for the CalcQuad() 
    function called in this listing 
     | 
   
    
    
     
    float CAppForm::CalcHeight(float x, float z) 
    { 
    // offset to base 
    x-=m_vQuadBase.x; 
    z-=m_vQuadBase.z; 
     
    // normalize to quad size 
    x/=m_fQuadSize; 
    z/=m_fQuadSize; 
     
    // get integer part 
    int row=(int) z; 
    int col=(int) x; 
     
    // return if out of range 
    if (row<0||row>=m_numSplines-3||col<0||col>=m_numSplines-3) { 
        backCol=0x00ffff00; 
        return 0.0f; 
    } 
     
    // get fractional parts 
    x-=floorf(x); 
    z-=floorf(z); 
     
    // calculate and return quad height 
    return m_vQuadScaling.y 
           * 
    CalcQuad(x,z,&splineMat[row][col]) 
           + m_vQuadBase.y; 
    } 
  | 
     
    
    | 
     Listing 10  | 
     
   
 
Rendering the Landscape
Before rendering the landscape, we will first perform the following 
initializations: 
    | Set up D3D to render from our vertex and index buffers |  
    | Set D3D to use our programmable vertex shader |  
    | Combine and transpose the world, view, and projection matrices and set as 
  a vertex shader constant |  
    | Set a vertex shader constant to a vector defining the patch scaling. |  
 
These steps are shown in Listing 11, below: 
  
    
    
     
    m_pd3dDevice->SetIndices(m_pIB,0); 
    m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(SPLINEVERTEX) ); 
    m_pd3dDevice->SetVertexShader(m_hVertexShader); 
    D3DXMATRIX mat,matViewWorld; 
    D3DXMatrixMultiply( &matViewWorld, &m_matWorld, &m_matView); 
    D3DXMatrixMultiply( &mat, &matViewWorld, &m_matProj); 
    D3DXMatrixTranspose( &mat, &mat ); 
     
    // shader input : c0-c3 = world/view/proj matrix 
    m_pd3dDevice->SetVertexShaderConstant( 0, &mat, 4 ); 
     
    // shader input : c4 = patch scaling 
    m_pd3dDevice->SetVertexShaderConstant( 4, &m_vQuadScaling, 1 ); | 
     
    
    | 
     Listing 11  | 
     
   
 
The landscape is then rendered by repeatedly drawing the same vertex buffer, 
applying different vertex shader constants each time to set the patch shape, 
lighting, and location: 
  
    
    
     
    // loop through the patches 
    for (int i=0;i<m_numSplines-3;i++) { 
     
    float baseZ=m_vQuadBase.z+i*m_fQuadSize; 
     
    for (int j=0;j<m_numSplines-3;j++) { 
     
        // shader input : c5 = starting 
    location 
        float 
    baseX=m_vQuadBase.x+j*m_fQuadSize; 
        
    m_pd3dDevice->SetVertexShaderConstant(5, 
                                              
    &(D3DXVECTOR4(baseX, 
                                                            
    m_vQuadBase.y, 
                                                            
    baseZ, 
                                                            
    0.0f)),  
                                              
    1 ); 
     
        // shader input : c6-c9 = patch 
    altitude matrix 
        
    m_pd3dDevice->SetVertexShaderConstant( 6, &splineMat[i][j], 4 ); 
     
        // shader input : c16-c19 = patch 
    lighting matrix 
        
    m_pd3dDevice->SetVertexShaderConstant( 16, &splineNormMat[i][j], 4 ); 
     
        // render the patch 
        m_pd3dDevice->DrawIndexedPrimitive( 
    D3DPT_TRIANGLELIST,  
                                            
    0,  
                                            
    m_patchWidth*m_patchWidth, 
                                            
    0, 
                                            
    (m_patchWidth-1)*(m_patchWidth-1)*2);  
    } 
    } | 
     
    
    | 
     Listing 12  | 
     
   
 
 
  
Downloadable demo for this article 
landshader.zip 
 |