Se realizaron ajustes significativos en la configuración de fricción y recuperación en la simulación de botellas, mejorando la estabilidad y el comportamiento en contactos. Se implementaron nuevas funciones para limitar fuerzas Z y calcular la profundidad de penetración, optimizando la respuesta de las botellas en situaciones de contacto. Además, se ajustaron los parámetros de amortiguamiento y velocidad de separación para lograr un comportamiento más realista en la simulación.

This commit is contained in:
Miguel 2025-07-08 17:10:44 +02:00
parent 62b45ebf1c
commit 6887ede5e0
1 changed files with 129 additions and 23 deletions

View File

@ -87,12 +87,12 @@ namespace CtrEditor.Simulacion
public bool ConfigureContactManifold<TManifold>(int workerIndex, CollidablePair pair, ref TManifold manifold, out PairMaterialProperties pairMaterial) where TManifold : unmanaged, IContactManifold<TManifold>
{
// ✅ CONFIGURACIÓN BÁSICA de materiales físicos
// ✅ CONFIGURACIÓN BÁSICA de materiales físicos con valores rígidos pero estables
pairMaterial = new PairMaterialProperties
{
FrictionCoefficient = 0.3f,
MaximumRecoveryVelocity = 1f,
SpringSettings = new SpringSettings(80, 6)
MaximumRecoveryVelocity = 0.8f, // ✅ AJUSTADO: Velocidad de separación moderada
SpringSettings = new SpringSettings(120, 8) // ✅ AJUSTADO: Más rígido pero bien amortiguado
};
if (_simulationManager != null)
@ -165,16 +165,16 @@ namespace CtrEditor.Simulacion
botella.isOnBrakeTransport = true;
pairMaterial.FrictionCoefficient = 2f;
pairMaterial.MaximumRecoveryVelocity = 0.1f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f);
pairMaterial.MaximumRecoveryVelocity = 0.5f; // ✅ AJUSTADO: Velocidad de separación controlada
pairMaterial.SpringSettings = new SpringSettings(80, 6f); // ✅ AJUSTADO: Rígido para frenado
}
else
{
botella.isOnBrakeTransport = false;
// ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
pairMaterial.FrictionCoefficient = 0.3f; // CalculateTransportFriction(botella, transport, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.1f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f);
pairMaterial.FrictionCoefficient = CalculateTransportFriction(botella, transport, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.6f; // ✅ AJUSTADO: Velocidad de separación más natural
pairMaterial.SpringSettings = new SpringSettings(100, 8f); // ✅ AJUSTADO: Rígido para transportes
}
}
@ -193,26 +193,40 @@ namespace CtrEditor.Simulacion
// ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
var curve = curveA ?? curveB;
pairMaterial.FrictionCoefficient = 0.3f; // CalculateCurveFriction(botella, curve, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.1f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Colision con la cinta por gravedad
pairMaterial.FrictionCoefficient = CalculateCurveFriction(botella, curve, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.6f; // ✅ AJUSTADO: Velocidad de separación más natural
pairMaterial.SpringSettings = new SpringSettings(100, 8f); // ✅ AJUSTADO: Rígido para curvas
}
// ✅ CONTACTO BOTELLA-GUÍA: Configuración específica de fricción
else if (botella != null && (GetGuiaFromCollidable(pair.A) != null || GetGuiaFromCollidable(pair.B) != null))
{
// Fricción baja para las guías, deben deslizar, no arrastrar.
pairMaterial.FrictionCoefficient = 0.1f;
pairMaterial.MaximumRecoveryVelocity = 0.8f;
pairMaterial.SpringSettings = new SpringSettings(50, 1f); // Rebote lateral moderado
pairMaterial.FrictionCoefficient = 0.01f;
pairMaterial.MaximumRecoveryVelocity = 0.5f; // ✅ AJUSTADO: Velocidad de separación normal
pairMaterial.SpringSettings = new SpringSettings(120, 10f); // ✅ AJUSTADO: Rígido para guías
}
// ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Lógica de presión proactiva basada en la penetración.
else if (botellaA != null && botellaB != null)
{
// ✅ NUEVO: Usar método especializado para contactos botella-botella
CalculateBottlePression(ref manifold, botellaA, botellaB);
pairMaterial.FrictionCoefficient = 0.1f;
pairMaterial.MaximumRecoveryVelocity = 0.03f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Rebote lateral moderado
// ✅ NUEVO: Limitar fuerzas basadas en profundidad de penetración
var maxPenetrationDepth = GetMaxPenetrationDepth(ref manifold);
if (maxPenetrationDepth > 0.005f) // Penetración profunda (reducido umbral)
{
// Fuerzas controladas para penetraciones profundas - evitar explosiones pero mantener rigidez
pairMaterial.FrictionCoefficient = 0.01f;
pairMaterial.MaximumRecoveryVelocity = 0.3f; // ✅ AUMENTADO: Más velocidad de separación
pairMaterial.SpringSettings = new SpringSettings(60, 12f); // ✅ AUMENTADO: Más rígido pero bien amortiguado
}
else
{
// Fuerzas normales para contactos superficiales - botellas rígidas
pairMaterial.FrictionCoefficient = 0.02f;
pairMaterial.MaximumRecoveryVelocity = 0.5f; // ✅ AUMENTADO: Velocidad normal de separación
pairMaterial.SpringSettings = new SpringSettings(150, 10f); // ✅ AUMENTADO: Muy rígido para contactos normales
}
}
// Ajustes básicos para otras botellas
else if (botella != null)
@ -220,8 +234,8 @@ namespace CtrEditor.Simulacion
System.Diagnostics.Debug.WriteLine($"[ConfigureContactManifold] ERROR: contacto no resuelto!");
// Fricción moderada para colisiones entre botellas.
pairMaterial.FrictionCoefficient = 0.3f;
pairMaterial.MaximumRecoveryVelocity = 1f;
pairMaterial.SpringSettings = new SpringSettings(30, 1);
pairMaterial.MaximumRecoveryVelocity = 0.6f; // ✅ AJUSTADO: Velocidad de separación normal
pairMaterial.SpringSettings = new SpringSettings(120, 8); // ✅ AJUSTADO: Rígido pero controlado
}
}
@ -331,8 +345,8 @@ namespace CtrEditor.Simulacion
float slipSpeedThreshold = transportVelocity.Length()*0.85f; // m/s - umbral para cambiar de fricción estática a dinámica
const float heatupRate = 1f; // Qué tan rápido sube HighSlippery
const float cooldownRate = 0.5f; // Qué tan rápido baja HighSlippery
const float staticFriction = 0.25f;
const float cooldownRate = 0.2f; // Qué tan rápido baja HighSlippery
const float staticFriction = 0.30f;
const float dynamicFriction = 0.10f;
// Sistema de heatup/cooldown para HighSlippery
@ -382,8 +396,8 @@ namespace CtrEditor.Simulacion
float slipSpeedThreshold = curveVelocityAtPoint.Length() * 0.85f; // m/s
const float heatupRate = 1f; // Qué tan rápido sube HighSlippery en curvas
const float cooldownRate = 0.5f; // Qué tan rápido baja HighSlippery en curvas
const float staticFriction = 0.20f;
const float cooldownRate = 0.2f; // Qué tan rápido baja HighSlippery en curvas
const float staticFriction = 0.30f;
const float dynamicFriction = 0.10f;
// Sistema de heatup/cooldown para HighSlippery
@ -440,6 +454,31 @@ namespace CtrEditor.Simulacion
}
}
/// <summary>
/// ✅ NUEVA FUNCIÓN: Obtiene la profundidad máxima de penetración en un manifold
/// </summary>
private float GetMaxPenetrationDepth<TManifold>(ref TManifold manifold) where TManifold : unmanaged, IContactManifold<TManifold>
{
try
{
float maxDepth = 0f;
for (int i = 0; i < manifold.Count; ++i)
{
var depth = manifold.GetDepth(i);
if (depth > maxDepth)
{
maxDepth = depth;
}
}
return maxDepth;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[GetMaxPenetrationDepth] Error: {ex.Message}");
return 0f;
}
}
public bool ConfigureContactManifold(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB, ref ConvexContactManifold manifold)
{
return true;
@ -938,6 +977,9 @@ namespace CtrEditor.Simulacion
botella.ContactPressure = 0f;
}
// ✅ NUEVO: APLICAR LIMITACIÓN DE FUERZAS Z ANTES DEL TIMESTEP
ApplyZForceLimitation();
// ✅ CONSERVAR - validación de deltaTime
var currentTime = stopwatch.Elapsed.TotalMilliseconds;
var deltaTime = (float)((currentTime - stopwatch_last) / 1000.0);
@ -1498,6 +1540,70 @@ namespace CtrEditor.Simulacion
return lineStart + lineDirection * projectionLength;
}
/// <summary>
/// ✅ NUEVA FUNCIÓN: Limita las fuerzas Z para evitar que las botellas se eleven
/// Esta función se ejecuta ANTES del timestep para controlar fuerzas de separación excesivas
/// </summary>
private void ApplyZForceLimitation()
{
try
{
const float maxZVelocity = 0.3f; // ✅ AJUSTADO: Velocidad Z máxima permitida más realista (m/s)
const float zVelocityDamping = 0.8f; // ✅ AJUSTADO: Amortiguamiento menos agresivo para Z
foreach (var botella in Cuerpos.OfType<simBotella>())
{
try
{
// Verificar que la botella aún existe en la simulación
if (botella?.BodyHandle.Value >= 0 && simulation?.Bodies?.BodyExists(botella.BodyHandle) == true)
{
var body = simulation.Bodies.GetBodyReference(botella.BodyHandle);
var velocity = body.Velocity;
// ✅ LIMITACIÓN DIRECTA DE VELOCIDAD Z
if (velocity.Linear.Z > maxZVelocity)
{
velocity.Linear.Z = maxZVelocity;
body.Velocity = velocity;
}
// ✅ AMORTIGUAMIENTO ADICIONAL EN Z
if (velocity.Linear.Z > 0)
{
velocity.Linear.Z *= zVelocityDamping;
body.Velocity = velocity;
}
// ✅ LIMITACIÓN DE FUERZAS EXTREMAS POR PENETRACIÓN
// Si la botella está muy por encima del nivel normal, aplicar fuerza hacia abajo
var position = body.Pose.Position;
var maxAllowedZ = simBase.zPos_Transporte + simBase.zAltura_Transporte + botella.Radius * 2;
if (position.Z > maxAllowedZ)
{
// Aplicar fuerza hacia abajo proporcional a la elevación excesiva
var excessHeight = position.Z - maxAllowedZ;
var downwardForce = new Vector3(0, 0, -excessHeight * 20f); // ✅ AJUSTADO: Fuerza menos agresiva
// Aplicar impulso para corregir la posición
velocity.Linear += downwardForce * (1f / 60f); // Asumir 60 FPS
body.Velocity = velocity;
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[ApplyZForceLimitation] Error procesando botella {botella?.BodyHandle}: {ex.Message}");
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[ApplyZForceLimitation] Error crítico: {ex.Message}");
}
}
public void Dispose()
{
Clear();