Se eliminó el sistema de limitación de fuerzas para contactos múltiples, reemplazándolo por un enfoque de intervención post-solver que mejora el control de velocidades Z y simplifica la lógica de simulación. Se ajustaron los parámetros de fricción y recuperación, optimizando el comportamiento de las botellas en situaciones de contacto. Además, se eliminaron funciones relacionadas con el seguimiento de densidad de contactos, simplificando el código y mejorando la eficiencia del sistema.

This commit is contained in:
Miguel 2025-07-09 12:05:49 +02:00
parent b44bdc5ece
commit 18017db56a
2 changed files with 76 additions and 186 deletions

View File

@ -34,16 +34,16 @@ simTransporte : Es un box por donde las botellas pueden desplazarse usando un tr
* Se ha reemplazado el sistema `ProcessPressureSystem` por un nuevo sistema de calibración visual `HighSlippery` que permite ajustar las fricciones de cada componente. Cada botella tiene una propiedad `HighSlippery` (rango 0-9) con sistema de heatup/cooldown que se incrementa durante deslizamiento y se decrementa durante adherencia. El valor se muestra como número en el centro de cada botella para calibración visual. Los `SpringSettings` se mantienen >= 30 para evitar compresiones irreales. El sistema permite calibrar las tasas de heatup/cooldown específicas para transportes (0.2/0.1) y curvas (0.15/0.08), y el umbral de cambio estático/dinámico (HighSlippery > 3). Este sistema elimina el problema del cooldown que reactivaba prematuramente la fricción estática. * Se ha reemplazado el sistema `ProcessPressureSystem` por un nuevo sistema de calibración visual `HighSlippery` que permite ajustar las fricciones de cada componente. Cada botella tiene una propiedad `HighSlippery` (rango 0-9) con sistema de heatup/cooldown que se incrementa durante deslizamiento y se decrementa durante adherencia. El valor se muestra como número en el centro de cada botella para calibración visual. Los `SpringSettings` se mantienen >= 30 para evitar compresiones irreales. El sistema permite calibrar las tasas de heatup/cooldown específicas para transportes (0.2/0.1) y curvas (0.15/0.08), y el umbral de cambio estático/dinámico (HighSlippery > 3). Este sistema elimina el problema del cooldown que reactivaba prematuramente la fricción estática.
# Sistema de Limitación de Fuerzas para Contactos Múltiples Simultáneos # Sistema de Limitación de Fuerzas para Contactos Múltiples Simultáneos (ELIMINADO)
## Problema Identificado ## Problema Identificado
Durante la simulación de "trenes largos" de botellas que impactan simultáneamente, se generaban fuerzas armónicas irreales que no ocurren en la vida real. Aunque tengas 50 botellas empujando, la fuerza máxima está limitada por la resistencia de los materiales. Durante la simulación de "trenes largos" de botellas que impactan simultáneamente, se generaban fuerzas armónicas irreales que no ocurren en la vida real. Aunque tengas 50 botellas empujando, la fuerza máxima está limitada por la resistencia de los materiales.
## Solución Implementada ## Solución Inicial Implementada (OBSOLETA)
### 1. Sistema de Tracking de Densidad de Contactos ### 1. Sistema de Tracking de Densidad de Contactos
- **Discretización espacial**: El espacio se divide en regiones de 0.5m x 0.5m x 0.5m - **Discretización espacial**: El espacio se dividía en regiones de 0.5m x 0.5m x 0.5m
- **Contador por región**: Se cuenta el número de contactos simultáneos en cada región - **Contador por región**: Se contaba el número de contactos simultáneos en cada región
- **Límite de contactos**: Máximo 10 contactos antes de aplicar limitación de fuerzas - **Límite de contactos**: Máximo 10 contactos antes de aplicar limitación de fuerzas
### 2. Factor de Escala Dinámico ### 2. Factor de Escala Dinámico
@ -57,20 +57,21 @@ return Math.Max(scaleFactor, 0.3f); // Mínimo 30% de fuerza original
``` ```
### 3. Aplicación Integral ### 3. Aplicación Integral
- **SpringSettings**: Se escalan proporcionalmente (frecuencia reducida) - **SpringSettings**: Se escalaban proporcionalmente (frecuencia reducida)
- **MaximumRecoveryVelocity**: Se reduce proporcionalmente - **MaximumRecoveryVelocity**: Se reducía proporcionalmente
- **Todos los tipos de contacto**: Botella-botella, botella-transporte, botella-curva, etc. - **Todos los tipos de contacto**: Botella-botella, botella-transporte, botella-curva, etc.
## Beneficios ## Razón para la Eliminación
- **Comportamiento realista**: Elimina fuerzas armónicas irreales en impactos múltiples Este sistema se **eliminó completamente** porque:
- **Estabilidad mejorada**: Previene explosiones por acumulación de fuerzas - Era un enfoque indirecto modificando parámetros de material
- **Configurabilidad**: Límites y factores ajustables según necesidades - El nuevo sistema de **intervención post-solver** es más efectivo
- **Mantenimiento de rigidez**: Las fuerzas normales permanecen intactas hasta el límite - La cancelación directa de velocidades Z es más elegante y simple
- Reducía la complejidad del código sin comprometer la funcionalidad
# Sistema de Intervención Post-Solver para Control de Velocidades Z # Sistema de Intervención Post-Solver para Control de Velocidades Z
## Problema Identificado ## Problema Identificado
El sistema anterior de limitación de fuerzas pre-solver no controlaba directamente las velocidades Z excesivas generadas por el solver de BEPU. Las botellas seguían elevándose debido a fuerzas de separación acumuladas que se aplicaban después de las restricciones iniciales. El sistema anterior de limitación de fuerzas pre-solver no controlaba directamente las velocidades Z excesivas generadas por el solver de BEPU. Las botellas seguían elevándose debido a fuerzas de separación acumuladas que se aplicaban después de las restricciones iniciales. Además, el sistema de `forceScale` para contactos múltiples era un enfoque indirecto que no atacaba la causa raíz del problema.
## Solución Implementada ## Solución Implementada
@ -114,4 +115,6 @@ if (velocity.Linear.Z > maxUpwardVelocity) {
- **Más directo**: Control directo de velocidades en lugar de modificar parámetros de material - **Más directo**: Control directo de velocidades en lugar de modificar parámetros de material
- **Más predecible**: Comportamiento determinista independiente de las configuraciones del solver - **Más predecible**: Comportamiento determinista independiente de las configuraciones del solver
- **Mantenimiento de rigidez**: Las fuerzas normales en XY permanecen intactas - **Mantenimiento de rigidez**: Las fuerzas normales en XY permanecen intactas
- **Solución integral**: Resuelve tanto el problema de elevación como el de contactos múltiples simultáneos
- **Código más simple**: Elimina la complejidad del sistema de tracking de densidad de contactos

View File

@ -95,27 +95,7 @@ namespace CtrEditor.Simulacion
SpringSettings = new SpringSettings(120, 8) // ✅ AJUSTADO: Más rígido pero bien amortiguado SpringSettings = new SpringSettings(120, 8) // ✅ AJUSTADO: Más rígido pero bien amortiguado
}; };
// ✅ NUEVO: SISTEMA DE LIMITACIÓN DE FUERZAS PARA CONTACTOS MÚLTIPLES // ✅ ELIMINADO: Sistema de limitación de fuerzas forceScale - reemplazado por intervención post-solver
float forceScale = 1.0f;
if (_simulationManager != null)
{
var contactPosition = _simulationManager.GetContactPosition(pair);
forceScale = _simulationManager.RegisterContactAndGetForceScale(contactPosition);
// Aplicar limitación de fuerzas si hay demasiados contactos simultáneos
if (forceScale < 1.0f)
{
// Reducir SpringSettings proporcionalmente
var originalFreq = pairMaterial.SpringSettings.Frequency;
var originalDamp = pairMaterial.SpringSettings.DampingRatio;
pairMaterial.SpringSettings = new SpringSettings(originalFreq * forceScale, originalDamp);
// Reducir velocidad de recuperación proporcionalmente
pairMaterial.MaximumRecoveryVelocity *= forceScale;
//System.Diagnostics.Debug.WriteLine($"[ConfigureContactManifold] ⚠️ LIMITANDO FUERZAS: Factor={forceScale:F2}, Región={contactPosition}");
}
}
if (_simulationManager != null) if (_simulationManager != null)
{ {
@ -146,7 +126,7 @@ namespace CtrEditor.Simulacion
// ✅ CONTACTO BOTELLA-TRANSPORTE: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA // ✅ CONTACTO BOTELLA-TRANSPORTE: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA
if (botella != null && (transportA != null || transportB != null)) if (botella != null && (transportA != null || transportB != null))
{ {
botella.forceScale = forceScale; // ✅ ELIMINADO: botella.forceScale = forceScale;
// ✅ NUEVO: Lógica de control de presión/flotación // ✅ NUEVO: Lógica de control de presión/flotación
botella.IsTouchingTransport = true; botella.IsTouchingTransport = true;
var botellaCollidable = GetBotellaFromCollidable(pair.A) != null ? pair.A : pair.B; var botellaCollidable = GetBotellaFromCollidable(pair.A) != null ? pair.A : pair.B;
@ -188,23 +168,23 @@ namespace CtrEditor.Simulacion
botella.isOnBrakeTransport = true; botella.isOnBrakeTransport = true;
pairMaterial.FrictionCoefficient = 8f; pairMaterial.FrictionCoefficient = 8f;
pairMaterial.MaximumRecoveryVelocity = 0.5f * forceScale; // ✅ APLICAR FACTOR DE ESCALA pairMaterial.MaximumRecoveryVelocity = 1f; // ✅ REMOVIDO: * forceScale
pairMaterial.SpringSettings = new SpringSettings(80 * forceScale, 6f); // ✅ APLICAR FACTOR DE ESCALA pairMaterial.SpringSettings = new SpringSettings(30, 1f); // ✅ REMOVIDO: * forceScale
} }
else else
{ {
botella.isOnBrakeTransport = false; botella.isOnBrakeTransport = false;
// ✅ NUEVO: Usar fricción dinámica basada en deslizamiento // ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
pairMaterial.FrictionCoefficient = CalculateTransportFriction(botella, transport, botellaCollidable); pairMaterial.FrictionCoefficient = CalculateTransportFriction(botella, transport, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.6f * forceScale; // ✅ APLICAR FACTOR DE ESCALA pairMaterial.MaximumRecoveryVelocity = 1f; // ✅ REMOVIDO: * forceScale
pairMaterial.SpringSettings = new SpringSettings(100 * forceScale, 8f); // ✅ APLICAR FACTOR DE ESCALA pairMaterial.SpringSettings = new SpringSettings(30, 1f); // ✅ REMOVIDO: * forceScale
} }
} }
// ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA // ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA
else if (botella != null && (curveA != null || curveB != null)) else if (botella != null && (curveA != null || curveB != null))
{ {
botella.forceScale = forceScale; // ✅ ELIMINADO: botella.forceScale = forceScale;
// ✅ NUEVO: Lógica de control de presión/flotación // ✅ NUEVO: Lógica de control de presión/flotación
botella.IsTouchingTransport = true; botella.IsTouchingTransport = true;
botella.isOnBrakeTransport = false; botella.isOnBrakeTransport = false;
@ -218,16 +198,16 @@ namespace CtrEditor.Simulacion
// ✅ NUEVO: Usar fricción dinámica basada en deslizamiento // ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
var curve = curveA ?? curveB; var curve = curveA ?? curveB;
pairMaterial.FrictionCoefficient = CalculateCurveFriction(botella, curve, botellaCollidable); pairMaterial.FrictionCoefficient = CalculateCurveFriction(botella, curve, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.6f * forceScale; // ✅ APLICAR FACTOR DE ESCALA pairMaterial.MaximumRecoveryVelocity = 1f; // ✅ REMOVIDO: * forceScale
pairMaterial.SpringSettings = new SpringSettings(100 * forceScale, 8f); // ✅ APLICAR FACTOR DE ESCALA pairMaterial.SpringSettings = new SpringSettings(30, 1f); // ✅ REMOVIDO: * forceScale
} }
// ✅ CONTACTO BOTELLA-GUÍA: Configuración específica de fricción // ✅ CONTACTO BOTELLA-GUÍA: Configuración específica de fricción
else if (botella != null && (GetGuiaFromCollidable(pair.A) != null || GetGuiaFromCollidable(pair.B) != null)) else if (botella != null && (GetGuiaFromCollidable(pair.A) != null || GetGuiaFromCollidable(pair.B) != null))
{ {
// Fricción baja para las guías, deben deslizar, no arrastrar. // Fricción baja para las guías, deben deslizar, no arrastrar.
pairMaterial.FrictionCoefficient = 0.01f; pairMaterial.FrictionCoefficient = 0.01f;
pairMaterial.MaximumRecoveryVelocity = 0.5f * forceScale; // ✅ APLICAR FACTOR DE ESCALA pairMaterial.MaximumRecoveryVelocity = 0.95f; // ✅ REMOVIDO: * forceScale
pairMaterial.SpringSettings = new SpringSettings(120 * forceScale, 10f); // ✅ APLICAR FACTOR DE ESCALA pairMaterial.SpringSettings = new SpringSettings(40, 1f); // ✅ REMOVIDO: * forceScale
} }
// ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Lógica de presión proactiva basada en la penetración. // ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Lógica de presión proactiva basada en la penetración.
else if (botellaA != null && botellaB != null) else if (botellaA != null && botellaB != null)
@ -236,30 +216,20 @@ namespace CtrEditor.Simulacion
CalculateBottlePression(ref manifold, botellaA, botellaB); CalculateBottlePression(ref manifold, botellaA, botellaB);
// ✅ NUEVO: Limitar fuerzas basadas en profundidad de penetración // ✅ NUEVO: Limitar fuerzas basadas en profundidad de penetración
var maxPenetrationDepth = GetMaxPenetrationDepth(ref manifold); //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 * forceScale; // ✅ APLICAR FACTOR DE ESCALA
pairMaterial.SpringSettings = new SpringSettings(60 * forceScale, 12f); // ✅ APLICAR FACTOR DE ESCALA
}
else
{
// Fuerzas normales para contactos superficiales - botellas rígidas // Fuerzas normales para contactos superficiales - botellas rígidas
pairMaterial.FrictionCoefficient = 0.02f; pairMaterial.FrictionCoefficient = 0.02f;
pairMaterial.MaximumRecoveryVelocity = 0.5f * forceScale; // ✅ APLICAR FACTOR DE ESCALA pairMaterial.MaximumRecoveryVelocity = 1f; // ✅ REMOVIDO: * forceScale
pairMaterial.SpringSettings = new SpringSettings(150 * forceScale, 10f); // ✅ APLICAR FACTOR DE ESCALA pairMaterial.SpringSettings = new SpringSettings(40, 10f); // ✅ REMOVIDO: * forceScale
}
} }
// Ajustes básicos para otras botellas // Ajustes básicos para otras botellas
else if (botella != null) else if (botella != null)
{ {
System.Diagnostics.Debug.WriteLine($"[ConfigureContactManifold] ERROR: contacto no resuelto!"); System.Diagnostics.Debug.WriteLine($"[ConfigureContactManifold] ERROR: contacto no resuelto!");
// Fricción moderada para colisiones entre botellas. // Fricción moderada para colisiones entre botellas.
pairMaterial.FrictionCoefficient = 0.3f; pairMaterial.FrictionCoefficient = 0f;
pairMaterial.MaximumRecoveryVelocity = 0.6f * forceScale; // ✅ APLICAR FACTOR DE ESCALA pairMaterial.MaximumRecoveryVelocity = 1f; // ✅ REMOVIDO: * forceScale
pairMaterial.SpringSettings = new SpringSettings(120 * forceScale, 8); // ✅ APLICAR FACTOR DE ESCALA pairMaterial.SpringSettings = new SpringSettings(80, 1); // ✅ REMOVIDO: * forceScale
} }
} }
@ -369,9 +339,9 @@ namespace CtrEditor.Simulacion
float slipSpeedThreshold = transportVelocity.Length()*0.85f; // m/s - umbral para cambiar de fricción estática a dinámica 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 heatupRate = 1f; // Qué tan rápido sube HighSlippery
const float cooldownRate = 0.2f; // Qué tan rápido baja HighSlippery const float cooldownRate = 1f; // Qué tan rápido baja HighSlippery
const float staticFriction = 0.30f; const float staticFriction = 0.80f;
const float dynamicFriction = 0.10f; const float dynamicFriction = 0.50f;
// Sistema de heatup/cooldown para HighSlippery // Sistema de heatup/cooldown para HighSlippery
if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0 if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0
@ -381,12 +351,17 @@ namespace CtrEditor.Simulacion
// Calcular fricción basada en HighSlippery // Calcular fricción basada en HighSlippery
// HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática // HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática
if (botella.HighSlippery > 3f) if (botella.ContactPressure > 0)
return dynamicFriction / 10;
else
{
if (botella.HighSlippery > 1f)
return dynamicFriction; return dynamicFriction;
else else
return staticFriction; return staticFriction;
} }
} }
}
catch (Exception ex) catch (Exception ex)
{ {
System.Diagnostics.Debug.WriteLine($"[CalculateTransportFriction] Error: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"[CalculateTransportFriction] Error: {ex.Message}");
@ -420,9 +395,9 @@ namespace CtrEditor.Simulacion
float slipSpeedThreshold = curveVelocityAtPoint.Length() * 0.85f; // m/s float slipSpeedThreshold = curveVelocityAtPoint.Length() * 0.85f; // m/s
const float heatupRate = 1f; // Qué tan rápido sube HighSlippery en curvas const float heatupRate = 1f; // Qué tan rápido sube HighSlippery en curvas
const float cooldownRate = 0.2f; // Qué tan rápido baja HighSlippery en curvas const float cooldownRate = 1f; // Qué tan rápido baja HighSlippery en curvas
const float staticFriction = 0.30f; const float staticFriction = 0.80f;
const float dynamicFriction = 0.10f; const float dynamicFriction = 0.50f;
// Sistema de heatup/cooldown para HighSlippery // Sistema de heatup/cooldown para HighSlippery
if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0 if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0
@ -432,12 +407,17 @@ namespace CtrEditor.Simulacion
// Calcular fricción basada en HighSlippery // Calcular fricción basada en HighSlippery
// HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática // HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática
if (botella.ContactPressure > 0)
return dynamicFriction / 10;
else
{
if (botella.HighSlippery > 3f) if (botella.HighSlippery > 3f)
return dynamicFriction; return dynamicFriction;
else else
return staticFriction; return staticFriction;
} }
} }
}
catch (Exception ex) catch (Exception ex)
{ {
System.Diagnostics.Debug.WriteLine($"[CalculateCurveFriction] Error: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"[CalculateCurveFriction] Error: {ex.Message}");
@ -654,11 +634,7 @@ namespace CtrEditor.Simulacion
public Dictionary<int, simBase> CollidableData = new Dictionary<int, simBase>(); public Dictionary<int, simBase> CollidableData = new Dictionary<int, simBase>();
public float GlobalTime { get; private set; } public float GlobalTime { get; private set; }
// ✅ NUEVO: Sistema de limitación de fuerzas para contactos múltiples simultáneos // ✅ ELIMINADO: Sistema de limitación de fuerzas - reemplazado por intervención post-solver
private Dictionary<Vector3, int> _contactDensityMap = new Dictionary<Vector3, int>();
private const int MAX_SIMULTANEOUS_CONTACTS = 10; // Máximo número de contactos antes de aplicar clamp
private const float CONTACT_REGION_SIZE = 0.5f; // Tamaño de región para agrupar contactos (metros)
private const float MAX_FORCE_SCALE_FACTOR = 0.3f; // Factor mínimo de escala cuando hay muchos contactos
/// <summary> /// <summary>
/// Obtiene el objeto simBase correspondiente a un BodyHandle /// Obtiene el objeto simBase correspondiente a un BodyHandle
@ -852,6 +828,7 @@ namespace CtrEditor.Simulacion
{ {
var body = simulation.Bodies.GetBodyReference(botella.BodyHandle); var body = simulation.Bodies.GetBodyReference(botella.BodyHandle);
var velocity = body.Velocity; var velocity = body.Velocity;
var position = body.Pose.Position;
// CONFIGURACIÓN DE LÍMITES // CONFIGURACIÓN DE LÍMITES
const float maxUpwardVelocity = 0f; // Velocidad Z máxima hacia arriba (m/s) const float maxUpwardVelocity = 0f; // Velocidad Z máxima hacia arriba (m/s)
@ -860,23 +837,24 @@ namespace CtrEditor.Simulacion
if (velocity.Linear.Z > maxUpwardVelocity) if (velocity.Linear.Z > maxUpwardVelocity)
{ {
// Cancelar velocidades hacia arriba excesivas (anti-elevación) // Cancelar velocidades hacia arriba excesivas (anti-elevación)
velocity.Linear.Z = maxUpwardVelocity; velocity.Linear.Z = 0;
position.Z = botella.Radius + simBase.zPos_Transporte + simBase.zAltura_Transporte;
body.Velocity = velocity; body.Velocity = velocity;
body.Pose = position;
} }
// CONTROL DE POSICIÓN EXTREMA //// CONTROL DE POSICIÓN EXTREMA
// Si la botella está muy por encima del nivel normal, aplicar corrección //// Si la botella está muy por encima del nivel normal, aplicar corrección
var position = body.Pose.Position; //var maxAllowedZ = simBase.zPos_Transporte + simBase.zAltura_Transporte + botella.Radius * 2;
var maxAllowedZ = simBase.zPos_Transporte + simBase.zAltura_Transporte + botella.Radius * 2;
if (position.Z > maxAllowedZ) //if (position.Z > maxAllowedZ)
{ //{
// Aplicar velocidad correctiva hacia abajo // // Aplicar velocidad correctiva hacia abajo
var excessHeight = position.Z - maxAllowedZ; // var excessHeight = position.Z - maxAllowedZ;
var correctionVelocity = -Math.Min(excessHeight * 5f, 0.5f); // Máximo 0.5 m/s hacia abajo // var correctionVelocity = -Math.Min(excessHeight * 5f, 0.5f); // Máximo 0.5 m/s hacia abajo
velocity.Linear.Z = correctionVelocity; // velocity.Linear.Z = correctionVelocity;
body.Velocity = velocity; // body.Velocity = velocity;
} //}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -1029,11 +1007,7 @@ namespace CtrEditor.Simulacion
botella.ContactPressure = 0f; botella.ContactPressure = 0f;
} }
// ✅ NUEVO: RESETEAR MAPA DE DENSIDAD DE CONTACTOS // ✅ ELIMINADO: Reset del mapa de densidad de contactos ya no necesario
lock (_contactsLock)
{
_contactDensityMap.Clear();
}
// ✅ ELIMINADO: ApplyZForceLimitation - ahora usamos intervención post-solver en OnSubstepEnded // ✅ ELIMINADO: ApplyZForceLimitation - ahora usamos intervención post-solver en OnSubstepEnded
@ -1597,95 +1571,8 @@ namespace CtrEditor.Simulacion
return lineStart + lineDirection * projectionLength; return lineStart + lineDirection * projectionLength;
} }
/// <summary> // ✅ ELIMINADO: Funciones del sistema de limitación de fuerzas forceScale
/// ✅ NUEVA FUNCIÓN: Discretiza una posición en regiones para el tracking de densidad de contactos // GetContactRegion, RegisterContactAndGetForceScale, GetContactPosition
/// </summary>
private Vector3 GetContactRegion(Vector3 position)
{
// Discretizar la posición en regiones de tamaño CONTACT_REGION_SIZE
return new Vector3(
MathF.Floor(position.X / CONTACT_REGION_SIZE) * CONTACT_REGION_SIZE,
MathF.Floor(position.Y / CONTACT_REGION_SIZE) * CONTACT_REGION_SIZE,
MathF.Floor(position.Z / CONTACT_REGION_SIZE) * CONTACT_REGION_SIZE
);
}
/// <summary>
/// ✅ NUEVA FUNCIÓN: Registra un contacto en el mapa de densidad y retorna el factor de escala de fuerzas
/// </summary>
public float RegisterContactAndGetForceScale(Vector3 contactPosition)
{
try
{
var region = GetContactRegion(contactPosition);
lock (_contactsLock)
{
// Incrementar contador de contactos en esta región
if (_contactDensityMap.ContainsKey(region))
{
_contactDensityMap[region]++;
}
else
{
_contactDensityMap[region] = 1;
}
var contactCount = _contactDensityMap[region];
// Calcular factor de escala basado en número de contactos
if (contactCount <= MAX_SIMULTANEOUS_CONTACTS)
{
return 1.0f; // Sin limitación
}
else
{
// Aplicar factor de escala que decrece con más contactos
// Factor va desde 1.0 (10 contactos) hasta MAX_FORCE_SCALE_FACTOR (muchos contactos)
var excessContacts = contactCount - MAX_SIMULTANEOUS_CONTACTS;
var scaleFactor = 1.0f - (excessContacts * 0.05f); // Reducir 5% por cada contacto extra
return Math.Max(scaleFactor, MAX_FORCE_SCALE_FACTOR);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[RegisterContactAndGetForceScale] Error: {ex.Message}");
return 1.0f; // Sin limitación en caso de error
}
}
/// <summary>
/// ✅ NUEVA FUNCIÓN: Calcula la posición promedio de contacto entre dos collidables
/// </summary>
public Vector3 GetContactPosition(CollidablePair pair)
{
try
{
Vector3 positionA = Vector3.Zero;
Vector3 positionB = Vector3.Zero;
// Obtener posición del primer objeto
if (pair.A.BodyHandle.Value >= 0 && simulation?.Bodies?.BodyExists(pair.A.BodyHandle) == true)
{
positionA = simulation.Bodies[pair.A.BodyHandle].Pose.Position;
}
// Obtener posición del segundo objeto
if (pair.B.BodyHandle.Value >= 0 && simulation?.Bodies?.BodyExists(pair.B.BodyHandle) == true)
{
positionB = simulation.Bodies[pair.B.BodyHandle].Pose.Position;
}
// Retornar punto medio
return (positionA + positionB) * 0.5f;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[GetContactPosition] Error: {ex.Message}");
return Vector3.Zero;
}
}
// ✅ ELIMINADO: ApplyZForceLimitation - reemplazado por intervención post-solver en OnSubstepEnded // ✅ ELIMINADO: ApplyZForceLimitation - reemplazado por intervención post-solver en OnSubstepEnded