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 + -
显示快捷键?