//----------------------------------------------------------------------------- // Purpose: Initialize the rays to be cast from the vehicle wheel positions to // the "ground." //----------------------------------------------------------------------------- void IVP_Controller_Raycast_Airboat::PreRaycasts( IVP_Ray_Solver_Template *pRaySolverTemplates, const IVP_U_Matrix *matWorldFromCore, IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoons ) { int nPontoonPoints = n_wheels; for ( int iPoint = 0; iPoint < nPontoonPoints; ++iPoint ) { IVP_Raycast_Airboat_Wheel *pPontoonPoint = get_wheel( IVP_POS_WHEEL( iPoint ) ); if ( pPontoonPoint ) { // Fill the in the ray solver template for the current wheel. IVP_Ray_Solver_Template &raySolverTemplate = pRaySolverTemplates[iPoint]; // Transform the wheel "start" position from vehicle core-space to world-space. This is // the raycast starting position. matWorldFromCore->vmult4( &pPontoonPoint->raycast_start_cs, &raySolverTemplate.ray_start_point ); // Transform the shock (spring) direction from vehicle core-space to world-space. This is // the raycast direction. matWorldFromCore->vmult3( &pPontoonPoint->raycast_dir_cs, &pTempPontoons[iPoint].raycast_dir_ws ); raySolverTemplate.ray_normized_direction.set( &pTempPontoons[iPoint].raycast_dir_ws ); // Set the length of the ray cast. raySolverTemplate.ray_length = AIRBOAT_RAYCAST_DIST; // Set the ray solver template flags. This defines wish objects you wish to // collide against in the physics environment. raySolverTemplate.ray_flags = IVP_RAY_SOLVER_ALL; } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void IVP_Controller_Raycast_Airboat::InitRaycastCarWheels( const IVP_Template_Car_System *pCarSystemTemplate ) { IVP_U_Matrix m_core_f_object; m_pAirboatBody->calc_m_core_f_object( &m_core_f_object ); // Initialize the car wheel system. for ( int iWheel = 0; iWheel < n_wheels; iWheel++ ) { // Get and clear out memory for the current raycast wheel. IVP_Raycast_Airboat_Wheel *pRaycastWheel = get_wheel( IVP_POS_WHEEL( iWheel ) ); P_MEM_CLEAR( pRaycastWheel ); // Put the wheel in car space. m_core_f_object.vmult4( &pCarSystemTemplate->wheel_pos_Bos[iWheel], &pRaycastWheel->hp_cs ); m_core_f_object.vmult4( &pCarSystemTemplate->trace_pos_Bos[iWheel], &pRaycastWheel->raycast_start_cs ); // Add in the raycast start offset. pRaycastWheel->raycast_length = AIRBOAT_RAYCAST_DIST; pRaycastWheel->raycast_dir_cs.set_to_zero(); pRaycastWheel->raycast_dir_cs.k[index_y] = gravity_y_direction; // Spring (Shocks) data. pRaycastWheel->spring_len = -pCarSystemTemplate->spring_pre_tension[iWheel]; pRaycastWheel->spring_direction_cs.set_to_zero(); pRaycastWheel->spring_direction_cs.k[index_y] = gravity_y_direction; pRaycastWheel->spring_constant = pCarSystemTemplate->spring_constant[iWheel]; pRaycastWheel->spring_damp_relax = pCarSystemTemplate->spring_dampening[iWheel]; pRaycastWheel->spring_damp_compress = pCarSystemTemplate->spring_dampening_compression[iWheel]; // Wheel data. pRaycastWheel->friction_of_wheel = 1.0f;//pCarSystemTemplate->friction_of_wheel[iWheel]; pRaycastWheel->wheel_radius = pCarSystemTemplate->wheel_radius[iWheel]; pRaycastWheel->inv_wheel_radius = 1.0f / pCarSystemTemplate->wheel_radius[iWheel]; do_steering_wheel( IVP_POS_WHEEL( iWheel ), 0.0f ); pRaycastWheel->wheel_is_fixed = IVP_FALSE; pRaycastWheel->max_rotation_speed = pCarSystemTemplate->wheel_max_rotation_speed[iWheel>>1]; pRaycastWheel->wheel_is_fixed = IVP_TRUE; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void IVP_Controller_Raycast_Airboat::DoSimulationPontoons( IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoons, IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim ) { for ( int iPoint = 0; iPoint < n_wheels; ++iPoint ) { IVP_Raycast_Airboat_Wheel *pPontoonPoint = get_wheel( IVP_POS_WHEEL( iPoint ) ); if ( !pPontoonPoint ) continue; if ( pImpacts[iPoint].bImpact ) DoSimulationPontoonsGround( pPontoonPoint, &pTempPontoons[iPoint], &pImpacts[iPoint], pEventSim ); else if ( pImpacts[iPoint].bInWater ) DoSimulationPontoonsWater( &pTempPontoons[iPoint], &pImpacts[iPoint], pEventSim ); } }
void CPhysics_Car_System_Raycast_Wheels::update_wheel_positions( void ) { // Get the car body object. IVP_Cache_Object *pCacheObject = car_body->get_cache_object(); // Get the core (vehicle) matrix. IVP_U_Matrix m_core_f_object; car_body->calc_m_core_f_object( &m_core_f_object ); for ( int iWheel = 0; iWheel < n_wheels; ++iWheel ) { // Get the current raycast wheel. IVP_Raycast_Car_Wheel *pRaycastWheel = get_wheel( IVP_POS_WHEEL( iWheel ) ); // Get the position of the wheel in vehicle core space. IVP_U_Float_Point hp_cs; hp_cs.add_multiple( &pRaycastWheel->hp_cs, &pRaycastWheel->spring_direction_cs, pRaycastWheel->raycast_dist - pRaycastWheel->wheel_radius ); // Get the position on vehicle object space (inverse transform). IVP_U_Float_Point hp_os; m_core_f_object.vimult4( &hp_cs, &hp_os ); // Transform the wheel position from object space into world space. IVP_U_Point hp_ws; pCacheObject->transform_position_to_world_coords( &hp_os, &hp_ws ); // Apply rotational component. IVP_U_Point wheel_cs( &pRaycastWheel->axis_direction_cs ); IVP_U_Point wheel2_cs( 0 ,0 ,0 ); wheel2_cs.k[index_y] = -1.0; wheel2_cs.rotate( IVP_COORDINATE_INDEX( index_x ), pRaycastWheel->angle_wheel ); IVP_U_Matrix3 m_core_f_wheel; m_core_f_wheel.init_normized3_col( &wheel_cs, IVP_COORDINATE_INDEX( index_x ), &wheel2_cs ); IVP_U_Matrix3 m_world_f_wheel; pCacheObject->m_world_f_object.mmult3( &m_core_f_wheel, &m_world_f_wheel ); // bid hack, assumes cs = os (for rotation); IVP_U_Quat rot_ws; rot_ws.set_quaternion( &m_world_f_wheel ); m_pWheels[iWheel]->beam_object_to_new_position( &rot_ws, &hp_ws ); } pCacheObject->remove_reference(); }
void IVP_Controller_Raycast_Airboat::do_steering( IVP_FLOAT steering_angle_in ) { // Check for a change. if ( m_SteeringAngle == steering_angle_in) return; // Set the new steering angle. m_SteeringAngle = steering_angle_in; // Make sure the simulation is awake - we just go input. m_pAirboatBody->get_environment()->get_controller_manager()->ensure_controller_in_simulation( this ); // Steer each wheel. for ( int iWheel = 0; iWheel < wheels_per_axis; ++iWheel ) { do_steering_wheel( IVP_POS_WHEEL( iWheel ), m_SteeringAngle ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void IVP_Controller_Raycast_Airboat::DoSimulationSteering( IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoons, IVP_Core *pAirboatCore, IVP_Event_Sim *pEventSim ) { IVP_U_Float_Point vecRightWS; const IVP_U_Matrix *matWorldFromCore = pAirboatCore->get_m_world_f_core_PSI(); matWorldFromCore->get_col( IVP_COORDINATE_INDEX( index_x ), &vecRightWS ); IVP_FLOAT flForceRotational = 0.0f; // Check for rotation. if ( fabsf( m_SteeringAngle ) > 0.01 ) { // Get the steering sign. IVP_FLOAT flSteeringSign = m_SteeringAngle < 0.0f ? -1.0f : 1.0f; flForceRotational = IVP_RAYCAST_AIRBOAT_STEERING_RATE * pAirboatCore->get_mass() * pEventSim->i_delta_time; flForceRotational *= flSteeringSign; } // General force that will help get us back to zero rotation. IVP_FLOAT flRotSpeedSign = pAirboatCore->rot_speed.k[1] < 0.0f ? -1.0f : 1.0f; IVP_FLOAT flRotationalDrag = -0.5f * IVP_RAYCAST_AIRBOAT_STEERING_RATE * pAirboatCore->get_mass() * pEventSim->i_delta_time; flRotationalDrag *= flRotSpeedSign; flForceRotational += flRotationalDrag; IVP_U_Float_Point vecImpulse; for ( int iPoint = 0; iPoint < 4; ++iPoint ) { IVP_Raycast_Airboat_Wheel *pPontoonPoint = get_wheel( IVP_POS_WHEEL( iPoint ) ); IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoonPoint = &pTempPontoons[iPoint]; IVP_FLOAT flPontoonSign = iPoint >= 2 ? -1.0f : 1.0f; IVP_FLOAT flForceRot = flForceRotational * flPontoonSign; vecImpulse.set_multiple( &vecRightWS, flForceRot * pEventSim->delta_time ); IVP_U_Float_Point vecPointPosCS, vecPointPosWS; vecPointPosCS = pPontoonPoint->raycast_start_cs; matWorldFromCore->vmult3( &vecPointPosCS, &vecPointPosWS ); IVP_U_Point vecPointPositionWS( vecPointPosWS ); pAirboatCore->push_core_ws( &vecPointPositionWS, &vecImpulse ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void IVP_Controller_Raycast_Airboat::DoSimulationPontoons( IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoons, IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim, IVP_Core *pAirboatCore ) { int nPontoonPoints = n_wheels; for ( int iPoint = 0; iPoint < nPontoonPoints; ++iPoint ) { IVP_Raycast_Airboat_Wheel *pPontoonPoint = get_wheel( IVP_POS_WHEEL( iPoint ) ); if ( !pPontoonPoint ) continue; if ( pImpacts[iPoint].bImpact ) { DoSimulationPontoonsGround( pPontoonPoint, &pTempPontoons[iPoint], &pImpacts[iPoint], pEventSim, pAirboatCore ); } else if ( pImpacts[iPoint].bInWater ) { IVP_BOOL bFront = ( iPoint < 2 ) ? IVP_TRUE : IVP_FALSE; DoSimulationPontoonsWater( pPontoonPoint, &pTempPontoons[iPoint], &pImpacts[iPoint], pEventSim, pAirboatCore, bFront ); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool IVP_Controller_Raycast_Airboat::PostRaycasts( IVP_Ray_Solver_Template *pRaySolverTemplates, const IVP_U_Matrix *matWorldFromCore, IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoons, IVP_Raycast_Airboat_Impact *pImpacts ) { int nPontoonPoints = n_wheels; for( int iPoint = 0; iPoint < nPontoonPoints; ++iPoint ) { // Get data at raycast position. IVP_Raycast_Airboat_Wheel *pPontoonPoint = get_wheel( IVP_POS_WHEEL( iPoint ) ); IVP_Raycast_Airboat_Pontoon_Temp *pTempPontoonPoint = &pTempPontoons[iPoint]; IVP_Raycast_Airboat_Impact *pImpact = &pImpacts[iPoint]; IVP_Ray_Solver_Template *pRaySolver = &pRaySolverTemplates[iPoint]; if ( !pPontoonPoint || !pTempPontoonPoint || !pImpact || !pRaySolver ) continue; // Copy the ray length back, it may have changed. pPontoonPoint->raycast_length = pRaySolver->ray_length; // Test for inverted raycast direction. if ( pImpact->bInWater ) { pTempPontoonPoint->raycast_dir_ws.set_multiple( &pTempPontoonPoint->raycast_dir_ws, -1 ); } // Impact. if ( pImpact->bImpact ) { // Save impact normal. pTempPontoonPoint->ground_normal_ws = pImpact->vecImpactNormalWS; // Save impact distance. IVP_U_Point vecDelta; vecDelta.subtract( &pImpact->vecImpactPointWS, &pRaySolver->ray_start_point ); pPontoonPoint->raycast_dist = vecDelta.real_length(); // Get the inverse portion of the surface normal in the direction of the ray cast (shock - used in the shock simulation code for the sign // and percentage of force applied to the shock). pTempPontoonPoint->inv_normal_dot_dir = 1.1f / ( IVP_Inline_Math::fabsd( pTempPontoonPoint->raycast_dir_ws.dot_product( &pTempPontoonPoint->ground_normal_ws ) ) + 0.1f ); // Set the wheel friciton - ground friction (if any) + wheel friction. pTempPontoonPoint->friction_value = pImpact->flFriction * pPontoonPoint->friction_of_wheel; } // No impact. else { pPontoonPoint->raycast_dist = pPontoonPoint->raycast_length; pTempPontoonPoint->inv_normal_dot_dir = 1.0f; pTempPontoonPoint->moveable_object_hit_by_ray = NULL; pTempPontoonPoint->ground_normal_ws.set_multiple( &pTempPontoonPoint->raycast_dir_ws, -1 ); pTempPontoonPoint->friction_value = 1.0f; } // Set the new wheel position (the impact point or the full ray distance). Make this from the wheel not the ray trace position. pTempPontoonPoint->ground_hit_ws.add_multiple( &pRaySolver->ray_start_point, &pTempPontoonPoint->raycast_dir_ws, pPontoonPoint->raycast_dist ); // Get the speed (velocity) at the impact point. m_pAirboatBody->get_core()->get_surface_speed_ws( &pTempPontoonPoint->ground_hit_ws, &pTempPontoonPoint->surface_speed_wheel_ws ); pTempPontoonPoint->projected_surface_speed_wheel_ws.set_orthogonal_part( &pTempPontoonPoint->surface_speed_wheel_ws, &pTempPontoonPoint->ground_normal_ws ); matWorldFromCore->vmult3( &pPontoonPoint->axis_direction_cs, &pTempPontoonPoint->axis_direction_ws ); pTempPontoonPoint->projected_axis_direction_ws.set_orthogonal_part( &pTempPontoonPoint->axis_direction_ws, &pTempPontoonPoint->ground_normal_ws ); if ( pTempPontoonPoint->projected_axis_direction_ws.normize() == IVP_FAULT ) { printf( "IVP_Controller_Raycast_Airboat::do_simulation_controller projected_axis_direction_ws.normize failed\n" ); return false; } } return true; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPhysics_Airboat::SetWheelFriction( int iWheel, float flFriction ) { change_friction_of_wheel( IVP_POS_WHEEL( iWheel ), flFriction ); }