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:
parent
b44bdc5ece
commit
18017db56a
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 normales para contactos superficiales - botellas rígidas
|
||||||
{
|
pairMaterial.FrictionCoefficient = 0.02f;
|
||||||
// Fuerzas controladas para penetraciones profundas - evitar explosiones pero mantener rigidez
|
pairMaterial.MaximumRecoveryVelocity = 1f; // ✅ REMOVIDO: * forceScale
|
||||||
pairMaterial.FrictionCoefficient = 0.01f;
|
pairMaterial.SpringSettings = new SpringSettings(40, 10f); // ✅ REMOVIDO: * forceScale
|
||||||
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
|
|
||||||
pairMaterial.FrictionCoefficient = 0.02f;
|
|
||||||
pairMaterial.MaximumRecoveryVelocity = 0.5f * forceScale; // ✅ APLICAR FACTOR DE ESCALA
|
|
||||||
pairMaterial.SpringSettings = new SpringSettings(150 * forceScale, 10f); // ✅ APLICAR FACTOR DE ESCALA
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 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,10 +351,15 @@ 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;
|
return dynamicFriction / 10;
|
||||||
else
|
else
|
||||||
return staticFriction;
|
{
|
||||||
|
if (botella.HighSlippery > 1f)
|
||||||
|
return dynamicFriction;
|
||||||
|
else
|
||||||
|
return staticFriction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -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,10 +407,15 @@ 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;
|
return dynamicFriction / 10;
|
||||||
else
|
else
|
||||||
return staticFriction;
|
{
|
||||||
|
if (botella.HighSlippery > 3f)
|
||||||
|
return dynamicFriction;
|
||||||
|
else
|
||||||
|
return staticFriction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue