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
|