boidsland.cpp
来自「3D的Boids效果演示源程序」· C++ 代码 · 共 1,248 行 · 第 1/3 页
CPP
1,248 行
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row + 1 ][ col + 1 ][ 1 ] );
faces += 2;
}
if ( ( col + 1 ) < LAND_X_SIZE )
{
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row ][ col + 1 ][ 0 ] );
faces++;
}
averageNormal.x /= faces;
averageNormal.y /= faces;
averageNormal.z /= faces;
// Normalise the resultant vector.
D3DRMVectorNormalize( &averageNormal );
// Update the normal of vertex 2.
patchVertices[ 2 ].normal = averageNormal;
// Update the normal of vertex 4.
patchVertices[ 4 ].normal = averageNormal;
// Recalculate the normal from vertex 5.
// Find the average of the face normals surrounding the vertex.
averageNormal.x = 0;
averageNormal.y = 0;
averageNormal.z = 0;
faces = 0;
// Working round in a clockwise direction -
//- starting from the current face.
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row ][ col ][ 1 ] );
faces++;
if ( ( col + 1 ) < LAND_X_SIZE )
{
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row ][ col + 1 ][ 0 ] );
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row ][ col + 1 ][ 1 ] );
faces += 2;
}
if ( row > 0 && ( ( col + 1 ) < LAND_X_SIZE ) )
{
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row - 1 ][ col + 1 ][ 0 ] );
faces++;
}
if ( row > 0 )
{
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row - 1 ][ col ][ 1 ] );
D3DRMVectorAdd( &averageNormal, &averageNormal,
&patchFaceNormals[ row - 1 ][ col ][ 0 ] );
faces += 2;
}
averageNormal.x /= faces;
averageNormal.y /= faces;
averageNormal.z /= faces;
// Normalise the resultant vector.
D3DRMVectorNormalize( &averageNormal );
// Update the normal of vertex 5.
patchVertices[ 5 ].normal = averageNormal;
// Store the state of the current vertex.
landMesh -> SetVertices( patchGroups[ 0 ][ row ][ col ],
0, 6, patchVertices );
}
}
}
// Deconstruct the landscape.
void BoidsLand::deconstruct( )
{
// Abort the function if no landscape exists.
if ( exists == false )
{
return;
}
// First turn off the landscape existance flag.
// This is important because the boids will reference it.
exists = false;
// Release the land patch COM interface gracefully.
landFrame -> DeleteVisual( landMesh );
landMesh -> Release( );
landMesh = NULL;
if ( landFrame )
{
landFrame -> Release( );
landFrame = NULL;
}
}
// Remove the landscape.
void BoidsLand::renderNone( )
{
// Deconstruct the landscape.
deconstruct( );
solidOn = false; // Update the flags.
wireframeOn = false;
}
// Toggle the style of the landscape.
void BoidsLand::toggleWireframe( )
{
// Deconstruct the landscape.
if ( landFrame )
{
deconstruct( );
}
// Perform the toggle.
if ( wireframeOn )
{
wireframeOn = false; // Update the flag.
}
else
{
wireframeOn = true; // Update the flag.
}
// Re-build the landscape if required.
if ( solidOn || wireframeOn )
{
build( window, d3drm, scene, solidStyle );
}
}
// Toggle the style of the landscape.
void BoidsLand::toggleUnlitFlat( )
{
// Deconstruct the landscape.
if ( landFrame )
{
deconstruct( );
}
// Perform the toggle.
if ( solidStyle == D3DRMRENDER_UNLITFLAT && solidOn == true )
{
solidOn = false; // Update the flag.
}
else
{
solidStyle = D3DRMRENDER_UNLITFLAT; // Update the style.
solidOn = true; // Update the flag.
}
// Re-build the landscape if required.
if ( solidOn || wireframeOn )
{
build( window, d3drm, scene, solidStyle );
}
}
// Toggle the style of the landscape.
void BoidsLand::toggleFlat( )
{
// Deconstruct the landscape.
if ( landFrame )
{
deconstruct( );
}
// Perform the toggle.
if ( solidStyle == D3DRMRENDER_FLAT && solidOn == true )
{
solidOn = false; // Update the flag.
}
else
{
solidStyle = D3DRMRENDER_FLAT; // Update the style.
solidOn = true; // Update the flag.
}
// Re-build the landscape if required.
if ( solidOn || wireframeOn )
{
build( window, d3drm, scene, solidStyle );
}
}
// Toggle the style of the landscape.
void BoidsLand::toggleGouraud( )
{
// Deconstruct the landscape.
if ( landFrame )
{
deconstruct( );
}
// Perform the toggle.
if ( solidStyle == D3DRMRENDER_GOURAUD && solidOn == true )
{
solidOn = false; // Update the flag.
}
else
{
solidStyle = D3DRMRENDER_GOURAUD; // Update the style.
solidOn = true; // Update the flag.
}
// Re-build the landscape if required.
if ( solidOn || wireframeOn )
{
build( window, d3drm, scene, solidStyle );
}
}
// Set the colour of the solid landscape.
void BoidsLand::setSolidColour( SolidColourEnum colour )
{
// Re-build the landscape if required.
if ( !solidOn || solidColour != colour )
{
// Deconstruct the landscape.
deconstruct( );
solidOn = true; // Update the flag.
solidColour = colour; // Set the colour.
build( window, d3drm, scene, solidStyle );
}
}
// Destroy, recalculate and redraw the landscape.
void BoidsLand::recalculate( )
{
// Deconstruct the landscape.
if ( landFrame )
{
deconstruct( );
}
// Call the member function to produce the landscape altitudes.
calcHeights( );
// If the lanscape is not present, bring it back as a wireframe -
// - to show the recalculation.
if ( solidOn == false && wireframeOn == false )
{
wireframeOn = true;
}
// Re-build the landscape.
build( window, d3drm, scene, solidStyle );
}
// Perform a calculation to determine if a given point is below the surface.
bool BoidsLand::getBelowSurface( D3DVALUE x, D3DVALUE y, D3DVALUE z )
{
// 1. Find the correct patch of land on the landscape.
// Find the column number of the landscape patch.
int col = (double)( x + X_LIMIT ) / (double)xSpacing;
// Find the row number of the landscape patch.
int row = (double)( z + Z_LIMIT ) / (double)zSpacing;
if ( col < 0 )
{
col++; // Adjust for lost precision purposes.
}
if ( col == LAND_X_SIZE )
{
col--; // Adjust for lost precision purposes.
}
if ( row < 0 )
{
row++; // Adjust for lost precision purposes.
}
if ( row == LAND_Z_SIZE )
{
row--; // Adjust for lost precision purposes.
}
// Local buffer for storing the current patches vertex zero.
D3DRMVERTEX patchVertices[ 6 ];
// Make sure that the correct patch of land is being used.
do
{
// Find the position of point 0 of the landscape patch.
if ( solidOn )
{
// Get the solid patch.
landMesh -> GetVertices( patchGroups[ 0 ][ row ][ col ],
0, 6, patchVertices );
}
else
{
// Get the wireframe patch.
landMesh -> GetVertices( patchGroups[ 1 ][ row ][ col ],
0, 6, patchVertices );
}
if ( x < patchVertices[ 0 ].position.x )
{
col--;
}
if ( x > patchVertices[ 2 ].position.x )
{
col++;
}
if ( z < patchVertices[ 0 ].position.z )
{
row--;
}
if ( z > patchVertices[ 2 ].position.z )
{
row++;
}
}
while( !( x >= patchVertices[ 0 ].position.x &&
x <= patchVertices[ 2 ].position.x &&
z >= patchVertices[ 0 ].position.z &&
z <= patchVertices[ 2 ].position.z ) );
// 2. Find the correct triangle within that patch of land.
// 2.1 Calculate the z/x gradient of the division between the triangles.
D3DVALUE gradient = (double)zSpacing / (double)xSpacing;
// 2.2 Subtract the X & Z position of vertex 0 from the points position.
D3DVALUE tempX = x - patchVertices[ 0 ].position.x;
D3DVALUE tempZ = z - patchVertices[ 0 ].position.z;
// 2.3 Multiply the X position by the gradient -
// - to find the dividing lines Z position.
D3DVALUE zBorder = (double)tempX * (double)gradient;
// 2.4 Compare the positions to see which triangle the point lies in.
bool upperTriangle = false;
if ( tempZ >= zBorder )
{
upperTriangle = true;
}
// 3. Determine wether the point lies -
// - below the triangle's surface plane.
// 3.1 Get the heights of the appropiate triangle.
D3DVALUE x1, x2, x3, y1, y2, y3, z1, z2, z3;
if ( upperTriangle )
{
x1 = patchVertices[ 0 ].position.x;
x2 = patchVertices[ 1 ].position.x;
x3 = patchVertices[ 2 ].position.x;
y1 = patchVertices[ 0 ].position.y;
y2 = patchVertices[ 1 ].position.y;
y3 = patchVertices[ 2 ].position.y;
z1 = patchVertices[ 0 ].position.z;
z2 = patchVertices[ 1 ].position.z;
z3 = patchVertices[ 2 ].position.z;
}
else
{
x1 = patchVertices[ 3 ].position.x;
x2 = patchVertices[ 4 ].position.x;
x3 = patchVertices[ 5 ].position.x;
y1 = patchVertices[ 3 ].position.y;
y2 = patchVertices[ 4 ].position.y;
y3 = patchVertices[ 5 ].position.y;
z1 = patchVertices[ 3 ].position.z;
z2 = patchVertices[ 4 ].position.z;
z3 = patchVertices[ 5 ].position.z;
}
return getBelowPlane( x, y, z, x1, x2, x3, y1, y2, y3, z1, z2, z3 );
}
// Mathematical function to determine if a 3D point lies below a plane
// that is represented by three vertices.
bool BoidsLand::getBelowPlane( D3DVALUE x, D3DVALUE y, D3DVALUE z,
D3DVALUE x1, D3DVALUE x2, D3DVALUE x3,
D3DVALUE y1, D3DVALUE y2, D3DVALUE y3,
D3DVALUE z1, D3DVALUE z2, D3DVALUE z3 )
{
// Calculate the plane's coefficients.
D3DVALUE a, b, c, d;
a = y1 * ( z2 - z3 ) + y2 * ( z3 - z1 ) + y3 * ( z1 - z2 );
b = z1 * ( x2 - x3 ) + z2 * ( x3 - x1 ) + z3 * ( x1 - x2 );
c = x1 * ( y2 - y3 ) + x2 * ( y3 - y1 ) + x3 * ( y1 - y2 );
d = -x1 * ( y2 * z3 - y3 * z2 ) + -x2 * ( y3 * z1 - y1 * z3 )
+ -x3 * ( y1 * z2 - y2 * z1 );
// Using the plane equation: a * x + b * y + c * z + d = 0.
D3DVALUE surfaceYValue = ( ( -a * x ) - ( c * z ) - d ) / b;
// Return the correct answer.
if ( y < surfaceYValue )
{
return true;
}
else
{
return false;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?