/* Interpolation between two quaternions */ LPD3DRMQUATERNION WINAPI D3DRMQuaternionSlerp(LPD3DRMQUATERNION q, LPD3DRMQUATERNION a, LPD3DRMQUATERNION b, D3DVALUE alpha) { D3DVALUE dot, epsilon, temp, theta, u; D3DVECTOR v1, v2; dot = a->s * b->s + D3DRMVectorDotProduct(&a->v, &b->v); epsilon = 1.0f; temp = 1.0f - alpha; u = alpha; if (dot < 0.0) { epsilon = -1.0; dot = -dot; } if( 1.0f - dot > 0.001f ) { theta = acos(dot); temp = sin(theta * temp) / sin(theta); u = sin(theta * alpha) / sin(theta); } q->s = temp * a->s + epsilon * u * b->s; D3DRMVectorScale(&v1, &a->v, temp); D3DRMVectorScale(&v2, &b->v, epsilon * u); D3DRMVectorAdd(&q->v, &v1, &v2); return q; }
// Calculate the normals for all the vertices of the patches of land. void BoidsLand::gouraudShading( ) { // Local buffer for storing the current patches details. D3DRMVERTEX patchVertices[ 6 ]; D3DVECTOR averageNormal; int faces; // Iterate through the patches of land on the landscape. for ( int row = 0; row < LAND_Z_SIZE; row++ ) { for ( int col = 0; col < LAND_X_SIZE; col++ ) { // Get the current state of the current vertex. landMesh -> GetVertices( patchGroups[ 0 ][ row ][ col ], 0, 6, patchVertices ); // Recalculate the normals from vertices 0 & 3. // 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 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 0 ] ); faces += 2; if ( row > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col ][ 0 ] ); faces++; } if ( row > 0 && col > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col - 1 ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col - 1 ][ 0 ] ); faces += 2; } if ( col > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col - 1 ][ 1 ] ); faces++; } averageNormal.x /= faces; averageNormal.y /= faces; averageNormal.z /= faces; // Normalise the resultant vector. D3DRMVectorNormalize( &averageNormal ); // Update the normal of vertex 0. patchVertices[ 0 ].normal = averageNormal; // Update the normal of vertex 3. patchVertices[ 3 ].normal = averageNormal; // Recalculate the normal from vertex 1. // 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 ][ 0 ] ); faces++; if ( col > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col - 1 ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col - 1 ][ 0 ] ); faces += 2; } if ( col > 0 && ( ( row + 1 ) < LAND_Z_SIZE ) ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col - 1 ][ 1 ] ); faces++; } if ( ( row + 1 ) < LAND_Z_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col ][ 0 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col ][ 1 ] ); faces += 2; } averageNormal.x /= faces; averageNormal.y /= faces; averageNormal.z /= faces; // Normalise the resultant vector. D3DRMVectorNormalize( &averageNormal ); // Update the normal of vertex 1. patchVertices[ 1 ].normal = averageNormal; // Recalculate the normals from vertices 2 & 4. // 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 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 0 ] ); faces += 2; if ( ( row + 1 ) < LAND_Z_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col ][ 1 ] ); faces++; } if ( ( row + 1 ) < LAND_Z_SIZE && ( col + 1 ) < LAND_X_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col + 1 ][ 0 ] ); 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 ); } } }