g
This commit is contained in:
@@ -44,11 +44,15 @@ This is an Unreal Engine plugin that uses Unreal's build system. The plugin comp
|
|||||||
### Key Features
|
### Key Features
|
||||||
|
|
||||||
- **Realistic Physics**: Atmospheric density, temperature, pressure effects
|
- **Realistic Physics**: Atmospheric density, temperature, pressure effects
|
||||||
- **Material Penetration**: Configurable penetration depth per material
|
- **Mathematical Ballistics**: Physics-based penetration using Taylor-Hopkinson and Recht-Ipson models
|
||||||
|
- **Material Penetration**: Configurable penetration depth per material with physical material integration
|
||||||
- **Ricochet System**: Angle-based ricochet probability with energy loss
|
- **Ricochet System**: Angle-based ricochet probability with energy loss
|
||||||
|
- **Spalling System**: Secondary fragment generation on high-energy impacts
|
||||||
|
- **Ballistic Impact Component**: Event-driven impact handling with Blueprint events
|
||||||
- **Multiplayer Support**: Full replication with client-side prediction
|
- **Multiplayer Support**: Full replication with client-side prediction
|
||||||
- **Performance Optimization**: Object pooling for high-rate fire scenarios
|
- **Performance Optimization**: Object pooling, LOD systems for high-rate fire scenarios
|
||||||
- **Shotgun Support**: Multi-projectile spawning with configurable spread
|
- **Shotgun Support**: Multi-projectile spawning with configurable spread
|
||||||
|
- **Editor Integration**: Asset factories, smart material recognition, JSON import/export
|
||||||
|
|
||||||
### File Structure
|
### File Structure
|
||||||
|
|
||||||
@@ -83,3 +87,30 @@ Source/EasyBallistics/
|
|||||||
- Integrates with Unreal's physics system for impulse application
|
- Integrates with Unreal's physics system for impulse application
|
||||||
- Supports both simple and complex collision detection
|
- Supports both simple and complex collision detection
|
||||||
- Atmospheric model supports Earth-like conditions or custom curves
|
- Atmospheric model supports Earth-like conditions or custom curves
|
||||||
|
|
||||||
|
## Documentation Structure
|
||||||
|
|
||||||
|
The plugin includes comprehensive documentation in the `/docs` directory:
|
||||||
|
|
||||||
|
### Documentation Categories
|
||||||
|
- **Getting Started**: Installation and quick start guides
|
||||||
|
- **Core Concepts**: Mathematical ballistics, spalling system, impact components
|
||||||
|
- **Tutorials**: Step-by-step guides for material setup and advanced weapons
|
||||||
|
- **Advanced Guides**: Multiplayer, performance optimization, editor integration
|
||||||
|
- **API Reference**: Complete class and function documentation
|
||||||
|
- **Troubleshooting**: Common issues and debugging techniques
|
||||||
|
|
||||||
|
### Key Documentation Files
|
||||||
|
- `docs/docs/intro.md` - Main introduction and overview
|
||||||
|
- `docs/docs/core-concepts/mathematical-ballistics.md` - Physics calculations
|
||||||
|
- `docs/docs/core-concepts/spalling-system.md` - Fragment generation system
|
||||||
|
- `docs/docs/tutorials/material-setup-guide.md` - Material configuration tutorial
|
||||||
|
- `docs/docs/advanced/json-import-export.md` - Data import/export tools
|
||||||
|
- `docs/docs/api/bullet-reference.md` - Complete AEBBullet API
|
||||||
|
- `docs/docs/api/material-properties-reference.md` - Material system API
|
||||||
|
|
||||||
|
### Documentation Build System
|
||||||
|
- Uses Docusaurus 2 for static site generation
|
||||||
|
- Configuration in `docs/docusaurus.config.js`
|
||||||
|
- Sidebar structure in `docs/sidebars.js`
|
||||||
|
- Supports local development: `npm run start` in docs directory
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# EasyBallistics JSON Import/Export Tool
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The EasyBallistics JSON Import/Export Tool allows you to import and export bullet properties and material response configurations as JSON files. This is useful for:
|
||||||
|
|
||||||
|
- Sharing ballistic configurations between projects
|
||||||
|
- Backing up and versioning ballistic data
|
||||||
|
- Batch editing configurations outside of Unreal Engine
|
||||||
|
- Integration with external ballistics calculators
|
||||||
|
|
||||||
|
## Accessing the Tool
|
||||||
|
|
||||||
|
1. In the Unreal Engine editor, go to **Window > Ballistics JSON Import/Export**
|
||||||
|
2. This will open the JSON Import/Export tool window
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Bullet Properties Export/Import
|
||||||
|
|
||||||
|
**Export**: Creates a JSON file with all mathematical bullet properties including:
|
||||||
|
- Basic properties (grain weight, diameter, length, bullet type, material)
|
||||||
|
- Ballistic coefficients (G1/G7)
|
||||||
|
- Penetration properties (hardness, energy thresholds, expansion)
|
||||||
|
|
||||||
|
**Import**: Loads bullet properties from a JSON file and can create new bullet property assets
|
||||||
|
|
||||||
|
### Material Response Export/Import
|
||||||
|
|
||||||
|
**Export**: Creates a JSON file with material response settings including:
|
||||||
|
- Artistic properties (penetration, ricochet settings)
|
||||||
|
- Spalling properties (fragment generation)
|
||||||
|
- Mathematical material properties (density, hardness, strength values)
|
||||||
|
|
||||||
|
**Import**: Loads material response configurations from JSON files
|
||||||
|
|
||||||
|
## JSON Format Examples
|
||||||
|
|
||||||
|
### Bullet Properties JSON Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"GrainWeight": 55.0,
|
||||||
|
"DiameterInches": 0.224,
|
||||||
|
"LengthInches": 0.825,
|
||||||
|
"BulletType": 0,
|
||||||
|
"BulletMaterial": 3,
|
||||||
|
"BallisticCoefficientG1": 0.151,
|
||||||
|
"BallisticCoefficientG7": 0.076,
|
||||||
|
"UseG7Model": false,
|
||||||
|
"SectionalDensity": 0.0,
|
||||||
|
"BulletHardness": 15.0,
|
||||||
|
"PenetrationEnergyThreshold": 58.0,
|
||||||
|
"ExpansionVelocityThreshold": 1800.0,
|
||||||
|
"MaxExpansionMultiplier": 1.5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Material Response JSON Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PenTraceType": 0,
|
||||||
|
"NeverPenetrate": false,
|
||||||
|
"PenetrationDepthMultiplier": 1.0,
|
||||||
|
"PenetrationNormalization": 0.0,
|
||||||
|
"PenetrationNormalizationGrazing": 0.0,
|
||||||
|
"PenetrationEntryAngleSpread": 0.0,
|
||||||
|
"PenetrationExitAngleSpread": 0.0,
|
||||||
|
"NeverRicochet": false,
|
||||||
|
"RicochetProbabilityMultiplier": 1.0,
|
||||||
|
"RicochetRestitution": 0.5,
|
||||||
|
"RicochetRestitutionInfluence": 0.0,
|
||||||
|
"RicochetFriction": 0.5,
|
||||||
|
"RicochetFrictionInfluence": 0.0,
|
||||||
|
"RicochetSpread": 0.0,
|
||||||
|
"EnableSpalling": false,
|
||||||
|
"SpallVelocityThreshold": 50000.0,
|
||||||
|
"SpallFragmentCount": 3,
|
||||||
|
"SpallSpreadAngle": 45.0,
|
||||||
|
"SpallVelocityMultiplier": 0.3,
|
||||||
|
"SpallMassMultiplier": 0.1,
|
||||||
|
"UseMathematicalProperties": false,
|
||||||
|
"MathematicalProperties": {
|
||||||
|
"DensityGPerCm3": 7.85,
|
||||||
|
"MaterialHardness": 200.0,
|
||||||
|
"TensileStrengthMPa": 400.0,
|
||||||
|
"YieldStrengthMPa": 250.0,
|
||||||
|
"ElasticModulusGPa": 200.0,
|
||||||
|
"BallisticLimitVelocity": 2000.0,
|
||||||
|
"PerforationCoefficient": 1.0,
|
||||||
|
"EnergyAbsorptionCoefficient": 0.7,
|
||||||
|
"EnableMathematicalSpalling": false,
|
||||||
|
"SpallStrengthMPa": 150.0,
|
||||||
|
"CriticalStressFactor": 2.5,
|
||||||
|
"FragmentVelocityEfficiency": 0.25,
|
||||||
|
"AverageFragmentMassRatio": 0.08,
|
||||||
|
"FragmentSizeExponent": -1.6,
|
||||||
|
"MaxFragmentDensity": 50.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Enum Values Reference
|
||||||
|
|
||||||
|
### BulletType
|
||||||
|
- 0: Full Metal Jacket
|
||||||
|
- 1: Hollow Point
|
||||||
|
- 2: Soft Point
|
||||||
|
- 3: Armor Piercing
|
||||||
|
- 4: Armor Piercing Incendiary
|
||||||
|
- 5: Tracer
|
||||||
|
- 6: Match Grade
|
||||||
|
- 7: Frangible
|
||||||
|
- 8: Lead Round Nose
|
||||||
|
- 9: Wadcutter
|
||||||
|
- 10: Semi-Wadcutter
|
||||||
|
- 11: Custom
|
||||||
|
|
||||||
|
### BulletMaterial
|
||||||
|
- 0: Lead
|
||||||
|
- 1: Lead-Antimony
|
||||||
|
- 2: Copper
|
||||||
|
- 3: Copper Jacket
|
||||||
|
- 4: Brass
|
||||||
|
- 5: Steel
|
||||||
|
- 6: Tungsten
|
||||||
|
- 7: Bismuth
|
||||||
|
- 8: Zinc
|
||||||
|
- 9: Custom
|
||||||
|
|
||||||
|
### PenTraceType
|
||||||
|
- 0: Back Trace
|
||||||
|
- 1: By Component
|
||||||
|
- 2: Double Sided Geometry
|
||||||
|
|
||||||
|
## Usage Tips
|
||||||
|
|
||||||
|
1. **Backup Before Import**: Always backup your existing assets before importing new configurations
|
||||||
|
2. **Validation**: The tool performs basic validation but always test imported configurations in your project
|
||||||
|
3. **Version Control**: Include JSON files in your version control system for configuration tracking
|
||||||
|
4. **Batch Operations**: You can modify multiple configurations by editing JSON files in bulk
|
||||||
|
|
||||||
|
## Technical Notes
|
||||||
|
|
||||||
|
- The tool uses Unreal Engine's JSON parsing system for reliability
|
||||||
|
- All numeric values maintain their original precision
|
||||||
|
- Boolean and enum values are preserved exactly
|
||||||
|
- The tool supports the complete EasyBallistics property set
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
# Parameter Validation Reference
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document provides comprehensive validation ranges, typical values, and quality assurance guidelines for ballistic simulation parameters. Use this reference to verify that your configuration values are physically realistic and within expected bounds.
|
||||||
|
|
||||||
|
## Bullet Properties Validation
|
||||||
|
|
||||||
|
### Physical Dimensions
|
||||||
|
|
||||||
|
#### Grain Weight Validation
|
||||||
|
| Caliber Category | Typical Range (grains) | Examples |
|
||||||
|
|------------------|------------------------|----------|
|
||||||
|
| Rimfire | 20-60 | .22 LR: 30-40 gr |
|
||||||
|
| Small Pistol | 60-130 | 9mm: 115-147 gr |
|
||||||
|
| Large Pistol | 130-300 | .45 ACP: 200-230 gr |
|
||||||
|
| Small Rifle | 40-90 | .223: 55-77 gr |
|
||||||
|
| Medium Rifle | 100-200 | .308: 150-180 gr |
|
||||||
|
| Large Rifle | 200-500 | .338: 250-300 gr |
|
||||||
|
| Anti-Material | 500-750+ | .50 BMG: 647-750 gr |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Weight should correlate with caliber size
|
||||||
|
- Unusually light bullets (<20 gr) may indicate frangible/training rounds
|
||||||
|
- Unusually heavy bullets (>300 gr for caliber) may indicate specialty rounds
|
||||||
|
|
||||||
|
#### Diameter Validation
|
||||||
|
| Caliber | Actual Diameter (inches) | Metric Equivalent |
|
||||||
|
|---------|--------------------------|-------------------|
|
||||||
|
| .17 | 0.172 | 4.37mm |
|
||||||
|
| .22 | 0.224 | 5.69mm |
|
||||||
|
| .24 | 0.243 | 6.17mm |
|
||||||
|
| .25 | 0.257 | 6.53mm |
|
||||||
|
| .27 | 0.277 | 7.04mm |
|
||||||
|
| .28 | 0.284 | 7.21mm |
|
||||||
|
| .30 | 0.308 | 7.82mm |
|
||||||
|
| .32 | 0.312 | 7.92mm |
|
||||||
|
| .35 | 0.358 | 9.09mm |
|
||||||
|
| .38 | 0.357 | 9.07mm |
|
||||||
|
| .40 | 0.400 | 10.16mm |
|
||||||
|
| .44 | 0.429 | 10.90mm |
|
||||||
|
| .45 | 0.452 | 11.48mm |
|
||||||
|
| .50 | 0.510 | 12.95mm |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Diameter must be positive and reasonable (0.1-0.8 inches typical)
|
||||||
|
- Should match known caliber specifications
|
||||||
|
- Metric conversions should be consistent
|
||||||
|
|
||||||
|
#### Length-to-Diameter Ratio
|
||||||
|
| Bullet Type | Typical L/D Ratio | Length Range (inches) |
|
||||||
|
|-------------|-------------------|----------------------|
|
||||||
|
| Round Nose | 1.5-2.5 | Short, traditional design |
|
||||||
|
| Spitzer | 2.5-4.0 | Pointed, aerodynamic |
|
||||||
|
| Boat Tail | 3.0-4.5 | Long, high BC |
|
||||||
|
| VLD | 4.0-6.0 | Very Low Drag, match |
|
||||||
|
| Solid | 2.0-5.0 | Monolithic construction |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- L/D ratio should be realistic for bullet type
|
||||||
|
- Very long bullets (L/D > 6) may have stability issues
|
||||||
|
- Very short bullets (L/D < 1.5) are unusual outside specialty applications
|
||||||
|
|
||||||
|
### Ballistic Coefficients
|
||||||
|
|
||||||
|
#### G1 Ballistic Coefficient Ranges
|
||||||
|
| Bullet Shape | BC Range | Description |
|
||||||
|
|--------------|----------|-------------|
|
||||||
|
| Round Nose | 0.15-0.25 | Traditional, poor aerodynamics |
|
||||||
|
| Flat Point | 0.20-0.30 | Lever gun bullets |
|
||||||
|
| Spitzer | 0.25-0.45 | Standard pointed bullets |
|
||||||
|
| Boat Tail | 0.35-0.55 | Improved base design |
|
||||||
|
| Match/VLD | 0.45-0.70+ | Optimized for accuracy |
|
||||||
|
| Ultra-High BC | 0.70-1.0+ | Specialized long-range |
|
||||||
|
|
||||||
|
#### G7 to G1 Conversion
|
||||||
|
- G7 BC typically 0.5-0.7× the G1 value for modern bullets
|
||||||
|
- Conversion varies by bullet shape and velocity regime
|
||||||
|
- G7 more accurate for boat-tail designs
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- BC should correlate with bullet shape and quality
|
||||||
|
- Extremely high BC (>0.8 G1) requires verification
|
||||||
|
- G7 values should be lower than corresponding G1 values
|
||||||
|
|
||||||
|
### Material Properties
|
||||||
|
|
||||||
|
#### Bullet Hardness (BHN)
|
||||||
|
| Material | Hardness Range | Applications |
|
||||||
|
|----------|----------------|--------------|
|
||||||
|
| Pure Lead | 5-8 BHN | Cast bullets, training |
|
||||||
|
| Wheel Weights | 12-15 BHN | Economy cast bullets |
|
||||||
|
| Linotype | 22-25 BHN | Hard cast bullets |
|
||||||
|
| Swaged Lead | 8-12 BHN | Commercial lead bullets |
|
||||||
|
| Copper Plated | 10-15 BHN | Plated lead core |
|
||||||
|
| Copper Jacket | 15-25 BHN | FMJ bullets |
|
||||||
|
| Brass | 60-120 BHN | Solid brass bullets |
|
||||||
|
| Copper Solid | 35-80 BHN | Monolithic copper |
|
||||||
|
| Steel Core | 150-300 BHN | AP bullets |
|
||||||
|
| Tungsten | 300-400 BHN | High-density cores |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Hardness should match material type
|
||||||
|
- Jacket hardness is composite value including core
|
||||||
|
- Extremely hard bullets (>400 BHN) are specialized
|
||||||
|
|
||||||
|
#### Energy and Velocity Thresholds
|
||||||
|
|
||||||
|
**Penetration Energy Threshold (ft-lbs)**
|
||||||
|
| Application | Energy Range | Examples |
|
||||||
|
|-------------|--------------|----------|
|
||||||
|
| Small Game | 10-25 | Squirrel, rabbit |
|
||||||
|
| Varmint | 25-75 | Prairie dog, coyote |
|
||||||
|
| Deer | 75-150 | White-tail deer |
|
||||||
|
| Elk | 150-300 | Large game |
|
||||||
|
| Dangerous Game | 300-500+ | Bear, buffalo |
|
||||||
|
| Armor Piercing | 500-2000+ | Military applications |
|
||||||
|
|
||||||
|
**Expansion Velocity Threshold (fps)**
|
||||||
|
| Bullet Type | Velocity Range | Notes |
|
||||||
|
|-------------|----------------|-------|
|
||||||
|
| Handgun HP | 800-1200 | Lower velocity expansion |
|
||||||
|
| Rifle HP | 1600-2200 | Standard hunting bullets |
|
||||||
|
| Premium Hunting | 1400-1800 | Controlled expansion |
|
||||||
|
| Varmint | 2000-3000 | Rapid expansion |
|
||||||
|
| Match | N/A | Non-expanding |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Energy thresholds should match intended use
|
||||||
|
- Expansion velocities should be achievable at impact range
|
||||||
|
- Thresholds should be lower than typical muzzle velocities
|
||||||
|
|
||||||
|
## Material Response Validation
|
||||||
|
|
||||||
|
### Physical Properties
|
||||||
|
|
||||||
|
#### Density Values (g/cm³)
|
||||||
|
| Material Category | Density Range | Common Materials |
|
||||||
|
|-------------------|---------------|------------------|
|
||||||
|
| Woods | 0.3-1.2 | Balsa (0.16), Oak (0.75), Ebony (1.2) |
|
||||||
|
| Plastics | 0.9-2.0 | PE (0.95), Nylon (1.15), PVC (1.4) |
|
||||||
|
| Aluminum Alloys | 2.6-2.8 | 1100 (2.71), 6061 (2.70), 7075 (2.81) |
|
||||||
|
| Concrete | 2.0-2.8 | Normal (2.4), High-strength (2.6) |
|
||||||
|
| Titanium Alloys | 4.4-4.9 | Ti-6Al-4V (4.43), CP Ti (4.51) |
|
||||||
|
| Steel | 7.7-8.1 | Mild (7.85), Stainless (8.0) |
|
||||||
|
| Lead | 11.3-11.4 | Pure lead (11.34) |
|
||||||
|
| Tungsten | 19.2-19.3 | Pure tungsten (19.25) |
|
||||||
|
|
||||||
|
#### Hardness Correlation
|
||||||
|
**Brinell Hardness (HB)**
|
||||||
|
| Material | Hardness Range | Strength Correlation |
|
||||||
|
|----------|----------------|---------------------|
|
||||||
|
| Aluminum (soft) | 15-30 | Low strength |
|
||||||
|
| Aluminum (hard) | 60-150 | Heat treated |
|
||||||
|
| Steel (mild) | 120-200 | Structural steel |
|
||||||
|
| Steel (medium) | 200-300 | Heat treated |
|
||||||
|
| Steel (hard) | 300-500 | Tool steel |
|
||||||
|
| Steel (very hard) | 500-700 | Hardened/tempered |
|
||||||
|
| Ceramics | 1000-2000+ | Very brittle |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Hardness should correlate with tensile strength
|
||||||
|
- Rule of thumb: BHN ≈ 3.45 × Tensile Strength (ksi)
|
||||||
|
- Very hard materials often brittle
|
||||||
|
|
||||||
|
#### Strength Properties (MPa)
|
||||||
|
|
||||||
|
**Tensile Strength Ranges**
|
||||||
|
| Material Class | Yield Strength | Tensile Strength | Ratio (Yield/Tensile) |
|
||||||
|
|----------------|----------------|------------------|----------------------|
|
||||||
|
| Aluminum (soft) | 35-100 | 90-200 | 0.4-0.5 |
|
||||||
|
| Aluminum (hard) | 200-500 | 300-600 | 0.6-0.8 |
|
||||||
|
| Steel (mild) | 200-400 | 400-600 | 0.5-0.7 |
|
||||||
|
| Steel (high strength) | 400-1000 | 600-1200 | 0.7-0.8 |
|
||||||
|
| Stainless Steel | 200-800 | 500-1000 | 0.4-0.8 |
|
||||||
|
| Titanium | 200-1000 | 300-1200 | 0.6-0.8 |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Yield strength must be ≤ tensile strength
|
||||||
|
- Typical ratio: yield = 50-80% of tensile
|
||||||
|
- Higher ratios indicate brittle materials
|
||||||
|
|
||||||
|
### Ballistic Properties
|
||||||
|
|
||||||
|
#### Ballistic Limit Velocities (fps)
|
||||||
|
| Material/Thickness | Velocity Range | Projectile Type |
|
||||||
|
|-------------------|----------------|-----------------|
|
||||||
|
| Aluminum 0.25" | 800-1500 | Standard ball |
|
||||||
|
| Steel 0.25" | 1500-2500 | Standard ball |
|
||||||
|
| Steel 0.5" | 2500-3500 | Standard ball |
|
||||||
|
| Kevlar vest | 1200-1800 | Handgun bullets |
|
||||||
|
| Ceramic tile | 2000-3500 | Rifle bullets |
|
||||||
|
| Glass | 200-800 | Low-velocity impacts |
|
||||||
|
|
||||||
|
#### Energy Absorption Coefficients
|
||||||
|
| Material Type | Coefficient Range | Mechanism |
|
||||||
|
|---------------|-------------------|-----------|
|
||||||
|
| Soft (foam, sand) | 0.8-1.0 | Compression/displacement |
|
||||||
|
| Wood/Plastic | 0.6-0.8 | Crushing/deformation |
|
||||||
|
| Aluminum | 0.5-0.7 | Plastic deformation |
|
||||||
|
| Mild Steel | 0.4-0.6 | Plastic deformation |
|
||||||
|
| Hard Steel | 0.2-0.4 | Limited deformation |
|
||||||
|
| Ceramics | 0.3-0.5 | Fracture/pulverization |
|
||||||
|
|
||||||
|
### Ricochet Properties
|
||||||
|
|
||||||
|
#### Ricochet Probability by Material
|
||||||
|
| Surface Type | Probability Multiplier | Impact Angle Dependency |
|
||||||
|
|--------------|------------------------|------------------------|
|
||||||
|
| Water | 0.3-0.7 | High angle dependency |
|
||||||
|
| Concrete | 0.8-1.2 | Moderate dependency |
|
||||||
|
| Steel (mild) | 1.0-1.5 | Low angle dependency |
|
||||||
|
| Steel (hard) | 1.2-2.0 | Very low dependency |
|
||||||
|
| Ice | 1.2-1.8 | Temperature dependent |
|
||||||
|
| Rock/Stone | 0.6-1.4 | Surface roughness dependent |
|
||||||
|
|
||||||
|
#### Restitution Coefficients
|
||||||
|
| Material Pair | Coefficient Range | Energy Retention |
|
||||||
|
|---------------|-------------------|------------------|
|
||||||
|
| Lead-Steel | 0.2-0.4 | Low retention |
|
||||||
|
| Copper-Steel | 0.3-0.5 | Moderate retention |
|
||||||
|
| Steel-Steel | 0.5-0.7 | High retention |
|
||||||
|
| Tungsten-Steel | 0.6-0.8 | Very high retention |
|
||||||
|
|
||||||
|
### Spalling Parameters
|
||||||
|
|
||||||
|
#### Velocity Thresholds by Material
|
||||||
|
| Material | Threshold (cm/s) | Threshold (fps) | Fragment Characteristics |
|
||||||
|
|----------|------------------|-----------------|-------------------------|
|
||||||
|
| Glass | 15,000-30,000 | 500-1000 | Sharp, dangerous |
|
||||||
|
| Concrete | 30,000-60,000 | 1000-2000 | Angular, dust |
|
||||||
|
| Aluminum | 60,000-90,000 | 2000-3000 | Metal flakes |
|
||||||
|
| Mild Steel | 90,000-150,000 | 3000-5000 | Metal fragments |
|
||||||
|
| Hard Steel | 150,000+ | 5000+ | Small, high-velocity |
|
||||||
|
|
||||||
|
#### Fragment Count Guidelines
|
||||||
|
| Impact Energy | Fragment Count | Material Type |
|
||||||
|
|---------------|----------------|---------------|
|
||||||
|
| Low (<1000 ft-lbs) | 1-3 | Brittle materials only |
|
||||||
|
| Medium (1000-5000) | 3-8 | Most materials |
|
||||||
|
| High (5000-15000) | 8-15 | High-energy impacts |
|
||||||
|
| Very High (>15000) | 15-25 | Extreme conditions |
|
||||||
|
|
||||||
|
**Quality Checks:**
|
||||||
|
- Fragment count should scale with impact energy
|
||||||
|
- Brittle materials generate more fragments
|
||||||
|
- Consider computational cost vs. realism
|
||||||
|
|
||||||
|
## Validation Procedures
|
||||||
|
|
||||||
|
### Cross-Reference Validation
|
||||||
|
1. **Material Databases**: ASM International, NIST
|
||||||
|
2. **Military Standards**: MIL-HDBK, NATO STANAGs
|
||||||
|
3. **Industry Standards**: ASTM, SAE, AISI
|
||||||
|
4. **Academic Literature**: Peer-reviewed journals
|
||||||
|
|
||||||
|
### Physical Consistency Checks
|
||||||
|
1. **Density-Strength Correlation**: Generally, denser materials are stronger
|
||||||
|
2. **Hardness-Strength Relationship**: BHN ≈ 3.45 × UTS (ksi)
|
||||||
|
3. **Yield-Tensile Ratio**: Yield typically 50-80% of tensile strength
|
||||||
|
4. **Elastic Modulus**: Should match material class
|
||||||
|
|
||||||
|
### Ballistic Reasonableness
|
||||||
|
1. **BC vs. Shape**: High BC requires good aerodynamic shape
|
||||||
|
2. **Energy vs. Caliber**: Larger calibers generally have more energy
|
||||||
|
3. **Velocity Thresholds**: Should be achievable at intended range
|
||||||
|
4. **Material Response**: Should match known ballistic test results
|
||||||
|
|
||||||
|
### Common Validation Errors
|
||||||
|
|
||||||
|
#### Bullet Properties
|
||||||
|
- **Impossible BC**: Values >1.0 require careful verification
|
||||||
|
- **Mismatched Dimensions**: Diameter doesn't match caliber designation
|
||||||
|
- **Unrealistic Hardness**: Values inconsistent with material type
|
||||||
|
- **Inappropriate Thresholds**: Energy/velocity values too high/low for application
|
||||||
|
|
||||||
|
#### Material Properties
|
||||||
|
- **Inverted Strength Values**: Yield > tensile strength
|
||||||
|
- **Impossible Density**: Values outside known material ranges
|
||||||
|
- **Inconsistent Hardness**: Doesn't correlate with strength values
|
||||||
|
- **Unrealistic Ballistic Limits**: Too high/low for material thickness
|
||||||
|
|
||||||
|
### Quality Assurance Checklist
|
||||||
|
|
||||||
|
#### Before Simulation
|
||||||
|
- [ ] All values within documented ranges
|
||||||
|
- [ ] Physical relationships consistent (yield ≤ tensile, etc.)
|
||||||
|
- [ ] Units correct and consistent
|
||||||
|
- [ ] Sources documented for traceability
|
||||||
|
- [ ] Cross-referenced with multiple sources
|
||||||
|
|
||||||
|
#### During Simulation
|
||||||
|
- [ ] Results match expected physical behavior
|
||||||
|
- [ ] No obvious artifacts or anomalies
|
||||||
|
- [ ] Performance acceptable for application
|
||||||
|
- [ ] Sensitivity analysis completed
|
||||||
|
|
||||||
|
#### After Simulation
|
||||||
|
- [ ] Results compared to experimental data when available
|
||||||
|
- [ ] Peer review of critical parameters
|
||||||
|
- [ ] Documentation updated with lessons learned
|
||||||
|
- [ ] Parameters archived for reproducibility
|
||||||
|
|
||||||
|
## Recommended References
|
||||||
|
|
||||||
|
### Primary Sources
|
||||||
|
1. **ASM International Handbook Series** - Comprehensive material properties
|
||||||
|
2. **Military Ballistics Handbooks** - Validated ballistic data
|
||||||
|
3. **NIST Material Database** - Standardized property values
|
||||||
|
4. **Manufacturer Specifications** - Bullet and ammunition data
|
||||||
|
|
||||||
|
### Academic Journals
|
||||||
|
1. **International Journal of Impact Engineering**
|
||||||
|
2. **Journal of Applied Physics**
|
||||||
|
3. **Experimental Mechanics**
|
||||||
|
4. **Defence Technology**
|
||||||
|
|
||||||
|
### Professional Organizations
|
||||||
|
1. **SAAMI** - Sporting ammunition standards
|
||||||
|
2. **NATO** - Military ammunition specifications
|
||||||
|
3. **ASTM International** - Testing standards
|
||||||
|
4. **ASM International** - Materials engineering
|
||||||
|
|
||||||
|
This validation reference ensures that ballistic simulations are based on physically realistic and well-documented parameters, supporting credible research and engineering applications.
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
# EasyBallistics JSON Configuration Guide for Researchers
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide is designed for researchers, engineers, and scientists who need to configure ballistic simulation parameters without requiring knowledge of game development or Unreal Engine. The configuration files use self-documenting JSON format with embedded explanations.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Understanding the JSON Structure
|
||||||
|
|
||||||
|
Each configuration file follows this pattern:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ParameterName": {
|
||||||
|
"_description": "What this parameter does",
|
||||||
|
"_unit": "Units of measurement",
|
||||||
|
"_typical_values": "Expected ranges",
|
||||||
|
"_examples": "Real-world examples",
|
||||||
|
"value": actual_numeric_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important**: The underscore-prefixed fields (`_description`, `_unit`, etc.) are documentation only. The `value` field contains the actual parameter that affects the simulation.
|
||||||
|
|
||||||
|
### File Types
|
||||||
|
|
||||||
|
1. **Bullet Properties** (`Sample_BulletProperties.json`) - Physical and ballistic characteristics of projectiles
|
||||||
|
2. **Material Response** (`Sample_MaterialResponse.json`) - How materials respond to ballistic impact
|
||||||
|
|
||||||
|
## Bullet Properties Configuration
|
||||||
|
|
||||||
|
### Essential Parameters
|
||||||
|
|
||||||
|
#### Mass and Dimensions
|
||||||
|
- **GrainWeight**: Projectile mass in grains (1 grain = 0.0647989 grams)
|
||||||
|
- Small caliber: 20-80 grains
|
||||||
|
- Medium caliber: 80-200 grains
|
||||||
|
- Large caliber: 200-750+ grains
|
||||||
|
|
||||||
|
- **DiameterInches**: Bullet diameter in inches
|
||||||
|
- Common values: 0.224" (5.56mm), 0.308" (7.62mm), 0.452" (45 ACP)
|
||||||
|
|
||||||
|
- **LengthInches**: Overall bullet length
|
||||||
|
- Typically 0.4-2.0 inches depending on caliber
|
||||||
|
|
||||||
|
#### Ballistic Coefficients
|
||||||
|
Choose **either** G1 or G7 model (set UseG7Model accordingly):
|
||||||
|
|
||||||
|
- **G1 Model**: Traditional standard, good for round-nose bullets
|
||||||
|
- Poor: 0.15-0.25
|
||||||
|
- Average: 0.25-0.45
|
||||||
|
- Excellent: 0.65+
|
||||||
|
|
||||||
|
- **G7 Model**: Better for modern pointed bullets
|
||||||
|
- Typically 0.5-0.7× the G1 value
|
||||||
|
- More accurate for boat-tail designs
|
||||||
|
|
||||||
|
#### Material Properties
|
||||||
|
- **BulletHardness**: Brinell Hardness Number
|
||||||
|
- Lead: 5-15 BHN
|
||||||
|
- Copper jacket: 15-25 BHN
|
||||||
|
- Steel core: 150-600 BHN
|
||||||
|
|
||||||
|
- **PenetrationEnergyThreshold**: Minimum energy for penetration (ft-lbs)
|
||||||
|
- Varies by intended use: 10-500+ ft-lbs
|
||||||
|
|
||||||
|
### Research Applications
|
||||||
|
|
||||||
|
#### Ballistics Research
|
||||||
|
For academic ballistics research, focus on:
|
||||||
|
- Accurate ballistic coefficients from wind tunnel data
|
||||||
|
- Precise mass and dimensional measurements
|
||||||
|
- Material hardness from standardized testing
|
||||||
|
|
||||||
|
#### Terminal Ballistics Studies
|
||||||
|
For penetration and wound ballistics:
|
||||||
|
- Expansion characteristics (velocity thresholds, max expansion)
|
||||||
|
- Energy transfer parameters
|
||||||
|
- Material-specific hardness values
|
||||||
|
|
||||||
|
#### Forensic Applications
|
||||||
|
For bullet identification and trajectory analysis:
|
||||||
|
- Precise dimensional measurements
|
||||||
|
- Material composition data
|
||||||
|
- Manufacturer-specific variations
|
||||||
|
|
||||||
|
## Material Response Configuration
|
||||||
|
|
||||||
|
### Penetration Mechanics
|
||||||
|
|
||||||
|
#### Basic Penetration
|
||||||
|
- **PenetrationDepthMultiplier**: Scaling factor (0.1-10.0)
|
||||||
|
- Use 1.0 as baseline, adjust based on experimental data
|
||||||
|
- Values <1.0 for harder materials, >1.0 for softer
|
||||||
|
|
||||||
|
- **PenetrationNormalization**: Angle dependency (degrees)
|
||||||
|
- 0-15°: Soft materials (wood, plastic)
|
||||||
|
- 15-30°: Medium materials (aluminum, mild steel)
|
||||||
|
- 30-60°: Hard materials (armor steel, ceramics)
|
||||||
|
|
||||||
|
#### Advanced Penetration Modeling
|
||||||
|
When **UseMathematicalProperties** is enabled:
|
||||||
|
|
||||||
|
- **DensityGPerCm3**: Material density from engineering handbooks
|
||||||
|
- **TensileStrengthMPa**: Ultimate tensile strength from material testing
|
||||||
|
- **YieldStrengthMPa**: Yield strength (typically 50-80% of tensile strength)
|
||||||
|
- **BallisticLimitVelocity**: V50 velocity from ballistic testing
|
||||||
|
|
||||||
|
### Ricochet Behavior
|
||||||
|
|
||||||
|
#### Key Parameters
|
||||||
|
- **RicochetProbabilityMultiplier**: Likelihood scaling (0.0-5.0)
|
||||||
|
- 0.0: No ricochets (soft materials)
|
||||||
|
- 1.0: Normal probability
|
||||||
|
- 2.0+: High ricochet materials (hardened steel, ice)
|
||||||
|
|
||||||
|
- **RicochetRestitution**: Energy retention (0.0-1.0)
|
||||||
|
- Soft materials: 0.1-0.3
|
||||||
|
- Hard materials: 0.7-0.9
|
||||||
|
|
||||||
|
### Spalling and Fragmentation
|
||||||
|
|
||||||
|
#### When to Enable Spalling
|
||||||
|
Spalling is relevant for:
|
||||||
|
- Brittle materials (concrete, ceramics, glass)
|
||||||
|
- High-energy impacts (>2000 fps)
|
||||||
|
- Research into secondary fragmentation effects
|
||||||
|
|
||||||
|
#### Critical Parameters
|
||||||
|
- **SpallVelocityThreshold**: Minimum impact velocity (cm/s)
|
||||||
|
- Glass: 15,000-30,000 cm/s
|
||||||
|
- Concrete: 30,000-60,000 cm/s
|
||||||
|
- Steel: 60,000+ cm/s
|
||||||
|
|
||||||
|
- **SpallFragmentCount**: Number of fragments (1-20)
|
||||||
|
- Balance realism vs. computational cost
|
||||||
|
- Typical: 3-8 fragments for most materials
|
||||||
|
|
||||||
|
## Data Sources and Validation
|
||||||
|
|
||||||
|
### Recommended References
|
||||||
|
|
||||||
|
#### Bullet Properties
|
||||||
|
1. **Manufacturer Data**: Official ballistic coefficients and specifications
|
||||||
|
2. **Ballistic Tables**: Sierra, Hornady, Nosler reloading manuals
|
||||||
|
3. **Military Standards**: NATO STANAG documents for military ammunition
|
||||||
|
4. **SAAMI Standards**: Sporting Arms and Ammunition Manufacturers' Institute
|
||||||
|
|
||||||
|
#### Material Properties
|
||||||
|
1. **ASTM Standards**: Material testing standards (E8, E10, etc.)
|
||||||
|
2. **Engineering Handbooks**: ASM Metals Handbook, Machinery's Handbook
|
||||||
|
3. **Research Literature**: Journal of Applied Physics, International Journal of Impact Engineering
|
||||||
|
4. **Government Databases**: NIST materials database, military research reports
|
||||||
|
|
||||||
|
### Experimental Validation
|
||||||
|
|
||||||
|
#### Ballistic Testing
|
||||||
|
- Use chronographs for velocity measurements
|
||||||
|
- Ballistic gelatin for terminal performance
|
||||||
|
- Steel plate testing for penetration limits
|
||||||
|
- High-speed photography for fragment analysis
|
||||||
|
|
||||||
|
#### Material Testing
|
||||||
|
- Tensile testing per ASTM E8
|
||||||
|
- Hardness testing per ASTM E10
|
||||||
|
- Impact testing per ASTM E23
|
||||||
|
- Ballistic limit testing per MIL-STD protocols
|
||||||
|
|
||||||
|
## Common Material Examples
|
||||||
|
|
||||||
|
### Metals
|
||||||
|
```json
|
||||||
|
// Mild Steel (A36)
|
||||||
|
"DensityGPerCm3": 7.85,
|
||||||
|
"MaterialHardness": 150.0,
|
||||||
|
"TensileStrengthMPa": 400.0,
|
||||||
|
"YieldStrengthMPa": 250.0
|
||||||
|
|
||||||
|
// Aluminum 6061-T6
|
||||||
|
"DensityGPerCm3": 2.70,
|
||||||
|
"MaterialHardness": 95.0,
|
||||||
|
"TensileStrengthMPa": 310.0,
|
||||||
|
"YieldStrengthMPa": 276.0
|
||||||
|
|
||||||
|
// Hardened Steel (Armor)
|
||||||
|
"DensityGPerCm3": 7.85,
|
||||||
|
"MaterialHardness": 500.0,
|
||||||
|
"TensileStrengthMPa": 1200.0,
|
||||||
|
"YieldStrengthMPa": 1000.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ceramics and Composites
|
||||||
|
```json
|
||||||
|
// Alumina Ceramic
|
||||||
|
"DensityGPerCm3": 3.95,
|
||||||
|
"MaterialHardness": 1500.0,
|
||||||
|
"TensileStrengthMPa": 300.0,
|
||||||
|
"YieldStrengthMPa": 300.0,
|
||||||
|
"EnableSpalling": true
|
||||||
|
|
||||||
|
// Kevlar Composite
|
||||||
|
"DensityGPerCm3": 1.44,
|
||||||
|
"MaterialHardness": 50.0,
|
||||||
|
"TensileStrengthMPa": 3500.0,
|
||||||
|
"YieldStrengthMPa": 3500.0,
|
||||||
|
"NeverRicochet": true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quality Assurance
|
||||||
|
|
||||||
|
### Parameter Validation
|
||||||
|
1. **Physical Consistency**: Ensure yield strength ≤ tensile strength
|
||||||
|
2. **Unit Consistency**: Verify all units match the documentation
|
||||||
|
3. **Range Checking**: Compare values against published material databases
|
||||||
|
4. **Cross-Reference**: Validate against multiple independent sources
|
||||||
|
|
||||||
|
### Simulation Validation
|
||||||
|
1. **Known Results**: Test against published ballistic data
|
||||||
|
2. **Sensitivity Analysis**: Vary parameters to understand system response
|
||||||
|
3. **Comparative Testing**: Compare results between different bullet/material combinations
|
||||||
|
4. **Literature Comparison**: Validate results against peer-reviewed research
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
1. **Unrealistic Penetration**: Check density and hardness values
|
||||||
|
2. **No Expansion**: Verify expansion velocity threshold vs. impact velocity
|
||||||
|
3. **Excessive Ricochets**: Reduce ricochet probability multiplier
|
||||||
|
4. **Performance Issues**: Reduce spalling fragment count and density
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
1. **Start Simple**: Begin with basic parameters, add complexity gradually
|
||||||
|
2. **Document Sources**: Record where each value came from for traceability
|
||||||
|
3. **Version Control**: Keep track of parameter changes and their effects
|
||||||
|
4. **Peer Review**: Have other researchers validate your parameter choices
|
||||||
|
|
||||||
|
## Advanced Research Applications
|
||||||
|
|
||||||
|
### Multi-Material Studies
|
||||||
|
For composite armor or layered materials:
|
||||||
|
- Configure each layer separately
|
||||||
|
- Account for interface effects
|
||||||
|
- Consider cumulative energy absorption
|
||||||
|
|
||||||
|
### Dynamic Effects
|
||||||
|
For high strain rate phenomena:
|
||||||
|
- Use dynamic strength values (typically 1.5-3× static)
|
||||||
|
- Account for temperature effects
|
||||||
|
- Consider strain rate sensitivity
|
||||||
|
|
||||||
|
### Statistical Analysis
|
||||||
|
For probabilistic studies:
|
||||||
|
- Use parameter ranges rather than single values
|
||||||
|
- Apply Monte Carlo methods
|
||||||
|
- Document uncertainty and sensitivity
|
||||||
|
|
||||||
|
## Contact and Support
|
||||||
|
|
||||||
|
For research collaborations or technical questions:
|
||||||
|
- Review the complete API documentation
|
||||||
|
- Consult the troubleshooting guide
|
||||||
|
- Consider experimental validation of critical parameters
|
||||||
|
|
||||||
|
This configuration system is designed to support serious ballistics research while maintaining computational efficiency. The self-documenting JSON format ensures that parameter choices are traceable and scientifically justified.
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
{
|
||||||
|
"_description": "Ballistic Properties Configuration File",
|
||||||
|
"_notes": "This file defines the physical and ballistic characteristics of a projectile. All measurements use imperial units (inches, grains, fps) as is standard in ballistics research. 1 grain = 0.0647989 grams.",
|
||||||
|
"_example": "5.56x45mm NATO M193 Ball - Standard military rifle cartridge",
|
||||||
|
|
||||||
|
"GrainWeight": {
|
||||||
|
"_description": "Mass of the projectile in grains (ballistics standard unit)",
|
||||||
|
"_unit": "grains (gr)",
|
||||||
|
"_conversion": "1 grain = 0.0647989 grams = 0.000142857 pounds",
|
||||||
|
"_typical_range": "20-1000 grains depending on caliber",
|
||||||
|
"_examples": {
|
||||||
|
"22_LR": "40 grains",
|
||||||
|
"9mm": "115-147 grains",
|
||||||
|
"5.56mm": "55-77 grains",
|
||||||
|
"7.62mm": "147-175 grains",
|
||||||
|
"50_BMG": "647-750 grains"
|
||||||
|
},
|
||||||
|
"value": 55.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"DiameterInches": {
|
||||||
|
"_description": "Bullet diameter measured across the widest point",
|
||||||
|
"_unit": "inches",
|
||||||
|
"_conversion": "1 inch = 25.4 millimeters",
|
||||||
|
"_note": "This is the actual bullet diameter, not the cartridge designation",
|
||||||
|
"_examples": {
|
||||||
|
"22_caliber": "0.224 inches (5.56mm)",
|
||||||
|
"30_caliber": "0.308 inches (7.62mm)",
|
||||||
|
"9mm": "0.355 inches",
|
||||||
|
"45_ACP": "0.452 inches",
|
||||||
|
"50_BMG": "0.510 inches"
|
||||||
|
},
|
||||||
|
"value": 0.224
|
||||||
|
},
|
||||||
|
|
||||||
|
"LengthInches": {
|
||||||
|
"_description": "Overall length of the bullet from base to tip",
|
||||||
|
"_unit": "inches",
|
||||||
|
"_note": "Longer bullets generally have higher ballistic coefficients but require faster rifling twist rates",
|
||||||
|
"_typical_range": "0.4-2.0 inches depending on caliber and design",
|
||||||
|
"value": 0.825
|
||||||
|
},
|
||||||
|
|
||||||
|
"BulletType": {
|
||||||
|
"_description": "Construction and intended purpose of the bullet",
|
||||||
|
"_options": {
|
||||||
|
"0": "Full Metal Jacket (FMJ) - Lead core with copper/brass jacket, military standard",
|
||||||
|
"1": "Hollow Point (HP) - Designed to expand on impact, hunting/self-defense",
|
||||||
|
"2": "Soft Point (SP) - Exposed lead tip for controlled expansion, hunting",
|
||||||
|
"3": "Armor Piercing (AP) - Hardened core for penetrating armor",
|
||||||
|
"4": "Armor Piercing Incendiary (API) - AP with incendiary compound",
|
||||||
|
"5": "Tracer - Contains pyrotechnic compound for visible trajectory",
|
||||||
|
"6": "Match Grade - Precision manufactured for competitive shooting",
|
||||||
|
"7": "Frangible - Designed to disintegrate on impact with hard surfaces",
|
||||||
|
"8": "Lead Round Nose (LRN) - Basic lead bullet design",
|
||||||
|
"9": "Wadcutter (WC) - Flat-nosed design for paper target cutting",
|
||||||
|
"10": "Semi-Wadcutter (SWC) - Compromise between wadcutter and round nose",
|
||||||
|
"11": "Custom - User-defined characteristics"
|
||||||
|
},
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
|
||||||
|
"BulletMaterial": {
|
||||||
|
"_description": "Primary material composition affecting hardness and penetration",
|
||||||
|
"_options": {
|
||||||
|
"0": "Lead - Soft, traditional material (BHN ~5-12)",
|
||||||
|
"1": "Lead-Antimony - Hardened lead alloy (BHN ~12-18)",
|
||||||
|
"2": "Copper - Pure copper construction (BHN ~35-45)",
|
||||||
|
"3": "Copper Jacket - Lead core with copper jacket (most common)",
|
||||||
|
"4": "Brass - Brass construction (BHN ~60-80)",
|
||||||
|
"5": "Steel - Steel core or construction (BHN ~150-300)",
|
||||||
|
"6": "Tungsten - Dense, hard material (BHN ~300-400)",
|
||||||
|
"7": "Bismuth - Lead-free alternative (BHN ~7-12)",
|
||||||
|
"8": "Zinc - Zinc alloy construction (BHN ~80-120)",
|
||||||
|
"9": "Custom - User-defined material properties"
|
||||||
|
},
|
||||||
|
"_note": "BHN = Brinell Hardness Number",
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
|
||||||
|
"BallisticCoefficientG1": {
|
||||||
|
"_description": "Aerodynamic efficiency compared to G1 standard projectile",
|
||||||
|
"_explanation": "Higher values indicate better aerodynamic performance and less velocity loss over distance",
|
||||||
|
"_unit": "dimensionless ratio",
|
||||||
|
"_typical_range": "0.1-1.0+ (most bullets 0.2-0.7)",
|
||||||
|
"_examples": {
|
||||||
|
"poor_aerodynamics": "0.15-0.25 (round nose, flat base)",
|
||||||
|
"average": "0.25-0.45 (typical spitzer bullets)",
|
||||||
|
"good": "0.45-0.65 (boat tail, optimized design)",
|
||||||
|
"excellent": "0.65+ (VLD, match bullets)"
|
||||||
|
},
|
||||||
|
"_reference": "G1 standard: 1 lb, 1 inch diameter, flat base bullet",
|
||||||
|
"value": 0.151
|
||||||
|
},
|
||||||
|
|
||||||
|
"BallisticCoefficientG7": {
|
||||||
|
"_description": "Aerodynamic efficiency compared to G7 standard projectile",
|
||||||
|
"_explanation": "More accurate for modern boat-tail spitzer bullets than G1",
|
||||||
|
"_unit": "dimensionless ratio",
|
||||||
|
"_note": "G7 model better represents modern bullet shapes, typically 0.5-0.7x the G1 value",
|
||||||
|
"_reference": "G7 standard: boat-tail spitzer design",
|
||||||
|
"value": 0.076
|
||||||
|
},
|
||||||
|
|
||||||
|
"UseG7Model": {
|
||||||
|
"_description": "Whether to use G7 or G1 ballistic coefficient model",
|
||||||
|
"_explanation": "G7 is more accurate for modern pointed bullets, G1 is traditional standard",
|
||||||
|
"_recommendation": "Use G7 for boat-tail spitzer bullets, G1 for round nose or flat base",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"SectionalDensity": {
|
||||||
|
"_description": "Ratio of bullet mass to cross-sectional area",
|
||||||
|
"_formula": "SD = Weight(grains) / (7000 × Diameter²(inches))",
|
||||||
|
"_unit": "dimensionless ratio",
|
||||||
|
"_significance": "Higher SD indicates better penetration potential",
|
||||||
|
"_typical_ranges": {
|
||||||
|
"light": "0.15-0.20 (varmint bullets)",
|
||||||
|
"medium": "0.20-0.25 (general purpose)",
|
||||||
|
"heavy": "0.25-0.35 (hunting, long range)",
|
||||||
|
"very_heavy": "0.35+ (dangerous game, extreme penetration)"
|
||||||
|
},
|
||||||
|
"_note": "Set to 0.0 for automatic calculation from weight and diameter",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"BulletHardness": {
|
||||||
|
"_description": "Material hardness of the bullet",
|
||||||
|
"_unit": "Brinell Hardness Number (HB or BHN)",
|
||||||
|
"_measurement": "Standard 10mm steel ball, 3000kg load, 30 second duration",
|
||||||
|
"_typical_values": {
|
||||||
|
"pure_lead": "5-8 BHN",
|
||||||
|
"wheel_weight_alloy": "12-15 BHN",
|
||||||
|
"linotype_alloy": "22-25 BHN",
|
||||||
|
"copper_plated": "8-12 BHN",
|
||||||
|
"copper_jacket": "15-20 BHN (considers jacket)",
|
||||||
|
"mild_steel_core": "150-200 BHN",
|
||||||
|
"hardened_steel": "300-600 BHN"
|
||||||
|
},
|
||||||
|
"_penetration_effect": "Harder bullets penetrate better but may not expand",
|
||||||
|
"value": 15.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"PenetrationEnergyThreshold": {
|
||||||
|
"_description": "Minimum kinetic energy required for the bullet to penetrate materials",
|
||||||
|
"_unit": "foot-pounds (ft-lbs)",
|
||||||
|
"_conversion": "1 ft-lb = 1.35582 Joules",
|
||||||
|
"_explanation": "Below this energy, bullet will not penetrate and may bounce off",
|
||||||
|
"_typical_values": {
|
||||||
|
"small_game": "10-25 ft-lbs",
|
||||||
|
"medium_game": "25-80 ft-lbs",
|
||||||
|
"large_game": "80-200 ft-lbs",
|
||||||
|
"dangerous_game": "200+ ft-lbs",
|
||||||
|
"armor_piercing": "500+ ft-lbs"
|
||||||
|
},
|
||||||
|
"_factors": "Depends on bullet construction, target material, and impact angle",
|
||||||
|
"value": 58.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"ExpansionVelocityThreshold": {
|
||||||
|
"_description": "Minimum impact velocity required for bullet expansion",
|
||||||
|
"_unit": "feet per second (fps)",
|
||||||
|
"_conversion": "1 fps = 0.3048 meters per second",
|
||||||
|
"_explanation": "Below this velocity, expanding bullets (HP, SP) will not expand reliably",
|
||||||
|
"_typical_values": {
|
||||||
|
"handgun_bullets": "800-1200 fps",
|
||||||
|
"rifle_bullets": "1600-2200 fps",
|
||||||
|
"premium_hunting": "1400-1800 fps",
|
||||||
|
"varmint_bullets": "2000-2800 fps"
|
||||||
|
},
|
||||||
|
"_note": "Only applies to expanding bullet types (HP, SP, etc.)",
|
||||||
|
"value": 1800.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"MaxExpansionMultiplier": {
|
||||||
|
"_description": "Maximum diameter increase when bullet expands",
|
||||||
|
"_unit": "ratio (expanded diameter / original diameter)",
|
||||||
|
"_explanation": "How much the bullet can expand from its original diameter",
|
||||||
|
"_typical_values": {
|
||||||
|
"controlled_expansion": "1.3-1.6x (premium hunting)",
|
||||||
|
"moderate_expansion": "1.6-2.0x (standard hunting)",
|
||||||
|
"maximum_expansion": "2.0-2.5x (self-defense)",
|
||||||
|
"fragmenting": "2.5x+ (varmint bullets)"
|
||||||
|
},
|
||||||
|
"_examples": {
|
||||||
|
"9mm_hollow_point": "1.5-1.8x (0.355\" to ~0.64\")",
|
||||||
|
"30-06_hunting": "1.4-1.7x (0.308\" to ~0.52\")",
|
||||||
|
"22-250_varmint": "2.0-3.0x (0.224\" to ~0.67\")"
|
||||||
|
},
|
||||||
|
"_note": "Only applies to expanding bullet types",
|
||||||
|
"value": 1.5
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,525 @@
|
|||||||
|
{
|
||||||
|
"_description": "Material Response Configuration File",
|
||||||
|
"_notes": "This file defines how materials respond to ballistic impact, including penetration, ricochet, and fragmentation characteristics. Values are based on material science and ballistics research.",
|
||||||
|
"_example": "Mild Steel Plate - Typical structural steel properties",
|
||||||
|
"_warning": "These parameters significantly affect simulation realism. Consult ballistics literature for accurate values.",
|
||||||
|
|
||||||
|
"PenTraceType": {
|
||||||
|
"_description": "Method used to calculate penetration through material",
|
||||||
|
"_options": {
|
||||||
|
"0": "Back Trace - Traces backwards from exit point to calculate thickness",
|
||||||
|
"1": "By Component - Uses component bounds for thickness calculation",
|
||||||
|
"2": "Double Sided Geometry - Treats geometry as having entry and exit surfaces"
|
||||||
|
},
|
||||||
|
"_recommendation": "Use Back Trace (0) for most materials, Double Sided (2) for thin plates",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
|
||||||
|
"NeverPenetrate": {
|
||||||
|
"_description": "Forces material to be completely impenetrable regardless of impact energy",
|
||||||
|
"_use_cases": [
|
||||||
|
"Armor plates in arcade-style games",
|
||||||
|
"Indestructible barriers",
|
||||||
|
"Ultra-hard materials like tungsten carbide armor"
|
||||||
|
],
|
||||||
|
"_note": "Overrides all other penetration calculations when true",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"PenetrationDepthMultiplier": {
|
||||||
|
"_description": "Scaling factor for calculated penetration depth",
|
||||||
|
"_unit": "multiplier (1.0 = normal penetration)",
|
||||||
|
"_range": "0.1-10.0 typical",
|
||||||
|
"_effects": {
|
||||||
|
"0.5": "Half normal penetration (hardened armor)",
|
||||||
|
"1.0": "Normal penetration (standard calculation)",
|
||||||
|
"2.0": "Double penetration (soft materials)",
|
||||||
|
"5.0": "Very high penetration (foam, fabric)"
|
||||||
|
},
|
||||||
|
"_applications": "Adjust for material hardness variations not captured in other parameters",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"PenetrationNormalization": {
|
||||||
|
"_description": "Reduces penetration effectiveness at oblique impact angles",
|
||||||
|
"_unit": "degrees (0-90)",
|
||||||
|
"_explanation": "At angles greater than this value, penetration is reduced",
|
||||||
|
"_typical_values": {
|
||||||
|
"soft_materials": "0-15 degrees (wood, plastic)",
|
||||||
|
"medium_materials": "15-30 degrees (aluminum, mild steel)",
|
||||||
|
"hard_materials": "30-45 degrees (hardened steel, armor)",
|
||||||
|
"very_hard": "45-60 degrees (ceramics, tungsten)"
|
||||||
|
},
|
||||||
|
"_physics": "Represents material's resistance to angled impacts",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"PenetrationNormalizationGrazing": {
|
||||||
|
"_description": "Additional normalization for very shallow (grazing) angles",
|
||||||
|
"_unit": "degrees (0-90)",
|
||||||
|
"_explanation": "Applied in addition to PenetrationNormalization for extreme angles",
|
||||||
|
"_typical_range": "60-85 degrees",
|
||||||
|
"_effect": "Simulates bullet deflection at very shallow impact angles",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"PenetrationEntryAngleSpread": {
|
||||||
|
"_description": "Random deviation of bullet path when entering material",
|
||||||
|
"_unit": "degrees of cone spread",
|
||||||
|
"_range": "0-15 degrees typical",
|
||||||
|
"_causes": [
|
||||||
|
"Material inhomogeneity",
|
||||||
|
"Surface roughness",
|
||||||
|
"Bullet deformation on impact"
|
||||||
|
],
|
||||||
|
"_typical_values": {
|
||||||
|
"homogeneous": "0-2 degrees (steel, aluminum)",
|
||||||
|
"layered": "2-5 degrees (plywood, composites)",
|
||||||
|
"granular": "5-10 degrees (concrete, soil)",
|
||||||
|
"irregular": "10+ degrees (rock, masonry)"
|
||||||
|
},
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"PenetrationExitAngleSpread": {
|
||||||
|
"_description": "Random deviation of bullet path when exiting material",
|
||||||
|
"_unit": "degrees of cone spread",
|
||||||
|
"_explanation": "Usually larger than entry spread due to bullet tumbling and material displacement",
|
||||||
|
"_typical_values": {
|
||||||
|
"thin_plates": "1-3 degrees",
|
||||||
|
"medium_thickness": "3-8 degrees",
|
||||||
|
"thick_materials": "8-15 degrees",
|
||||||
|
"very_thick": "15+ degrees"
|
||||||
|
},
|
||||||
|
"_factors": "Increases with material thickness and bullet instability",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"NeverRicochet": {
|
||||||
|
"_description": "Prevents bullets from ricocheting off this material",
|
||||||
|
"_use_cases": [
|
||||||
|
"Soft materials (rubber, sand)",
|
||||||
|
"Materials that always absorb bullets",
|
||||||
|
"Gameplay balance (prevent unintended ricochets)"
|
||||||
|
],
|
||||||
|
"_note": "Overrides ricochet calculations when true",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"RicochetProbabilityMultiplier": {
|
||||||
|
"_description": "Scaling factor for ricochet probability calculations",
|
||||||
|
"_unit": "multiplier (1.0 = normal ricochet probability)",
|
||||||
|
"_range": "0.0-5.0 typical",
|
||||||
|
"_effects": {
|
||||||
|
"0.0": "No ricochets (same as NeverRicochet)",
|
||||||
|
"0.5": "Reduced ricochet probability",
|
||||||
|
"1.0": "Normal ricochet probability",
|
||||||
|
"2.0": "Increased ricochet probability",
|
||||||
|
"5.0": "Very high ricochet probability"
|
||||||
|
},
|
||||||
|
"_material_examples": {
|
||||||
|
"concrete": "0.8-1.2",
|
||||||
|
"steel": "1.0-1.5",
|
||||||
|
"water": "0.3-0.7",
|
||||||
|
"ice": "1.2-1.8"
|
||||||
|
},
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"RicochetRestitution": {
|
||||||
|
"_description": "Energy retention coefficient during ricochet",
|
||||||
|
"_unit": "ratio (0.0-1.0)",
|
||||||
|
"_explanation": "Fraction of kinetic energy retained after ricochet",
|
||||||
|
"_physics": "Based on coefficient of restitution in collision physics",
|
||||||
|
"_typical_values": {
|
||||||
|
"very_soft": "0.1-0.3 (sand, mud)",
|
||||||
|
"soft": "0.3-0.5 (wood, concrete)",
|
||||||
|
"medium": "0.5-0.7 (steel, aluminum)",
|
||||||
|
"hard": "0.7-0.9 (hardened steel, tungsten)",
|
||||||
|
"ideal": "0.9-1.0 (theoretical perfectly elastic)"
|
||||||
|
},
|
||||||
|
"_note": "Higher values mean bullets retain more energy after ricochet",
|
||||||
|
"value": 0.5
|
||||||
|
},
|
||||||
|
|
||||||
|
"RicochetRestitutionInfluence": {
|
||||||
|
"_description": "How much material properties affect restitution calculation",
|
||||||
|
"_unit": "influence factor (0.0-1.0)",
|
||||||
|
"_explanation": "0.0 = fixed restitution, 1.0 = fully material-dependent",
|
||||||
|
"_typical_range": "0.0-0.5",
|
||||||
|
"_usage": "Allows fine-tuning of material influence on energy loss",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"RicochetFriction": {
|
||||||
|
"_description": "Friction coefficient affecting ricochet angle and spin",
|
||||||
|
"_unit": "coefficient of friction (0.0-2.0 typical)",
|
||||||
|
"_physics": "Determines tangential force during ricochet contact",
|
||||||
|
"_typical_values": {
|
||||||
|
"smooth_metal": "0.1-0.3",
|
||||||
|
"rough_metal": "0.3-0.6",
|
||||||
|
"concrete": "0.6-0.9",
|
||||||
|
"rubber": "0.8-1.2",
|
||||||
|
"very_rough": "1.2+ (textured surfaces)"
|
||||||
|
},
|
||||||
|
"_effects": [
|
||||||
|
"Higher friction increases bullet spin",
|
||||||
|
"Affects ricochet angle deviation",
|
||||||
|
"Influences energy loss during contact"
|
||||||
|
],
|
||||||
|
"value": 0.5
|
||||||
|
},
|
||||||
|
|
||||||
|
"RicochetFrictionInfluence": {
|
||||||
|
"_description": "How much friction affects the ricochet calculation",
|
||||||
|
"_unit": "influence factor (0.0-1.0)",
|
||||||
|
"_explanation": "0.0 = friction ignored, 1.0 = full friction effects",
|
||||||
|
"_typical_range": "0.0-0.8",
|
||||||
|
"_usage": "Allows realistic friction effects while maintaining performance",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"RicochetSpread": {
|
||||||
|
"_description": "Random angular deviation added to ricochet direction",
|
||||||
|
"_unit": "degrees of cone spread",
|
||||||
|
"_causes": [
|
||||||
|
"Surface irregularities",
|
||||||
|
"Bullet deformation",
|
||||||
|
"Material inhomogeneity"
|
||||||
|
],
|
||||||
|
"_typical_values": {
|
||||||
|
"smooth_surfaces": "0-5 degrees",
|
||||||
|
"rough_surfaces": "5-15 degrees",
|
||||||
|
"very_rough": "15-30 degrees",
|
||||||
|
"irregular": "30+ degrees"
|
||||||
|
},
|
||||||
|
"_realism": "Real ricochets are rarely perfectly predictable",
|
||||||
|
"value": 0.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"EnableSpalling": {
|
||||||
|
"_description": "Whether this material generates spalling fragments when impacted",
|
||||||
|
"_explanation": "Spalling occurs when material fractures and ejects fragments from impact",
|
||||||
|
"_occurs_in": [
|
||||||
|
"Brittle materials (concrete, ceramics, glass)",
|
||||||
|
"Layered materials (armor plates)",
|
||||||
|
"Materials under tension stress"
|
||||||
|
],
|
||||||
|
"_note": "Computationally expensive - use selectively",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"SpallVelocityThreshold": {
|
||||||
|
"_description": "Minimum impact velocity to generate spalling fragments",
|
||||||
|
"_unit": "centimeters per second (cm/s)",
|
||||||
|
"_conversion": "1 fps = 30.48 cm/s, 1 m/s = 100 cm/s",
|
||||||
|
"_typical_thresholds": {
|
||||||
|
"glass": "15000-30000 cm/s (500-1000 fps)",
|
||||||
|
"concrete": "30000-60000 cm/s (1000-2000 fps)",
|
||||||
|
"mild_steel": "60000-120000 cm/s (2000-4000 fps)",
|
||||||
|
"hardened_steel": "120000+ cm/s (4000+ fps)"
|
||||||
|
},
|
||||||
|
"_physics": "Based on material's dynamic fracture strength",
|
||||||
|
"value": 50000.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"SpallFragmentCount": {
|
||||||
|
"_description": "Maximum number of spall fragments generated per impact",
|
||||||
|
"_unit": "count (integer)",
|
||||||
|
"_range": "1-20 typical (performance considerations)",
|
||||||
|
"_factors": [
|
||||||
|
"Impact energy",
|
||||||
|
"Material brittleness",
|
||||||
|
"Thickness",
|
||||||
|
"Computational limitations"
|
||||||
|
],
|
||||||
|
"_typical_values": {
|
||||||
|
"small_impact": "1-3 fragments",
|
||||||
|
"medium_impact": "3-8 fragments",
|
||||||
|
"large_impact": "8-15 fragments",
|
||||||
|
"massive_impact": "15+ fragments"
|
||||||
|
},
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
|
||||||
|
"SpallSpreadAngle": {
|
||||||
|
"_description": "Cone angle for spall fragment ejection",
|
||||||
|
"_unit": "degrees (0-180)",
|
||||||
|
"_physics": "Fragments typically eject in forward cone from impact point",
|
||||||
|
"_typical_values": {
|
||||||
|
"focused": "15-30 degrees (hard materials)",
|
||||||
|
"moderate": "30-60 degrees (typical materials)",
|
||||||
|
"wide": "60-90 degrees (soft/brittle materials)",
|
||||||
|
"hemispherical": "90+ degrees (extreme cases)"
|
||||||
|
},
|
||||||
|
"_note": "Larger angles create more dispersed fragment patterns",
|
||||||
|
"value": 45.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"SpallVelocityMultiplier": {
|
||||||
|
"_description": "Fraction of impact velocity inherited by spall fragments",
|
||||||
|
"_unit": "ratio (0.0-1.0)",
|
||||||
|
"_physics": "Conservation of momentum with energy losses",
|
||||||
|
"_typical_values": {
|
||||||
|
"low_energy": "0.1-0.2 (material absorbs most energy)",
|
||||||
|
"medium_energy": "0.2-0.4 (typical spalling)",
|
||||||
|
"high_energy": "0.4-0.6 (explosive spalling)",
|
||||||
|
"extreme": "0.6+ (theoretical maximum)"
|
||||||
|
},
|
||||||
|
"_factors": "Material brittleness, fragment size, impact energy",
|
||||||
|
"value": 0.3
|
||||||
|
},
|
||||||
|
|
||||||
|
"SpallMassMultiplier": {
|
||||||
|
"_description": "Fraction of projectile mass inherited by each spall fragment",
|
||||||
|
"_unit": "ratio (0.0-1.0)",
|
||||||
|
"_calculation": "Fragment mass = bullet mass × multiplier ÷ fragment count",
|
||||||
|
"_typical_values": {
|
||||||
|
"fine_fragments": "0.01-0.05 (dust-like)",
|
||||||
|
"small_fragments": "0.05-0.15 (typical)",
|
||||||
|
"large_fragments": "0.15-0.3 (dangerous sized)",
|
||||||
|
"very_large": "0.3+ (rare, massive impacts)"
|
||||||
|
},
|
||||||
|
"_realism": "Total fragment mass should be reasonable fraction of material displaced",
|
||||||
|
"value": 0.1
|
||||||
|
},
|
||||||
|
|
||||||
|
"UseMathematicalProperties": {
|
||||||
|
"_description": "Enable detailed material science calculations",
|
||||||
|
"_explanation": "Uses engineering properties for more accurate ballistic modeling",
|
||||||
|
"_benefits": [
|
||||||
|
"More realistic penetration calculations",
|
||||||
|
"Temperature and strain rate effects",
|
||||||
|
"Scientific accuracy for research"
|
||||||
|
],
|
||||||
|
"_cost": "Increased computational complexity",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"MathematicalProperties": {
|
||||||
|
"_description": "Detailed material science properties for accurate ballistic modeling",
|
||||||
|
"_note": "Values should be obtained from material testing or engineering handbooks",
|
||||||
|
"_reference": "ASTM standards, engineering material databases, scientific literature",
|
||||||
|
|
||||||
|
"DensityGPerCm3": {
|
||||||
|
"_description": "Material density",
|
||||||
|
"_unit": "grams per cubic centimeter (g/cm³)",
|
||||||
|
"_conversion": "1 g/cm³ = 1000 kg/m³ = 62.43 lb/ft³",
|
||||||
|
"_typical_values": {
|
||||||
|
"aluminum": "2.70 g/cm³",
|
||||||
|
"steel_mild": "7.85 g/cm³",
|
||||||
|
"steel_stainless": "8.0 g/cm³",
|
||||||
|
"titanium": "4.5 g/cm³",
|
||||||
|
"lead": "11.34 g/cm³",
|
||||||
|
"tungsten": "19.3 g/cm³",
|
||||||
|
"concrete": "2.4 g/cm³",
|
||||||
|
"wood_oak": "0.75 g/cm³",
|
||||||
|
"kevlar": "1.44 g/cm³"
|
||||||
|
},
|
||||||
|
"_importance": "Affects momentum transfer and penetration resistance",
|
||||||
|
"value": 7.85
|
||||||
|
},
|
||||||
|
|
||||||
|
"MaterialHardness": {
|
||||||
|
"_description": "Brinell hardness of the material",
|
||||||
|
"_unit": "Brinell Hardness Number (HB or BHN)",
|
||||||
|
"_test": "10mm steel ball, 3000kg load, 30 seconds",
|
||||||
|
"_typical_values": {
|
||||||
|
"aluminum_pure": "15-30 HB",
|
||||||
|
"aluminum_alloy": "30-150 HB",
|
||||||
|
"steel_mild": "120-200 HB",
|
||||||
|
"steel_carbon": "200-400 HB",
|
||||||
|
"steel_tool": "400-700 HB",
|
||||||
|
"titanium": "200-400 HB",
|
||||||
|
"brass": "60-200 HB",
|
||||||
|
"concrete": "20-40 HB (estimated)"
|
||||||
|
},
|
||||||
|
"_penetration_effect": "Harder materials resist penetration and deformation",
|
||||||
|
"value": 200.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"TensileStrengthMPa": {
|
||||||
|
"_description": "Ultimate tensile strength - maximum stress before failure",
|
||||||
|
"_unit": "Megapascals (MPa)",
|
||||||
|
"_conversion": "1 MPa = 145.04 psi = 0.145 ksi",
|
||||||
|
"_typical_values": {
|
||||||
|
"aluminum_1100": "90-165 MPa",
|
||||||
|
"aluminum_6061": "240-310 MPa",
|
||||||
|
"steel_mild": "400-550 MPa",
|
||||||
|
"steel_carbon": "550-1000 MPa",
|
||||||
|
"steel_stainless": "500-750 MPa",
|
||||||
|
"titanium_cp": "240-550 MPa",
|
||||||
|
"concrete": "3-5 MPa (compression much higher)",
|
||||||
|
"kevlar_fiber": "3000-3500 MPa"
|
||||||
|
},
|
||||||
|
"_ballistic_relevance": "Determines material failure under impact stress",
|
||||||
|
"value": 400.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"YieldStrengthMPa": {
|
||||||
|
"_description": "Yield strength - stress at which permanent deformation begins",
|
||||||
|
"_unit": "Megapascals (MPa)",
|
||||||
|
"_typical_ratio": "Usually 50-80% of tensile strength",
|
||||||
|
"_typical_values": {
|
||||||
|
"aluminum_1100": "35-145 MPa",
|
||||||
|
"aluminum_6061": "240-276 MPa",
|
||||||
|
"steel_mild": "250-400 MPa",
|
||||||
|
"steel_carbon": "400-700 MPa",
|
||||||
|
"steel_stainless": "200-300 MPa",
|
||||||
|
"titanium_cp": "170-485 MPa"
|
||||||
|
},
|
||||||
|
"_ballistic_relevance": "Determines when material begins permanent deformation during impact",
|
||||||
|
"value": 250.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"ElasticModulusGPa": {
|
||||||
|
"_description": "Young's modulus - material stiffness",
|
||||||
|
"_unit": "Gigapascals (GPa)",
|
||||||
|
"_conversion": "1 GPa = 1000 MPa = 145,038 psi",
|
||||||
|
"_typical_values": {
|
||||||
|
"aluminum": "69-70 GPa",
|
||||||
|
"steel": "200-210 GPa",
|
||||||
|
"titanium": "105-120 GPa",
|
||||||
|
"concrete": "20-50 GPa",
|
||||||
|
"kevlar": "60-125 GPa",
|
||||||
|
"carbon_fiber": "150-500 GPa"
|
||||||
|
},
|
||||||
|
"_ballistic_relevance": "Affects stress wave propagation and material response time",
|
||||||
|
"value": 200.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"BallisticLimitVelocity": {
|
||||||
|
"_description": "Velocity at which 50% of impacts will just penetrate completely",
|
||||||
|
"_unit": "feet per second (fps)",
|
||||||
|
"_conversion": "1 fps = 0.3048 m/s",
|
||||||
|
"_determination": "Experimental testing with specific projectile/material combinations",
|
||||||
|
"_typical_ranges": {
|
||||||
|
"thin_aluminum": "800-1500 fps",
|
||||||
|
"mild_steel_plate": "1500-3000 fps",
|
||||||
|
"hardened_steel": "2500-4500 fps",
|
||||||
|
"ceramic_armor": "2000-3500 fps",
|
||||||
|
"kevlar_vest": "1200-1800 fps"
|
||||||
|
},
|
||||||
|
"_note": "Highly dependent on projectile type, material thickness, and impact conditions",
|
||||||
|
"value": 2000.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"PerforationCoefficient": {
|
||||||
|
"_description": "Empirical factor for perforation calculations",
|
||||||
|
"_unit": "dimensionless coefficient",
|
||||||
|
"_typical_range": "0.5-2.0",
|
||||||
|
"_usage": "Adjusts theoretical calculations to match experimental data",
|
||||||
|
"_values": {
|
||||||
|
"soft_materials": "0.5-0.8",
|
||||||
|
"typical_metals": "0.8-1.2",
|
||||||
|
"hard_materials": "1.2-2.0"
|
||||||
|
},
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"EnergyAbsorptionCoefficient": {
|
||||||
|
"_description": "Fraction of projectile kinetic energy absorbed by material",
|
||||||
|
"_unit": "ratio (0.0-1.0)",
|
||||||
|
"_physics": "Energy dissipated through deformation, fracture, heat",
|
||||||
|
"_typical_values": {
|
||||||
|
"very_soft": "0.9-1.0 (sand, foam)",
|
||||||
|
"soft": "0.7-0.9 (wood, plastic)",
|
||||||
|
"medium": "0.5-0.7 (aluminum, mild steel)",
|
||||||
|
"hard": "0.3-0.5 (hardened steel, ceramics)",
|
||||||
|
"very_hard": "0.1-0.3 (tungsten, depleted uranium)"
|
||||||
|
},
|
||||||
|
"_note": "Higher values mean more energy absorbed, less exit velocity",
|
||||||
|
"value": 0.7
|
||||||
|
},
|
||||||
|
|
||||||
|
"EnableMathematicalSpalling": {
|
||||||
|
"_description": "Use physics-based spalling calculations instead of simple model",
|
||||||
|
"_benefits": [
|
||||||
|
"Stress-based fragment generation",
|
||||||
|
"Realistic fragment size distribution",
|
||||||
|
"Velocity-dependent fragment count"
|
||||||
|
],
|
||||||
|
"_cost": "Significantly more computational overhead",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"SpallStrengthMPa": {
|
||||||
|
"_description": "Dynamic tensile strength - stress required to cause spalling",
|
||||||
|
"_unit": "Megapascals (MPa)",
|
||||||
|
"_physics": "Material's resistance to tensile failure under shock loading",
|
||||||
|
"_typical_values": {
|
||||||
|
"concrete": "2-8 MPa",
|
||||||
|
"aluminum": "100-300 MPa",
|
||||||
|
"mild_steel": "150-400 MPa",
|
||||||
|
"hardened_steel": "200-600 MPa",
|
||||||
|
"ceramics": "50-200 MPa",
|
||||||
|
"composites": "20-100 MPa"
|
||||||
|
},
|
||||||
|
"_note": "Usually lower than static tensile strength due to high strain rates",
|
||||||
|
"value": 150.0
|
||||||
|
},
|
||||||
|
|
||||||
|
"CriticalStressFactor": {
|
||||||
|
"_description": "Multiplier for stress calculations in spalling",
|
||||||
|
"_unit": "dimensionless factor",
|
||||||
|
"_typical_range": "1.5-4.0",
|
||||||
|
"_physics": "Accounts for stress concentration, dynamic effects, material flaws",
|
||||||
|
"_calibration": "Adjust to match experimental spalling thresholds",
|
||||||
|
"value": 2.5
|
||||||
|
},
|
||||||
|
|
||||||
|
"FragmentVelocityEfficiency": {
|
||||||
|
"_description": "Efficiency of momentum transfer to spall fragments",
|
||||||
|
"_unit": "ratio (0.0-1.0)",
|
||||||
|
"_physics": "Based on conservation of momentum and energy dissipation",
|
||||||
|
"_typical_values": {
|
||||||
|
"brittle_materials": "0.1-0.3",
|
||||||
|
"ductile_materials": "0.2-0.4",
|
||||||
|
"optimal_conditions": "0.3-0.5"
|
||||||
|
},
|
||||||
|
"_factors": "Fragment size, material properties, impact energy",
|
||||||
|
"value": 0.25
|
||||||
|
},
|
||||||
|
|
||||||
|
"AverageFragmentMassRatio": {
|
||||||
|
"_description": "Average mass of fragments relative to total spalled material",
|
||||||
|
"_unit": "ratio (0.0-1.0)",
|
||||||
|
"_explanation": "Controls fragment size distribution - smaller ratios create more, smaller fragments",
|
||||||
|
"_typical_values": {
|
||||||
|
"fine_fragmentation": "0.01-0.05",
|
||||||
|
"normal_fragmentation": "0.05-0.15",
|
||||||
|
"coarse_fragmentation": "0.15-0.3"
|
||||||
|
},
|
||||||
|
"value": 0.08
|
||||||
|
},
|
||||||
|
|
||||||
|
"FragmentSizeExponent": {
|
||||||
|
"_description": "Power law exponent for fragment size distribution",
|
||||||
|
"_unit": "dimensionless exponent",
|
||||||
|
"_physics": "Based on fracture mechanics - typically negative values",
|
||||||
|
"_typical_range": "-2.5 to -1.0",
|
||||||
|
"_meaning": {
|
||||||
|
"-2.5": "Many small fragments, few large ones",
|
||||||
|
"-2.0": "Moderate distribution",
|
||||||
|
"-1.5": "More uniform fragment sizes",
|
||||||
|
"-1.0": "Tendency toward larger fragments"
|
||||||
|
},
|
||||||
|
"_reference": "Mott fragmentation theory, Weibull distributions",
|
||||||
|
"value": -1.6
|
||||||
|
},
|
||||||
|
|
||||||
|
"MaxFragmentDensity": {
|
||||||
|
"_description": "Maximum number of fragments per unit impact area",
|
||||||
|
"_unit": "fragments per square centimeter",
|
||||||
|
"_purpose": "Prevents excessive fragment generation that could impact performance",
|
||||||
|
"_typical_limits": {
|
||||||
|
"low_detail": "10-25 fragments/cm²",
|
||||||
|
"medium_detail": "25-75 fragments/cm²",
|
||||||
|
"high_detail": "75-150 fragments/cm²",
|
||||||
|
"research_quality": "150+ fragments/cm²"
|
||||||
|
},
|
||||||
|
"_balance": "Higher values increase realism but reduce performance",
|
||||||
|
"value": 50.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -264,7 +264,16 @@ bool AEBBullet::ShouldGenerateSpalling(FVector ImpactVelocity, UPhysicalMaterial
|
|||||||
}
|
}
|
||||||
|
|
||||||
float ImpactSpeed = ImpactVelocity.Size();
|
float ImpactSpeed = ImpactVelocity.Size();
|
||||||
return ImpactSpeed >= ResponseEntry->SpallVelocityThreshold;
|
|
||||||
|
// Calculate dynamic spalling threshold based on material properties
|
||||||
|
float MaterialSpallResistance = Material->Density * 0.1f; // Denser materials resist spalling more
|
||||||
|
float EffectiveThreshold = ResponseEntry->SpallVelocityThreshold * (1.0f + MaterialSpallResistance);
|
||||||
|
|
||||||
|
// Check if bullet has enough kinetic energy to cause spalling
|
||||||
|
float ImpactEnergy = 0.5f * GetEffectiveMass() * ImpactSpeed * ImpactSpeed;
|
||||||
|
float MinimumSpallEnergy = 50.0f * Material->Density; // Energy threshold scales with material density
|
||||||
|
|
||||||
|
return ImpactSpeed >= EffectiveThreshold && ImpactEnergy >= MinimumSpallEnergy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEBBullet::GenerateSpallFragments(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal, UPhysicalMaterial* Material, AActor* HitActor)
|
void AEBBullet::GenerateSpallFragments(FVector ImpactLocation, FVector ImpactVelocity, FVector ImpactNormal, UPhysicalMaterial* Material, AActor* HitActor)
|
||||||
@@ -286,42 +295,172 @@ void AEBBullet::GenerateSpallFragments(FVector ImpactLocation, FVector ImpactVel
|
|||||||
FragmentClass = GetClass();
|
FragmentClass = GetClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 FragmentCount = FMath::RandRange(1, ResponseEntry->SpallFragmentCount);
|
float ImpactSpeed = ImpactVelocity.Size();
|
||||||
float SpreadAngleRad = FMath::DegreesToRadians(ResponseEntry->SpallSpreadAngle);
|
float ImpactAngle = FMath::Acos(FMath::Abs(FVector::DotProduct(ImpactVelocity.GetSafeNormal(), ImpactNormal)));
|
||||||
float BaseVelocityMagnitude = ImpactVelocity.Size() * ResponseEntry->SpallVelocityMultiplier;
|
float ImpactAngleDegrees = FMath::RadiansToDegrees(ImpactAngle);
|
||||||
float FragmentMass = GetEffectiveMass() * ResponseEntry->SpallMassMultiplier;
|
|
||||||
|
|
||||||
FVector BaseDirection = UKismetMathLibrary::GetReflectionVector(ImpactVelocity.GetSafeNormal(), ImpactNormal);
|
int32 FragmentCount;
|
||||||
|
float SpreadAngleRad;
|
||||||
|
|
||||||
|
// Check if we should use mathematical spalling calculations
|
||||||
|
bool UseMathematicalSpalling = UseMathematicalPhysics && BulletPropertiesAsset &&
|
||||||
|
ResponseEntry->UseMathematicalProperties &&
|
||||||
|
ResponseEntry->MathematicalProperties.EnableMathematicalSpalling;
|
||||||
|
|
||||||
|
if (UseMathematicalSpalling)
|
||||||
|
{
|
||||||
|
// Use mathematical ballistics for spalling calculations
|
||||||
|
float VelocityMPS = ImpactSpeed / 100.0f; // Convert cm/s to m/s
|
||||||
|
|
||||||
|
FragmentCount = UEBMathematicalBallistics::CalculateSpallFragmentCount(
|
||||||
|
BulletPropertiesAsset->BulletProperties,
|
||||||
|
ResponseEntry->MathematicalProperties,
|
||||||
|
VelocityMPS,
|
||||||
|
ImpactAngleDegrees
|
||||||
|
);
|
||||||
|
|
||||||
|
float ConeAngle = UEBMathematicalBallistics::CalculateSpallConeAngle(
|
||||||
|
BulletPropertiesAsset->BulletProperties,
|
||||||
|
ResponseEntry->MathematicalProperties,
|
||||||
|
VelocityMPS,
|
||||||
|
ImpactAngleDegrees
|
||||||
|
);
|
||||||
|
|
||||||
|
SpreadAngleRad = FMath::DegreesToRadians(ConeAngle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use artistic spalling calculations (original physics-based approach)
|
||||||
|
float ImpactKineticEnergy = 0.5f * GetEffectiveMass() * ImpactSpeed * ImpactSpeed;
|
||||||
|
float AngleEffectiveness = FMath::Cos(ImpactAngle);
|
||||||
|
float MaterialHardness = Material ? FMath::Clamp(Material->Density * 0.001f, 0.1f, 5.0f) : 1.0f;
|
||||||
|
|
||||||
|
float BaseFragmentCount = FMath::Sqrt(ImpactKineticEnergy / 1000.0f) * MaterialHardness * AngleEffectiveness;
|
||||||
|
FragmentCount = FMath::Clamp(FMath::RoundToInt(BaseFragmentCount), 1, ResponseEntry->SpallFragmentCount);
|
||||||
|
|
||||||
|
float PhysicalSpreadAngle = FMath::Lerp(15.0f, 60.0f, FMath::Sin(ImpactAngle));
|
||||||
|
SpreadAngleRad = FMath::DegreesToRadians(PhysicalSpreadAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base spalling direction (combination of reflection and surface normal)
|
||||||
|
FVector ReflectionDirection = UKismetMathLibrary::GetReflectionVector(ImpactVelocity.GetSafeNormal(), ImpactNormal);
|
||||||
|
FVector SpallBaseDirection = FMath::Lerp(ImpactNormal, ReflectionDirection, 0.3f).GetSafeNormal();
|
||||||
|
|
||||||
for (int32 i = 0; i < FragmentCount; i++)
|
for (int32 i = 0; i < FragmentCount; i++)
|
||||||
{
|
{
|
||||||
FVector FragmentDirection = RandomStream.VRandCone(BaseDirection, SpreadAngleRad);
|
float FragmentMass;
|
||||||
float VelocityVariation = RandomStream.FRandRange(0.7f, 1.3f);
|
float FragmentSpeed;
|
||||||
FVector FragmentVelocity = FragmentDirection * BaseVelocityMagnitude * VelocityVariation;
|
|
||||||
|
if (UseMathematicalSpalling)
|
||||||
|
{
|
||||||
|
// Mathematical fragment calculations
|
||||||
|
float VelocityMPS = ImpactSpeed / 100.0f; // Convert cm/s to m/s
|
||||||
|
|
||||||
|
float FragmentMassRatio = UEBMathematicalBallistics::CalculateSpallFragmentMass(
|
||||||
|
BulletPropertiesAsset->BulletProperties,
|
||||||
|
ResponseEntry->MathematicalProperties,
|
||||||
|
i, FragmentCount
|
||||||
|
);
|
||||||
|
|
||||||
|
FragmentMass = GetEffectiveMass() * FragmentMassRatio;
|
||||||
|
|
||||||
|
float FragmentVelocityMPS = UEBMathematicalBallistics::CalculateSpallFragmentVelocity(
|
||||||
|
BulletPropertiesAsset->BulletProperties,
|
||||||
|
ResponseEntry->MathematicalProperties,
|
||||||
|
VelocityMPS,
|
||||||
|
FragmentMassRatio
|
||||||
|
);
|
||||||
|
|
||||||
|
FragmentSpeed = FragmentVelocityMPS * 100.0f; // Convert back to cm/s
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Artistic fragment calculations
|
||||||
|
float ImpactKineticEnergy = 0.5f * GetEffectiveMass() * ImpactSpeed * ImpactSpeed;
|
||||||
|
float AngleEffectiveness = FMath::Cos(ImpactAngle);
|
||||||
|
float SpallEnergyFraction = FMath::Clamp(0.05f + (AngleEffectiveness * 0.15f), 0.05f, 0.2f);
|
||||||
|
float AvailableSpallEnergy = ImpactKineticEnergy * SpallEnergyFraction;
|
||||||
|
float EnergyPerFragment = AvailableSpallEnergy / FragmentCount;
|
||||||
|
|
||||||
|
float MassFraction = RandomStream.FRandRange(0.02f, 0.2f) * ResponseEntry->SpallMassMultiplier;
|
||||||
|
FragmentMass = GetEffectiveMass() * MassFraction;
|
||||||
|
|
||||||
|
float FragmentKineticEnergy = EnergyPerFragment * RandomStream.FRandRange(0.5f, 1.5f);
|
||||||
|
FragmentSpeed = FMath::Sqrt(2.0f * FragmentKineticEnergy / FragmentMass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fragment direction with dispersion
|
||||||
|
FVector FragmentDirection = RandomStream.VRandCone(SpallBaseDirection, SpreadAngleRad);
|
||||||
|
FVector FragmentVelocity = FragmentDirection * FragmentSpeed;
|
||||||
|
|
||||||
FVector SpawnLocation = ImpactLocation + ImpactNormal * 2.0f;
|
FVector SpawnLocation = ImpactLocation + ImpactNormal * 2.0f;
|
||||||
|
|
||||||
if (HasAuthority())
|
if (HasAuthority())
|
||||||
{
|
{
|
||||||
AEBBullet* Fragment = GetWorld()->SpawnActor<AEBBullet>(FragmentClass, SpawnLocation, FragmentVelocity.Rotation());
|
// Create spawn transform
|
||||||
|
FTransform SpawnTransform;
|
||||||
|
SpawnTransform.SetLocation(SpawnLocation);
|
||||||
|
SpawnTransform.SetRotation(FragmentVelocity.Rotation().Quaternion());
|
||||||
|
|
||||||
|
// Spawn fragment using deferred spawn to set properties before BeginPlay
|
||||||
|
AEBBullet* Fragment = GetWorld()->SpawnActorDeferred<AEBBullet>(FragmentClass, SpawnTransform, GetOwner(), GetInstigator());
|
||||||
|
|
||||||
if (Fragment)
|
if (Fragment)
|
||||||
{
|
{
|
||||||
Fragment->SetOwner(GetOwner());
|
// Configure fragment properties before finishing spawn
|
||||||
Fragment->SetInstigator(GetInstigator());
|
|
||||||
Fragment->Velocity = FragmentVelocity;
|
Fragment->Velocity = FragmentVelocity;
|
||||||
Fragment->Mass = FragmentMass;
|
Fragment->Mass = FragmentMass;
|
||||||
Fragment->OwnerSafe = false;
|
Fragment->OwnerSafe = false;
|
||||||
Fragment->IsSpallFragment = true;
|
Fragment->IsSpallFragment = true;
|
||||||
Fragment->SetFiringBarrel(GetFiringBarrel());
|
|
||||||
|
|
||||||
|
// CRITICAL: Disable spalling on fragments to prevent chain spalling
|
||||||
|
Fragment->EnableSpalling = false;
|
||||||
|
|
||||||
|
// Set fragment-specific properties for proper behavior
|
||||||
|
Fragment->SetFiringBarrel(GetFiringBarrel());
|
||||||
|
Fragment->DespawnVelocity = FMath::Max(DespawnVelocity * 0.5f, 50.0f); // Lower threshold for fragments
|
||||||
|
Fragment->InitialLifeSpan = FMath::Min(InitialLifeSpan, 5.0f); // Shorter lifespan for fragments
|
||||||
|
|
||||||
|
// Inherit material response map but disable spalling
|
||||||
if (Fragment->MaterialResponseMap == nullptr)
|
if (Fragment->MaterialResponseMap == nullptr)
|
||||||
{
|
{
|
||||||
Fragment->MaterialResponseMap = MaterialResponseMap;
|
Fragment->MaterialResponseMap = MaterialResponseMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up velocity parameters to ensure fragment uses its assigned velocity
|
||||||
|
Fragment->MuzzleVelocityMin = FragmentVelocity.Size();
|
||||||
|
Fragment->MuzzleVelocityMax = FragmentVelocity.Size();
|
||||||
|
Fragment->Spread = 0.0f; // No additional spread
|
||||||
|
|
||||||
|
// Configure for fragment physics
|
||||||
|
Fragment->Mass = FragmentMass;
|
||||||
|
Fragment->Diameter = GetEffectiveDiameter() * 0.3f; // Smaller diameter for fragments
|
||||||
|
|
||||||
|
// Set ignored actors to prevent immediate collisions
|
||||||
Fragment->IgnoredActors.Add(HitActor);
|
Fragment->IgnoredActors.Add(HitActor);
|
||||||
Fragment->IgnoredActors.Add(this);
|
Fragment->IgnoredActors.Add(this);
|
||||||
Fragment->IgnoredActors.Append(IgnoredActors);
|
Fragment->IgnoredActors.Append(IgnoredActors);
|
||||||
|
|
||||||
|
// Ensure proper velocity assignment by setting RandomStream seed
|
||||||
|
Fragment->RandomStream.GenerateNewSeed();
|
||||||
|
|
||||||
|
// Finish spawning to trigger BeginPlay with all properties set
|
||||||
|
Fragment->FinishSpawning(SpawnTransform);
|
||||||
|
|
||||||
|
// Double-check velocity assignment after spawn
|
||||||
|
if (Fragment->Velocity.Size() < FragmentVelocity.Size() * 0.8f)
|
||||||
|
{
|
||||||
|
Fragment->Velocity = FragmentVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logging for spall fragment creation
|
||||||
|
if (DebugEnabled)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Spall Fragment Created: Velocity=%.1f cm/s, Mass=%.4f kg, IsSpallFragment=%s, EnableSpalling=%s"),
|
||||||
|
Fragment->Velocity.Size(), Fragment->Mass,
|
||||||
|
Fragment->IsSpallFragment ? TEXT("true") : TEXT("false"),
|
||||||
|
Fragment->EnableSpalling ? TEXT("true") : TEXT("false"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,3 +471,27 @@ void AEBBullet::GenerateSpallFragments(FVector ImpactLocation, FVector ImpactVel
|
|||||||
void AEBBullet::OnSpallFragmentGenerated_Implementation(FVector FragmentLocation, FVector FragmentVelocity, float FragmentMass, UPhysicalMaterial* Material)
|
void AEBBullet::OnSpallFragmentGenerated_Implementation(FVector FragmentLocation, FVector FragmentVelocity, float FragmentMass, UPhysicalMaterial* Material)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AEBBullet::ConfigureAsSpallFragment(float FragmentMass, float FragmentVelocity)
|
||||||
|
{
|
||||||
|
// Mark as spall fragment
|
||||||
|
IsSpallFragment = true;
|
||||||
|
EnableSpalling = false;
|
||||||
|
|
||||||
|
// Set fragment properties
|
||||||
|
Mass = FragmentMass;
|
||||||
|
Diameter = GetEffectiveDiameter() * 0.3f; // Smaller fragments
|
||||||
|
|
||||||
|
// Set velocity parameters
|
||||||
|
float VelocitySize = FragmentVelocity;
|
||||||
|
MuzzleVelocityMin = VelocitySize;
|
||||||
|
MuzzleVelocityMax = VelocitySize;
|
||||||
|
Spread = 0.0f;
|
||||||
|
|
||||||
|
// Fragment lifecycle
|
||||||
|
DespawnVelocity = FMath::Max(DespawnVelocity * 0.5f, 50.0f);
|
||||||
|
InitialLifeSpan = FMath::Min(InitialLifeSpan, 5.0f);
|
||||||
|
|
||||||
|
// Safety settings
|
||||||
|
OwnerSafe = false;
|
||||||
|
}
|
||||||
@@ -294,3 +294,134 @@ float UEBMathematicalBallistics::CalculateMaterialFactor(EBulletMaterial BulletM
|
|||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mathematical Spalling Implementations
|
||||||
|
bool UEBMathematicalBallistics::ShouldGenerateMathematicalSpalling(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float ImpactAngleDegrees)
|
||||||
|
{
|
||||||
|
if (!MaterialProps.EnableMathematicalSpalling)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional safety check: prevent spalling from very small fragments
|
||||||
|
if (BulletProps.GetMassKg() < 0.001f) // Less than 1 gram
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate impact stress using Rankine-Hugoniot relations
|
||||||
|
float BulletDensity = BulletProps.GetMassKg() / (BulletProps.GetCrossSectionCm2() * 0.0001f); // kg/m³
|
||||||
|
float MaterialDensity = MaterialProps.DensityGPerCm3 * 1000.0f; // kg/m³
|
||||||
|
|
||||||
|
// Impact stress (Pa) = 0.5 * ρ * v²
|
||||||
|
float ImpactStress = 0.5f * FMath::Sqrt(BulletDensity * MaterialDensity) * VelocityMPS * VelocityMPS;
|
||||||
|
float ImpactStressMPa = ImpactStress / 1000000.0f; // Convert to MPa
|
||||||
|
|
||||||
|
// Critical stress for spalling
|
||||||
|
float CriticalStress = MaterialProps.SpallStrengthMPa * MaterialProps.CriticalStressFactor;
|
||||||
|
|
||||||
|
// Impact angle factor (perpendicular impacts more effective)
|
||||||
|
float AngleFactor = CalculateAngleFactor(ImpactAngleDegrees);
|
||||||
|
float EffectiveStress = ImpactStressMPa * AngleFactor;
|
||||||
|
|
||||||
|
return EffectiveStress >= CriticalStress;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 UEBMathematicalBallistics::CalculateSpallFragmentCount(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float ImpactAngleDegrees)
|
||||||
|
{
|
||||||
|
// Fragment count based on impact area and fragment density
|
||||||
|
float ImpactArea = BulletProps.GetCrossSectionCm2();
|
||||||
|
float AngleFactor = CalculateAngleFactor(ImpactAngleDegrees);
|
||||||
|
float EffectiveArea = ImpactArea / FMath::Max(AngleFactor, 0.1f); // Grazing impacts affect larger area
|
||||||
|
|
||||||
|
// Energy factor - higher energy creates more fragments
|
||||||
|
float KineticEnergy = CalculateKineticEnergy(BulletProps, VelocityMPS);
|
||||||
|
float EnergyFactor = FMath::Sqrt(KineticEnergy / 1000.0f); // Normalized
|
||||||
|
|
||||||
|
// Material factor - harder materials create more, smaller fragments
|
||||||
|
float MaterialFactor = MaterialProps.MaterialHardness / 100.0f;
|
||||||
|
|
||||||
|
float BaseFragmentCount = EffectiveArea * MaterialProps.MaxFragmentDensity * EnergyFactor * MaterialFactor;
|
||||||
|
|
||||||
|
return FMath::Clamp(FMath::RoundToInt(BaseFragmentCount), 1, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
float UEBMathematicalBallistics::CalculateSpallFragmentVelocity(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float FragmentMassRatio)
|
||||||
|
{
|
||||||
|
// Gurney equation for fragment velocity: v = √(2E/M)
|
||||||
|
// Where E is explosive energy equivalent and M is fragment mass
|
||||||
|
|
||||||
|
float KineticEnergy = CalculateKineticEnergy(BulletProps, VelocityMPS);
|
||||||
|
float SpallEnergyFraction = MaterialProps.FragmentVelocityEfficiency;
|
||||||
|
float AvailableEnergy = KineticEnergy * SpallEnergyFraction;
|
||||||
|
|
||||||
|
// Fragment kinetic energy based on mass ratio
|
||||||
|
float FragmentEnergy = AvailableEnergy * (1.0f / FragmentMassRatio);
|
||||||
|
|
||||||
|
// Calculate fragment velocity using kinetic energy equation
|
||||||
|
float FragmentMass = BulletProps.GetMassKg() * FragmentMassRatio;
|
||||||
|
float FragmentVelocity = FMath::Sqrt(2.0f * FragmentEnergy / FragmentMass);
|
||||||
|
|
||||||
|
// Apply material efficiency factor
|
||||||
|
return FragmentVelocity * MaterialProps.FragmentVelocityEfficiency;
|
||||||
|
}
|
||||||
|
|
||||||
|
float UEBMathematicalBallistics::CalculateSpallFragmentMass(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
int32 FragmentIndex,
|
||||||
|
int32 TotalFragments)
|
||||||
|
{
|
||||||
|
// Power-law distribution for fragment masses
|
||||||
|
// Smaller fragments are more common (Mott distribution)
|
||||||
|
|
||||||
|
float NormalizedIndex = (float)FragmentIndex / (float)TotalFragments;
|
||||||
|
|
||||||
|
// Power-law with typical exponent around -1.6 to -2.0
|
||||||
|
float SizeDistribution = FMath::Pow(NormalizedIndex + 0.1f, MaterialProps.FragmentSizeExponent);
|
||||||
|
|
||||||
|
// Base fragment mass ratio
|
||||||
|
float BaseMassRatio = MaterialProps.AverageFragmentMassRatio;
|
||||||
|
float FragmentMassRatio = BaseMassRatio * SizeDistribution;
|
||||||
|
|
||||||
|
// Clamp to reasonable range
|
||||||
|
return FMath::Clamp(FragmentMassRatio, 0.01f, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float UEBMathematicalBallistics::CalculateSpallConeAngle(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float ImpactAngleDegrees)
|
||||||
|
{
|
||||||
|
// Spall cone angle based on impact angle and material properties
|
||||||
|
// Perpendicular impacts create tighter cones, grazing impacts wider
|
||||||
|
|
||||||
|
float BaseAngle = 30.0f; // Base cone half-angle in degrees
|
||||||
|
|
||||||
|
// Impact angle factor (grazing impacts create wider cones)
|
||||||
|
float AngleFactor = 1.0f + FMath::Sin(FMath::DegreesToRadians(ImpactAngleDegrees));
|
||||||
|
|
||||||
|
// Material factor (harder materials create tighter cones)
|
||||||
|
float MaterialFactor = 100.0f / MaterialProps.MaterialHardness;
|
||||||
|
MaterialFactor = FMath::Clamp(MaterialFactor, 0.5f, 2.0f);
|
||||||
|
|
||||||
|
// Velocity factor (higher velocity creates wider dispersion)
|
||||||
|
float VelocityFactor = 1.0f + (VelocityMPS / 1000.0f) * 0.2f;
|
||||||
|
|
||||||
|
float ConeAngle = BaseAngle * AngleFactor * MaterialFactor * VelocityFactor;
|
||||||
|
|
||||||
|
return FMath::Clamp(ConeAngle, 10.0f, 90.0f);
|
||||||
|
}
|
||||||
@@ -217,10 +217,13 @@ float AEBBullet::Trace(FVector start, FVector PreviousVelocity, float delta, TEn
|
|||||||
// Entry spalling
|
// Entry spalling
|
||||||
GenerateSpallFragments(HitResult.Location, Velocity, HitResult.Normal, PhysMaterial, HitResult.GetActor());
|
GenerateSpallFragments(HitResult.Location, Velocity, HitResult.Normal, PhysMaterial, HitResult.GetActor());
|
||||||
|
|
||||||
// Exit spalling for penetration
|
// Exit spalling (backspall) for penetration - typically more dangerous
|
||||||
if (Penetration && (exitLoc - HitResult.Location).Size() > 1.0f)
|
if (Penetration && (exitLoc - HitResult.Location).Size() > 1.0f)
|
||||||
{
|
{
|
||||||
GenerateSpallFragments(exitLoc, NewVelocity, -exitNormal, PhysMaterial, HitResult.GetActor());
|
// Exit spalling velocity is based on remaining velocity after penetration
|
||||||
|
// Backspall typically has higher fragment velocity than entry spalling
|
||||||
|
FVector ExitSpallVelocity = NewVelocity * 1.2f; // Amplify for more realistic backspall effect
|
||||||
|
GenerateSpallFragments(exitLoc, ExitSpallVelocity, -exitNormal, PhysMaterial, HitResult.GetActor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -258,6 +258,9 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spalling")
|
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spalling")
|
||||||
bool ShouldGenerateSpalling(FVector ImpactVelocity, UPhysicalMaterial* Material) const;
|
bool ShouldGenerateSpalling(FVector ImpactVelocity, UPhysicalMaterial* Material) const;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "EBBullet|Spalling")
|
||||||
|
void ConfigureAsSpallFragment(float FragmentMass, float FragmentVelocity);
|
||||||
|
|
||||||
void SetFiringBarrel(class UEBBarrel* Barrel) { FiringBarrel = Barrel; }
|
void SetFiringBarrel(class UEBBarrel* Barrel) { FiringBarrel = Barrel; }
|
||||||
|
|
||||||
//pooling
|
//pooling
|
||||||
|
|||||||
@@ -168,6 +168,28 @@ struct FMathematicalMaterialProperties
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistic Properties", meta = (ToolTip = "Energy absorption coefficient"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistic Properties", meta = (ToolTip = "Energy absorption coefficient"))
|
||||||
float EnergyAbsorptionCoefficient = 0.7f;
|
float EnergyAbsorptionCoefficient = 0.7f;
|
||||||
|
|
||||||
|
// Spalling Properties
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (ToolTip = "Enable mathematical spalling calculations"))
|
||||||
|
bool EnableMathematicalSpalling = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (EditCondition = "EnableMathematicalSpalling", ToolTip = "Spall strength in MPa (material resistance to spalling)"))
|
||||||
|
float SpallStrengthMPa = 150.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (EditCondition = "EnableMathematicalSpalling", ToolTip = "Critical stress factor for spalling initiation"))
|
||||||
|
float CriticalStressFactor = 2.5f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (EditCondition = "EnableMathematicalSpalling", ToolTip = "Fragment velocity efficiency (0-1)"))
|
||||||
|
float FragmentVelocityEfficiency = 0.25f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (EditCondition = "EnableMathematicalSpalling", ToolTip = "Average fragment mass ratio"))
|
||||||
|
float AverageFragmentMassRatio = 0.08f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (EditCondition = "EnableMathematicalSpalling", ToolTip = "Fragment size distribution exponent"))
|
||||||
|
float FragmentSizeExponent = -1.6f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties", meta = (EditCondition = "EnableMathematicalSpalling", ToolTip = "Maximum fragment count per unit area"))
|
||||||
|
float MaxFragmentDensity = 50.0f;
|
||||||
|
|
||||||
// Constructor with default steel properties
|
// Constructor with default steel properties
|
||||||
FMathematicalMaterialProperties()
|
FMathematicalMaterialProperties()
|
||||||
{
|
{
|
||||||
@@ -179,6 +201,13 @@ struct FMathematicalMaterialProperties
|
|||||||
BallisticLimitVelocity = 2000.0f;
|
BallisticLimitVelocity = 2000.0f;
|
||||||
PerforationCoefficient = 1.0f;
|
PerforationCoefficient = 1.0f;
|
||||||
EnergyAbsorptionCoefficient = 0.7f;
|
EnergyAbsorptionCoefficient = 0.7f;
|
||||||
|
EnableMathematicalSpalling = false;
|
||||||
|
SpallStrengthMPa = 150.0f;
|
||||||
|
CriticalStressFactor = 2.5f;
|
||||||
|
FragmentVelocityEfficiency = 0.25f;
|
||||||
|
AverageFragmentMassRatio = 0.08f;
|
||||||
|
FragmentSizeExponent = -1.6f;
|
||||||
|
MaxFragmentDensity = 50.0f;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,47 @@ public:
|
|||||||
float VelocityMPS
|
float VelocityMPS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Mathematical spalling calculations
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Mathematical Spalling")
|
||||||
|
static bool ShouldGenerateMathematicalSpalling(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float ImpactAngleDegrees
|
||||||
|
);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Mathematical Spalling")
|
||||||
|
static int32 CalculateSpallFragmentCount(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float ImpactAngleDegrees
|
||||||
|
);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Mathematical Spalling")
|
||||||
|
static float CalculateSpallFragmentVelocity(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float FragmentMassRatio
|
||||||
|
);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Mathematical Spalling")
|
||||||
|
static float CalculateSpallFragmentMass(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
int32 FragmentIndex,
|
||||||
|
int32 TotalFragments
|
||||||
|
);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Mathematical Spalling")
|
||||||
|
static float CalculateSpallConeAngle(
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
float VelocityMPS,
|
||||||
|
float ImpactAngleDegrees
|
||||||
|
);
|
||||||
|
|
||||||
// Utility function to convert feet per second to meters per second
|
// Utility function to convert feet per second to meters per second
|
||||||
UFUNCTION(BlueprintCallable, Category = "Mathematical Ballistics")
|
UFUNCTION(BlueprintCallable, Category = "Mathematical Ballistics")
|
||||||
static float ConvertFPStoMPS(float FPS) { return FPS * 0.3048f; }
|
static float ConvertFPStoMPS(float FPS) { return FPS * 0.3048f; }
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ public class EasyBallisticsEditor : ModuleRules
|
|||||||
"PropertyEditor",
|
"PropertyEditor",
|
||||||
"WorkspaceMenuStructure",
|
"WorkspaceMenuStructure",
|
||||||
"DesktopPlatform",
|
"DesktopPlatform",
|
||||||
"ToolMenus"
|
"ToolMenus",
|
||||||
|
"Json"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,596 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "EBJsonImportExportTool.h"
|
||||||
|
#include "Widgets/Layout/SBorder.h"
|
||||||
|
#include "Widgets/Layout/SBox.h"
|
||||||
|
#include "Widgets/Layout/SScrollBox.h"
|
||||||
|
#include "Widgets/Text/STextBlock.h"
|
||||||
|
#include "Widgets/Input/SButton.h"
|
||||||
|
#include "Widgets/Layout/SUniformGridPanel.h"
|
||||||
|
#include "Framework/Application/SlateApplication.h"
|
||||||
|
#include "DesktopPlatformModule.h"
|
||||||
|
#include "Json.h"
|
||||||
|
#include "Engine/Engine.h"
|
||||||
|
#include "AssetToolsModule.h"
|
||||||
|
#include "ContentBrowserModule.h"
|
||||||
|
#include "IContentBrowserSingleton.h"
|
||||||
|
#include "Framework/Docking/TabManager.h"
|
||||||
|
#include "WorkspaceMenuStructure.h"
|
||||||
|
#include "WorkspaceMenuStructureModule.h"
|
||||||
|
#include "ToolMenus.h"
|
||||||
|
#include "HAL/IConsoleManager.h"
|
||||||
|
|
||||||
|
const FName FEBJsonImportExportTool::ImportExportTabName("EBJsonImportExport");
|
||||||
|
|
||||||
|
// Console command to open the tool
|
||||||
|
static FAutoConsoleCommand OpenJsonToolCommand(
|
||||||
|
TEXT("EasyBallistics.OpenJsonTool"),
|
||||||
|
TEXT("Opens the EasyBallistics JSON Import/Export tool"),
|
||||||
|
FConsoleCommandDelegate::CreateStatic(&FEBJsonImportExportTool::OpenImportExportWindow)
|
||||||
|
);
|
||||||
|
|
||||||
|
void SEBJsonImportExportTool::Construct(const FArguments& InArgs)
|
||||||
|
{
|
||||||
|
ChildSlot
|
||||||
|
[
|
||||||
|
SNew(SBorder)
|
||||||
|
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
||||||
|
[
|
||||||
|
SNew(SScrollBox)
|
||||||
|
+ SScrollBox::Slot()
|
||||||
|
[
|
||||||
|
SNew(SBox)
|
||||||
|
.Padding(10.0f)
|
||||||
|
[
|
||||||
|
SNew(SVerticalBox)
|
||||||
|
|
||||||
|
// Title
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
.Padding(0, 0, 0, 20)
|
||||||
|
[
|
||||||
|
SNew(STextBlock)
|
||||||
|
.Text(FText::FromString("EasyBallistics JSON Import/Export Tool"))
|
||||||
|
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 16))
|
||||||
|
.Justification(ETextJustify::Center)
|
||||||
|
]
|
||||||
|
|
||||||
|
// Bullet Properties Section
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
.Padding(0, 0, 0, 15)
|
||||||
|
[
|
||||||
|
SNew(SBorder)
|
||||||
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
||||||
|
.Padding(10)
|
||||||
|
[
|
||||||
|
SNew(SVerticalBox)
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
[
|
||||||
|
SNew(STextBlock)
|
||||||
|
.Text(FText::FromString("Bullet Properties"))
|
||||||
|
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 14))
|
||||||
|
]
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
.Padding(0, 10, 0, 0)
|
||||||
|
[
|
||||||
|
SNew(SUniformGridPanel)
|
||||||
|
.SlotPadding(5)
|
||||||
|
+ SUniformGridPanel::Slot(0, 0)
|
||||||
|
[
|
||||||
|
SNew(SButton)
|
||||||
|
.Text(FText::FromString("Export Bullet Properties"))
|
||||||
|
.OnClicked(this, &SEBJsonImportExportTool::OnExportBulletPropertiesClicked)
|
||||||
|
]
|
||||||
|
+ SUniformGridPanel::Slot(1, 0)
|
||||||
|
[
|
||||||
|
SNew(SButton)
|
||||||
|
.Text(FText::FromString("Import Bullet Properties"))
|
||||||
|
.OnClicked(this, &SEBJsonImportExportTool::OnImportBulletPropertiesClicked)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
// Material Response Section
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
.Padding(0, 0, 0, 15)
|
||||||
|
[
|
||||||
|
SNew(SBorder)
|
||||||
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
||||||
|
.Padding(10)
|
||||||
|
[
|
||||||
|
SNew(SVerticalBox)
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
[
|
||||||
|
SNew(STextBlock)
|
||||||
|
.Text(FText::FromString("Material Response Maps"))
|
||||||
|
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 14))
|
||||||
|
]
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
.Padding(0, 10, 0, 0)
|
||||||
|
[
|
||||||
|
SNew(SUniformGridPanel)
|
||||||
|
.SlotPadding(5)
|
||||||
|
+ SUniformGridPanel::Slot(0, 0)
|
||||||
|
[
|
||||||
|
SNew(SButton)
|
||||||
|
.Text(FText::FromString("Export Material Response"))
|
||||||
|
.OnClicked(this, &SEBJsonImportExportTool::OnExportMaterialResponseClicked)
|
||||||
|
]
|
||||||
|
+ SUniformGridPanel::Slot(1, 0)
|
||||||
|
[
|
||||||
|
SNew(SButton)
|
||||||
|
.Text(FText::FromString("Import Material Response"))
|
||||||
|
.OnClicked(this, &SEBJsonImportExportTool::OnImportMaterialResponseClicked)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
// Status Section
|
||||||
|
+ SVerticalBox::Slot()
|
||||||
|
.AutoHeight()
|
||||||
|
.Padding(0, 20, 0, 0)
|
||||||
|
[
|
||||||
|
SNew(SBorder)
|
||||||
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryBottom"))
|
||||||
|
.Padding(10)
|
||||||
|
[
|
||||||
|
SAssignNew(StatusText, STextBlock)
|
||||||
|
.Text(FText::FromString("Ready"))
|
||||||
|
.AutoWrapText(true)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
FReply SEBJsonImportExportTool::OnExportBulletPropertiesClicked()
|
||||||
|
{
|
||||||
|
FString Filename;
|
||||||
|
if (SaveFileDialog("Export Bullet Properties", "", "JSON Files (*.json)|*.json", Filename))
|
||||||
|
{
|
||||||
|
// For demo purposes, create default bullet properties
|
||||||
|
FMathematicalBulletProperties DefaultProperties;
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> JsonObject = BulletPropertiesToJson(DefaultProperties);
|
||||||
|
|
||||||
|
FString OutputString;
|
||||||
|
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
|
||||||
|
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);
|
||||||
|
|
||||||
|
if (FFileHelper::SaveStringToFile(OutputString, *Filename))
|
||||||
|
{
|
||||||
|
UpdateStatus(FString::Printf(TEXT("Successfully exported bullet properties to: %s"), *Filename));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to save bullet properties file."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FReply::Handled();
|
||||||
|
}
|
||||||
|
|
||||||
|
FReply SEBJsonImportExportTool::OnImportBulletPropertiesClicked()
|
||||||
|
{
|
||||||
|
FString Filename;
|
||||||
|
if (OpenFileDialog("Import Bullet Properties", "", "JSON Files (*.json)|*.json", Filename))
|
||||||
|
{
|
||||||
|
FString FileContent;
|
||||||
|
if (FFileHelper::LoadFileToString(FileContent, *Filename))
|
||||||
|
{
|
||||||
|
TSharedPtr<FJsonObject> JsonObject;
|
||||||
|
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(FileContent);
|
||||||
|
|
||||||
|
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
|
||||||
|
{
|
||||||
|
FMathematicalBulletProperties ImportedProperties;
|
||||||
|
if (JsonToBulletProperties(JsonObject, ImportedProperties))
|
||||||
|
{
|
||||||
|
UpdateStatus(FString::Printf(TEXT("Successfully imported bullet properties from: %s"), *Filename));
|
||||||
|
// Here you would typically create a new asset or update an existing one
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to parse bullet properties from JSON."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to parse JSON file."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to load file."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FReply::Handled();
|
||||||
|
}
|
||||||
|
|
||||||
|
FReply SEBJsonImportExportTool::OnExportMaterialResponseClicked()
|
||||||
|
{
|
||||||
|
FString Filename;
|
||||||
|
if (SaveFileDialog("Export Material Response", "", "JSON Files (*.json)|*.json", Filename))
|
||||||
|
{
|
||||||
|
// For demo purposes, create default material response
|
||||||
|
FEBMaterialResponseMapEntry DefaultEntry;
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> JsonObject = MaterialResponseToJson(DefaultEntry);
|
||||||
|
|
||||||
|
FString OutputString;
|
||||||
|
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
|
||||||
|
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);
|
||||||
|
|
||||||
|
if (FFileHelper::SaveStringToFile(OutputString, *Filename))
|
||||||
|
{
|
||||||
|
UpdateStatus(FString::Printf(TEXT("Successfully exported material response to: %s"), *Filename));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to save material response file."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FReply::Handled();
|
||||||
|
}
|
||||||
|
|
||||||
|
FReply SEBJsonImportExportTool::OnImportMaterialResponseClicked()
|
||||||
|
{
|
||||||
|
FString Filename;
|
||||||
|
if (OpenFileDialog("Import Material Response", "", "JSON Files (*.json)|*.json", Filename))
|
||||||
|
{
|
||||||
|
FString FileContent;
|
||||||
|
if (FFileHelper::LoadFileToString(FileContent, *Filename))
|
||||||
|
{
|
||||||
|
TSharedPtr<FJsonObject> JsonObject;
|
||||||
|
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(FileContent);
|
||||||
|
|
||||||
|
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
|
||||||
|
{
|
||||||
|
FEBMaterialResponseMapEntry ImportedEntry;
|
||||||
|
if (JsonToMaterialResponse(JsonObject, ImportedEntry))
|
||||||
|
{
|
||||||
|
UpdateStatus(FString::Printf(TEXT("Successfully imported material response from: %s"), *Filename));
|
||||||
|
// Here you would typically create a new asset or update an existing one
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to parse material response from JSON."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to parse JSON file."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus(TEXT("Failed to load file."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FReply::Handled();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEBJsonImportExportTool::OpenFileDialog(const FString& DialogTitle, const FString& DefaultPath, const FString& FileTypes, FString& OutFilename)
|
||||||
|
{
|
||||||
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
||||||
|
if (DesktopPlatform)
|
||||||
|
{
|
||||||
|
TArray<FString> OutFilenames;
|
||||||
|
bool bOpened = DesktopPlatform->OpenFileDialog(
|
||||||
|
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
|
||||||
|
DialogTitle,
|
||||||
|
DefaultPath,
|
||||||
|
TEXT(""),
|
||||||
|
FileTypes,
|
||||||
|
EFileDialogFlags::None,
|
||||||
|
OutFilenames
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bOpened && OutFilenames.Num() > 0)
|
||||||
|
{
|
||||||
|
OutFilename = OutFilenames[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEBJsonImportExportTool::SaveFileDialog(const FString& DialogTitle, const FString& DefaultPath, const FString& FileTypes, FString& OutFilename)
|
||||||
|
{
|
||||||
|
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
||||||
|
if (DesktopPlatform)
|
||||||
|
{
|
||||||
|
TArray<FString> OutFilenames;
|
||||||
|
bool bOpened = DesktopPlatform->SaveFileDialog(
|
||||||
|
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
|
||||||
|
DialogTitle,
|
||||||
|
DefaultPath,
|
||||||
|
TEXT(""),
|
||||||
|
FileTypes,
|
||||||
|
EFileDialogFlags::None,
|
||||||
|
OutFilenames
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bOpened && OutFilenames.Num() > 0)
|
||||||
|
{
|
||||||
|
OutFilename = OutFilenames[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> SEBJsonImportExportTool::BulletPropertiesToJson(const FMathematicalBulletProperties& Properties)
|
||||||
|
{
|
||||||
|
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||||
|
|
||||||
|
// Basic Properties
|
||||||
|
JsonObject->SetNumberField("GrainWeight", Properties.GrainWeight);
|
||||||
|
JsonObject->SetNumberField("DiameterInches", Properties.DiameterInches);
|
||||||
|
JsonObject->SetNumberField("LengthInches", Properties.LengthInches);
|
||||||
|
JsonObject->SetNumberField("BulletType", static_cast<int32>(Properties.BulletType));
|
||||||
|
JsonObject->SetNumberField("BulletMaterial", static_cast<int32>(Properties.BulletMaterial));
|
||||||
|
|
||||||
|
// Ballistics
|
||||||
|
JsonObject->SetNumberField("BallisticCoefficientG1", Properties.BallisticCoefficientG1);
|
||||||
|
JsonObject->SetNumberField("BallisticCoefficientG7", Properties.BallisticCoefficientG7);
|
||||||
|
JsonObject->SetBoolField("UseG7Model", Properties.UseG7Model);
|
||||||
|
JsonObject->SetNumberField("SectionalDensity", Properties.SectionalDensity);
|
||||||
|
|
||||||
|
// Penetration
|
||||||
|
JsonObject->SetNumberField("BulletHardness", Properties.BulletHardness);
|
||||||
|
JsonObject->SetNumberField("PenetrationEnergyThreshold", Properties.PenetrationEnergyThreshold);
|
||||||
|
JsonObject->SetNumberField("ExpansionVelocityThreshold", Properties.ExpansionVelocityThreshold);
|
||||||
|
JsonObject->SetNumberField("MaxExpansionMultiplier", Properties.MaxExpansionMultiplier);
|
||||||
|
|
||||||
|
return JsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEBJsonImportExportTool::JsonToBulletProperties(const TSharedPtr<FJsonObject>& JsonObject, FMathematicalBulletProperties& OutProperties)
|
||||||
|
{
|
||||||
|
if (!JsonObject.IsValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic Properties
|
||||||
|
OutProperties.GrainWeight = JsonObject->GetNumberField(TEXT("GrainWeight"));
|
||||||
|
OutProperties.DiameterInches = JsonObject->GetNumberField(TEXT("DiameterInches"));
|
||||||
|
OutProperties.LengthInches = JsonObject->GetNumberField(TEXT("LengthInches"));
|
||||||
|
OutProperties.BulletType = static_cast<EBulletType>(JsonObject->GetIntegerField(TEXT("BulletType")));
|
||||||
|
OutProperties.BulletMaterial = static_cast<EBulletMaterial>(JsonObject->GetIntegerField(TEXT("BulletMaterial")));
|
||||||
|
|
||||||
|
// Ballistics
|
||||||
|
OutProperties.BallisticCoefficientG1 = JsonObject->GetNumberField(TEXT("BallisticCoefficientG1"));
|
||||||
|
OutProperties.BallisticCoefficientG7 = JsonObject->GetNumberField(TEXT("BallisticCoefficientG7"));
|
||||||
|
OutProperties.UseG7Model = JsonObject->GetBoolField(TEXT("UseG7Model"));
|
||||||
|
OutProperties.SectionalDensity = JsonObject->GetNumberField(TEXT("SectionalDensity"));
|
||||||
|
|
||||||
|
// Penetration
|
||||||
|
OutProperties.BulletHardness = JsonObject->GetNumberField(TEXT("BulletHardness"));
|
||||||
|
OutProperties.PenetrationEnergyThreshold = JsonObject->GetNumberField(TEXT("PenetrationEnergyThreshold"));
|
||||||
|
OutProperties.ExpansionVelocityThreshold = JsonObject->GetNumberField(TEXT("ExpansionVelocityThreshold"));
|
||||||
|
OutProperties.MaxExpansionMultiplier = JsonObject->GetNumberField(TEXT("MaxExpansionMultiplier"));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> SEBJsonImportExportTool::MaterialResponseToJson(const FEBMaterialResponseMapEntry& Entry)
|
||||||
|
{
|
||||||
|
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||||
|
|
||||||
|
// Artistic Properties
|
||||||
|
JsonObject->SetNumberField("PenTraceType", static_cast<int32>(Entry.PenTraceType));
|
||||||
|
JsonObject->SetBoolField("NeverPenetrate", Entry.NeverPenetrate);
|
||||||
|
JsonObject->SetNumberField("PenetrationDepthMultiplier", Entry.PenetrationDepthMultiplier);
|
||||||
|
JsonObject->SetNumberField("PenetrationNormalization", Entry.PenetrationNormalization);
|
||||||
|
JsonObject->SetNumberField("PenetrationNormalizationGrazing", Entry.PenetrationNormalizationGrazing);
|
||||||
|
JsonObject->SetNumberField("PenetrationEntryAngleSpread", Entry.PenetrationEntryAngleSpread);
|
||||||
|
JsonObject->SetNumberField("PenetrationExitAngleSpread", Entry.PenetrationExitAngleSpread);
|
||||||
|
JsonObject->SetBoolField("NeverRicochet", Entry.NeverRicochet);
|
||||||
|
JsonObject->SetNumberField("RicochetProbabilityMultiplier", Entry.RicochetProbabilityMultiplier);
|
||||||
|
JsonObject->SetNumberField("RicochetRestitution", Entry.RicochetRestitution);
|
||||||
|
JsonObject->SetNumberField("RicochetRestitutionInfluence", Entry.RicochetRestitutionInfluence);
|
||||||
|
JsonObject->SetNumberField("RicochetFriction", Entry.RicochetFriction);
|
||||||
|
JsonObject->SetNumberField("RicochetFrictionInfluence", Entry.RicochetFrictionInfluence);
|
||||||
|
JsonObject->SetNumberField("RicochetSpread", Entry.RicochetSpread);
|
||||||
|
|
||||||
|
// Spalling Properties
|
||||||
|
JsonObject->SetBoolField("EnableSpalling", Entry.EnableSpalling);
|
||||||
|
JsonObject->SetNumberField("SpallVelocityThreshold", Entry.SpallVelocityThreshold);
|
||||||
|
JsonObject->SetNumberField("SpallFragmentCount", Entry.SpallFragmentCount);
|
||||||
|
JsonObject->SetNumberField("SpallSpreadAngle", Entry.SpallSpreadAngle);
|
||||||
|
JsonObject->SetNumberField("SpallVelocityMultiplier", Entry.SpallVelocityMultiplier);
|
||||||
|
JsonObject->SetNumberField("SpallMassMultiplier", Entry.SpallMassMultiplier);
|
||||||
|
|
||||||
|
// Mathematical Properties
|
||||||
|
JsonObject->SetBoolField("UseMathematicalProperties", Entry.UseMathematicalProperties);
|
||||||
|
if (Entry.UseMathematicalProperties)
|
||||||
|
{
|
||||||
|
TSharedPtr<FJsonObject> MathProps = MaterialPropertiesToJson(Entry.MathematicalProperties);
|
||||||
|
JsonObject->SetObjectField("MathematicalProperties", MathProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEBJsonImportExportTool::JsonToMaterialResponse(const TSharedPtr<FJsonObject>& JsonObject, FEBMaterialResponseMapEntry& OutEntry)
|
||||||
|
{
|
||||||
|
if (!JsonObject.IsValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Artistic Properties
|
||||||
|
OutEntry.PenTraceType = static_cast<EPenTraceType>(JsonObject->GetIntegerField(TEXT("PenTraceType")));
|
||||||
|
OutEntry.NeverPenetrate = JsonObject->GetBoolField(TEXT("NeverPenetrate"));
|
||||||
|
OutEntry.PenetrationDepthMultiplier = JsonObject->GetNumberField(TEXT("PenetrationDepthMultiplier"));
|
||||||
|
OutEntry.PenetrationNormalization = JsonObject->GetNumberField(TEXT("PenetrationNormalization"));
|
||||||
|
OutEntry.PenetrationNormalizationGrazing = JsonObject->GetNumberField(TEXT("PenetrationNormalizationGrazing"));
|
||||||
|
OutEntry.PenetrationEntryAngleSpread = JsonObject->GetNumberField(TEXT("PenetrationEntryAngleSpread"));
|
||||||
|
OutEntry.PenetrationExitAngleSpread = JsonObject->GetNumberField(TEXT("PenetrationExitAngleSpread"));
|
||||||
|
OutEntry.NeverRicochet = JsonObject->GetBoolField(TEXT("NeverRicochet"));
|
||||||
|
OutEntry.RicochetProbabilityMultiplier = JsonObject->GetNumberField(TEXT("RicochetProbabilityMultiplier"));
|
||||||
|
OutEntry.RicochetRestitution = JsonObject->GetNumberField(TEXT("RicochetRestitution"));
|
||||||
|
OutEntry.RicochetRestitutionInfluence = JsonObject->GetNumberField(TEXT("RicochetRestitutionInfluence"));
|
||||||
|
OutEntry.RicochetFriction = JsonObject->GetNumberField(TEXT("RicochetFriction"));
|
||||||
|
OutEntry.RicochetFrictionInfluence = JsonObject->GetNumberField(TEXT("RicochetFrictionInfluence"));
|
||||||
|
OutEntry.RicochetSpread = JsonObject->GetNumberField(TEXT("RicochetSpread"));
|
||||||
|
|
||||||
|
// Spalling Properties
|
||||||
|
OutEntry.EnableSpalling = JsonObject->GetBoolField(TEXT("EnableSpalling"));
|
||||||
|
OutEntry.SpallVelocityThreshold = JsonObject->GetNumberField(TEXT("SpallVelocityThreshold"));
|
||||||
|
OutEntry.SpallFragmentCount = JsonObject->GetIntegerField(TEXT("SpallFragmentCount"));
|
||||||
|
OutEntry.SpallSpreadAngle = JsonObject->GetNumberField(TEXT("SpallSpreadAngle"));
|
||||||
|
OutEntry.SpallVelocityMultiplier = JsonObject->GetNumberField(TEXT("SpallVelocityMultiplier"));
|
||||||
|
OutEntry.SpallMassMultiplier = JsonObject->GetNumberField(TEXT("SpallMassMultiplier"));
|
||||||
|
|
||||||
|
// Mathematical Properties
|
||||||
|
OutEntry.UseMathematicalProperties = JsonObject->GetBoolField(TEXT("UseMathematicalProperties"));
|
||||||
|
if (OutEntry.UseMathematicalProperties)
|
||||||
|
{
|
||||||
|
const TSharedPtr<FJsonObject>* MathPropsPtr;
|
||||||
|
if (JsonObject->TryGetObjectField(TEXT("MathematicalProperties"), MathPropsPtr))
|
||||||
|
{
|
||||||
|
JsonToMaterialProperties(*MathPropsPtr, OutEntry.MathematicalProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> SEBJsonImportExportTool::MaterialPropertiesToJson(const FMathematicalMaterialProperties& Properties)
|
||||||
|
{
|
||||||
|
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
|
||||||
|
|
||||||
|
// Material Properties
|
||||||
|
JsonObject->SetNumberField("DensityGPerCm3", Properties.DensityGPerCm3);
|
||||||
|
JsonObject->SetNumberField("MaterialHardness", Properties.MaterialHardness);
|
||||||
|
JsonObject->SetNumberField("TensileStrengthMPa", Properties.TensileStrengthMPa);
|
||||||
|
JsonObject->SetNumberField("YieldStrengthMPa", Properties.YieldStrengthMPa);
|
||||||
|
JsonObject->SetNumberField("ElasticModulusGPa", Properties.ElasticModulusGPa);
|
||||||
|
|
||||||
|
// Ballistic Properties
|
||||||
|
JsonObject->SetNumberField("BallisticLimitVelocity", Properties.BallisticLimitVelocity);
|
||||||
|
JsonObject->SetNumberField("PerforationCoefficient", Properties.PerforationCoefficient);
|
||||||
|
JsonObject->SetNumberField("EnergyAbsorptionCoefficient", Properties.EnergyAbsorptionCoefficient);
|
||||||
|
|
||||||
|
// Spalling Properties
|
||||||
|
JsonObject->SetBoolField("EnableMathematicalSpalling", Properties.EnableMathematicalSpalling);
|
||||||
|
JsonObject->SetNumberField("SpallStrengthMPa", Properties.SpallStrengthMPa);
|
||||||
|
JsonObject->SetNumberField("CriticalStressFactor", Properties.CriticalStressFactor);
|
||||||
|
JsonObject->SetNumberField("FragmentVelocityEfficiency", Properties.FragmentVelocityEfficiency);
|
||||||
|
JsonObject->SetNumberField("AverageFragmentMassRatio", Properties.AverageFragmentMassRatio);
|
||||||
|
JsonObject->SetNumberField("FragmentSizeExponent", Properties.FragmentSizeExponent);
|
||||||
|
JsonObject->SetNumberField("MaxFragmentDensity", Properties.MaxFragmentDensity);
|
||||||
|
|
||||||
|
return JsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEBJsonImportExportTool::JsonToMaterialProperties(const TSharedPtr<FJsonObject>& JsonObject, FMathematicalMaterialProperties& OutProperties)
|
||||||
|
{
|
||||||
|
if (!JsonObject.IsValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Material Properties
|
||||||
|
OutProperties.DensityGPerCm3 = JsonObject->GetNumberField(TEXT("DensityGPerCm3"));
|
||||||
|
OutProperties.MaterialHardness = JsonObject->GetNumberField(TEXT("MaterialHardness"));
|
||||||
|
OutProperties.TensileStrengthMPa = JsonObject->GetNumberField(TEXT("TensileStrengthMPa"));
|
||||||
|
OutProperties.YieldStrengthMPa = JsonObject->GetNumberField(TEXT("YieldStrengthMPa"));
|
||||||
|
OutProperties.ElasticModulusGPa = JsonObject->GetNumberField(TEXT("ElasticModulusGPa"));
|
||||||
|
|
||||||
|
// Ballistic Properties
|
||||||
|
OutProperties.BallisticLimitVelocity = JsonObject->GetNumberField(TEXT("BallisticLimitVelocity"));
|
||||||
|
OutProperties.PerforationCoefficient = JsonObject->GetNumberField(TEXT("PerforationCoefficient"));
|
||||||
|
OutProperties.EnergyAbsorptionCoefficient = JsonObject->GetNumberField(TEXT("EnergyAbsorptionCoefficient"));
|
||||||
|
|
||||||
|
// Spalling Properties
|
||||||
|
OutProperties.EnableMathematicalSpalling = JsonObject->GetBoolField(TEXT("EnableMathematicalSpalling"));
|
||||||
|
OutProperties.SpallStrengthMPa = JsonObject->GetNumberField(TEXT("SpallStrengthMPa"));
|
||||||
|
OutProperties.CriticalStressFactor = JsonObject->GetNumberField(TEXT("CriticalStressFactor"));
|
||||||
|
OutProperties.FragmentVelocityEfficiency = JsonObject->GetNumberField(TEXT("FragmentVelocityEfficiency"));
|
||||||
|
OutProperties.AverageFragmentMassRatio = JsonObject->GetNumberField(TEXT("AverageFragmentMassRatio"));
|
||||||
|
OutProperties.FragmentSizeExponent = JsonObject->GetNumberField(TEXT("FragmentSizeExponent"));
|
||||||
|
OutProperties.MaxFragmentDensity = JsonObject->GetNumberField(TEXT("MaxFragmentDensity"));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SEBJsonImportExportTool::UpdateStatus(const FString& Message)
|
||||||
|
{
|
||||||
|
if (StatusText.IsValid())
|
||||||
|
{
|
||||||
|
StatusText->SetText(FText::FromString(Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FEBJsonImportExportTool implementation
|
||||||
|
|
||||||
|
void FEBJsonImportExportTool::RegisterMenus()
|
||||||
|
{
|
||||||
|
// Register the tab spawner
|
||||||
|
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(ImportExportTabName, FOnSpawnTab::CreateStatic(&FEBJsonImportExportTool::OnSpawnImportExportTab))
|
||||||
|
.SetDisplayName(NSLOCTEXT("EasyBallisticsEditor", "ImportExportTabTitle", "Ballistics JSON Import/Export"))
|
||||||
|
.SetMenuType(ETabSpawnerMenuType::Hidden);
|
||||||
|
|
||||||
|
// Add to main menu bar under Tools
|
||||||
|
UToolMenus* ToolMenus = UToolMenus::Get();
|
||||||
|
{
|
||||||
|
UToolMenu* MainMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Tools");
|
||||||
|
{
|
||||||
|
FToolMenuSection& Section = MainMenu->FindOrAddSection("Programming");
|
||||||
|
Section.AddMenuEntry(
|
||||||
|
"OpenEBJsonImportExport",
|
||||||
|
NSLOCTEXT("EasyBallisticsEditor", "OpenEBJsonImportExport", "Ballistics JSON Import/Export"),
|
||||||
|
NSLOCTEXT("EasyBallisticsEditor", "OpenEBJsonImportExportTooltip", "Open the Ballistics JSON Import/Export tool"),
|
||||||
|
FSlateIcon(),
|
||||||
|
FUIAction(FExecuteAction::CreateStatic(&FEBJsonImportExportTool::OpenImportExportWindow))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FEBJsonImportExportTool::OpenImportExportWindow()
|
||||||
|
{
|
||||||
|
// Ensure the tab spawner is registered
|
||||||
|
if (!FGlobalTabmanager::Get()->HasTabSpawner(ImportExportTabName))
|
||||||
|
{
|
||||||
|
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(ImportExportTabName, FOnSpawnTab::CreateStatic(&FEBJsonImportExportTool::OnSpawnImportExportTab))
|
||||||
|
.SetDisplayName(NSLOCTEXT("EasyBallisticsEditor", "ImportExportTabTitle", "Ballistics JSON Import/Export"))
|
||||||
|
.SetMenuType(ETabSpawnerMenuType::Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
FGlobalTabmanager::Get()->TryInvokeTab(ImportExportTabName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FEBJsonImportExportTool::UnregisterMenus()
|
||||||
|
{
|
||||||
|
if (FGlobalTabmanager::Get()->HasTabSpawner(ImportExportTabName))
|
||||||
|
{
|
||||||
|
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ImportExportTabName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedRef<SDockTab> FEBJsonImportExportTool::OnSpawnImportExportTab(const FSpawnTabArgs& SpawnTabArgs)
|
||||||
|
{
|
||||||
|
return SNew(SDockTab)
|
||||||
|
.TabRole(ETabRole::NomadTab)
|
||||||
|
[
|
||||||
|
SNew(SEBJsonImportExportTool)
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "EBBarrelComponentFactory.h"
|
#include "EBBarrelComponentFactory.h"
|
||||||
#include "EBMathematicalBallisticsFactory.h"
|
#include "EBMathematicalBallisticsFactory.h"
|
||||||
#include "EBPhysicalMaterialCustomization.h"
|
#include "EBPhysicalMaterialCustomization.h"
|
||||||
|
#include "EBJsonImportExportTool.h"
|
||||||
#include "PhysicalMaterials/PhysicalMaterial.h"
|
#include "PhysicalMaterials/PhysicalMaterial.h"
|
||||||
|
|
||||||
#define LOCTEXT_NAMESPACE "FEasyBallisticsEditorModule"
|
#define LOCTEXT_NAMESPACE "FEasyBallisticsEditorModule"
|
||||||
@@ -46,10 +47,19 @@ void FEasyBallisticsEditorModule::StartupModule()
|
|||||||
UPhysicalMaterial::StaticClass()->GetFName(),
|
UPhysicalMaterial::StaticClass()->GetFName(),
|
||||||
FOnGetDetailCustomizationInstance::CreateStatic(&FEBPhysicalMaterialCustomization::MakeInstance)
|
FOnGetDetailCustomizationInstance::CreateStatic(&FEBPhysicalMaterialCustomization::MakeInstance)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Register JSON Import/Export tool - delay this until after editor is fully loaded
|
||||||
|
FCoreDelegates::OnFEngineLoopInitComplete.AddLambda([]()
|
||||||
|
{
|
||||||
|
FEBJsonImportExportTool::RegisterMenus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void FEasyBallisticsEditorModule::ShutdownModule()
|
void FEasyBallisticsEditorModule::ShutdownModule()
|
||||||
{
|
{
|
||||||
|
// Unregister JSON Import/Export tool
|
||||||
|
FEBJsonImportExportTool::UnregisterMenus();
|
||||||
|
|
||||||
// Unregister Physical Material customization
|
// Unregister Physical Material customization
|
||||||
if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
|
if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2016 Mookie. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Widgets/SCompoundWidget.h"
|
||||||
|
#include "Widgets/DeclarativeSyntaxSupport.h"
|
||||||
|
#include "EBBulletProperties.h"
|
||||||
|
#include "EBMaterialResponseMap.h"
|
||||||
|
|
||||||
|
class SButton;
|
||||||
|
class STextBlock;
|
||||||
|
|
||||||
|
class EASYBALLISTICSEDITOR_API SEBJsonImportExportTool : public SCompoundWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SLATE_BEGIN_ARGS(SEBJsonImportExportTool) {}
|
||||||
|
SLATE_END_ARGS()
|
||||||
|
|
||||||
|
void Construct(const FArguments& InArgs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Button handlers
|
||||||
|
FReply OnExportBulletPropertiesClicked();
|
||||||
|
FReply OnImportBulletPropertiesClicked();
|
||||||
|
FReply OnExportMaterialResponseClicked();
|
||||||
|
FReply OnImportMaterialResponseClicked();
|
||||||
|
|
||||||
|
// File dialog helpers
|
||||||
|
bool OpenFileDialog(const FString& DialogTitle, const FString& DefaultPath, const FString& FileTypes, FString& OutFilename);
|
||||||
|
bool SaveFileDialog(const FString& DialogTitle, const FString& DefaultPath, const FString& FileTypes, FString& OutFilename);
|
||||||
|
|
||||||
|
// JSON conversion functions
|
||||||
|
TSharedPtr<FJsonObject> BulletPropertiesToJson(const FMathematicalBulletProperties& Properties);
|
||||||
|
bool JsonToBulletProperties(const TSharedPtr<FJsonObject>& JsonObject, FMathematicalBulletProperties& OutProperties);
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> MaterialResponseToJson(const FEBMaterialResponseMapEntry& Entry);
|
||||||
|
bool JsonToMaterialResponse(const TSharedPtr<FJsonObject>& JsonObject, FEBMaterialResponseMapEntry& OutEntry);
|
||||||
|
|
||||||
|
TSharedPtr<FJsonObject> MaterialPropertiesToJson(const FMathematicalMaterialProperties& Properties);
|
||||||
|
bool JsonToMaterialProperties(const TSharedPtr<FJsonObject>& JsonObject, FMathematicalMaterialProperties& OutProperties);
|
||||||
|
|
||||||
|
// Status text
|
||||||
|
TSharedPtr<STextBlock> StatusText;
|
||||||
|
void UpdateStatus(const FString& Message);
|
||||||
|
};
|
||||||
|
|
||||||
|
class EASYBALLISTICSEDITOR_API FEBJsonImportExportTool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterMenus();
|
||||||
|
static void UnregisterMenus();
|
||||||
|
static void OpenImportExportWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TSharedRef<SDockTab> OnSpawnImportExportTab(const class FSpawnTabArgs& SpawnTabArgs);
|
||||||
|
static const FName ImportExportTabName;
|
||||||
|
};
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
# JSON Import/Export Tool
|
||||||
|
|
||||||
|
The EasyBallistics JSON Import/Export Tool provides a powerful interface for importing and exporting ballistic data, enabling easy sharing of configurations, batch processing, and integration with external ballistic databases.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The JSON Import/Export Tool supports:
|
||||||
|
|
||||||
|
- **Bullet Properties**: Export/import mathematical bullet characteristics
|
||||||
|
- **Material Response Maps**: Share material interaction configurations
|
||||||
|
- **Material Properties**: Exchange physical material ballistic data
|
||||||
|
- **Batch Processing**: Handle multiple assets simultaneously
|
||||||
|
- **External Integration**: Connect with ballistic databases and calculators
|
||||||
|
|
||||||
|
## Accessing the Tool
|
||||||
|
|
||||||
|
### Via Editor Menu
|
||||||
|
|
||||||
|
1. **Main Menu**: Window → EasyBallistics → Import/Export Tool
|
||||||
|
2. **Content Browser**: Right-click ballistic assets → EasyBallistics → Export to JSON
|
||||||
|
3. **Toolbar**: Look for the EasyBallistics icon in the main toolbar
|
||||||
|
|
||||||
|
### Via Console Command
|
||||||
|
|
||||||
|
```
|
||||||
|
EasyBallistics.OpenImportExportTool
|
||||||
|
```
|
||||||
|
|
||||||
|
## User Interface
|
||||||
|
|
||||||
|
The tool provides a clean, tab-based interface:
|
||||||
|
|
||||||
|
### Main Tabs
|
||||||
|
|
||||||
|
- **Bullet Properties**: Import/export bullet characteristic data
|
||||||
|
- **Material Response**: Import/export material response configurations
|
||||||
|
- **Material Properties**: Import/export physical material ballistic data
|
||||||
|
- **Batch Operations**: Process multiple files simultaneously
|
||||||
|
|
||||||
|
### Common Controls
|
||||||
|
|
||||||
|
- **Import Button**: Select and import JSON files
|
||||||
|
- **Export Button**: Save current data to JSON
|
||||||
|
- **Validate Button**: Check data integrity
|
||||||
|
- **Clear Button**: Reset current selections
|
||||||
|
|
||||||
|
## Bullet Properties Export/Import
|
||||||
|
|
||||||
|
### Export Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"bulletProperties": {
|
||||||
|
"grainWeight": 55.0,
|
||||||
|
"diameterInches": 0.224,
|
||||||
|
"lengthInches": 0.825,
|
||||||
|
"bulletType": "FullMetalJacket",
|
||||||
|
"bulletMaterial": "CopperJacket",
|
||||||
|
"ballisticCoefficientG1": 0.151,
|
||||||
|
"ballisticCoefficientG7": 0.076,
|
||||||
|
"useG7Model": false,
|
||||||
|
"sectionalDensity": 0.156,
|
||||||
|
"bulletHardness": 15.0,
|
||||||
|
"penetrationEnergyThreshold": 58.0,
|
||||||
|
"expansionVelocityThreshold": 1800.0,
|
||||||
|
"maxExpansionMultiplier": 1.5
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"exportDate": "2024-12-02T10:30:00Z",
|
||||||
|
"pluginVersion": "2.83.0",
|
||||||
|
"description": "5.56x45mm NATO M855 Ball",
|
||||||
|
"source": "Military specification data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Import Process
|
||||||
|
|
||||||
|
1. **Select File**: Click "Import Bullet Properties" and choose JSON file
|
||||||
|
2. **Validation**: Tool automatically validates data structure and ranges
|
||||||
|
3. **Asset Creation**: Creates new UEBBulletPropertiesAsset with imported data
|
||||||
|
4. **Auto-Naming**: Suggests asset name based on bullet characteristics
|
||||||
|
|
||||||
|
### Export Process
|
||||||
|
|
||||||
|
1. **Select Asset**: Choose bullet properties asset in Content Browser
|
||||||
|
2. **Export Options**: Configure export settings (metadata, precision)
|
||||||
|
3. **Save Location**: Choose destination file
|
||||||
|
4. **Format Options**: Include metadata, comments, validation schemas
|
||||||
|
|
||||||
|
## Material Response Maps
|
||||||
|
|
||||||
|
### Export Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"materialResponseMap": {
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"materialName": "Steel",
|
||||||
|
"materialPath": "/Game/Materials/PhysicalMaterials/PM_Steel",
|
||||||
|
"response": {
|
||||||
|
"neverPenetrate": false,
|
||||||
|
"penetrationDepthMultiplier": 0.3,
|
||||||
|
"penetrationNormalization": 0.0,
|
||||||
|
"neverRicochet": false,
|
||||||
|
"ricochetProbabilityMultiplier": 2.0,
|
||||||
|
"ricochetRestitution": 0.8,
|
||||||
|
"ricochetFriction": 0.3,
|
||||||
|
"useMathematicalProperties": true,
|
||||||
|
"mathematicalProperties": {
|
||||||
|
"densityGPerCm3": 7.85,
|
||||||
|
"materialHardness": 200.0,
|
||||||
|
"tensileStrengthMPa": 400.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"exportDate": "2024-12-02T10:30:00Z",
|
||||||
|
"pluginVersion": "2.83.0",
|
||||||
|
"description": "Military vehicle armor response map"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Features
|
||||||
|
|
||||||
|
#### Material Path Resolution
|
||||||
|
- **Automatic Mapping**: Tool resolves Physical Material references
|
||||||
|
- **Path Validation**: Ensures materials exist in project
|
||||||
|
- **Reference Updates**: Updates broken references during import
|
||||||
|
|
||||||
|
#### Batch Import
|
||||||
|
- **Multiple Files**: Import multiple response maps simultaneously
|
||||||
|
- **Merge Options**: Combine entries from multiple files
|
||||||
|
- **Conflict Resolution**: Handle duplicate material entries
|
||||||
|
|
||||||
|
## Material Properties
|
||||||
|
|
||||||
|
### Export Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"materialProperties": {
|
||||||
|
"densityGPerCm3": 7.85,
|
||||||
|
"materialHardness": 200.0,
|
||||||
|
"tensileStrengthMPa": 400.0,
|
||||||
|
"yieldStrengthMPa": 250.0,
|
||||||
|
"elasticModulusGPa": 200.0,
|
||||||
|
"ballisticLimitVelocity": 2000.0,
|
||||||
|
"perforationCoefficient": 1.0,
|
||||||
|
"energyAbsorptionCoefficient": 0.7,
|
||||||
|
"spalling": {
|
||||||
|
"enableMathematicalSpalling": true,
|
||||||
|
"spallStrengthMPa": 150.0,
|
||||||
|
"fragmentationThreshold": 500.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"materialType": "Steel",
|
||||||
|
"standard": "ASTM A36",
|
||||||
|
"description": "Structural steel properties"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Features
|
||||||
|
|
||||||
|
#### Database Integration
|
||||||
|
- **Material Libraries**: Connect to online material databases
|
||||||
|
- **Standard References**: Import from ASTM, ISO, military standards
|
||||||
|
- **Validation**: Cross-reference with known material properties
|
||||||
|
|
||||||
|
#### Smart Suggestions
|
||||||
|
- **Property Estimation**: Estimate missing properties based on material type
|
||||||
|
- **Range Validation**: Warn about unrealistic property values
|
||||||
|
- **Unit Conversion**: Automatic conversion between unit systems
|
||||||
|
|
||||||
|
## Batch Operations
|
||||||
|
|
||||||
|
### Multi-File Processing
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Batch import multiple bullet properties
|
||||||
|
FString ImportDirectory = "C:/BallisticData/Bullets/";
|
||||||
|
TArray<FString> ImportFiles = {
|
||||||
|
"556_NATO.json",
|
||||||
|
"762_NATO.json",
|
||||||
|
"50_BMG.json",
|
||||||
|
"9mm_Para.json"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const FString& File : ImportFiles)
|
||||||
|
{
|
||||||
|
ImportBulletPropertiesFromJSON(ImportDirectory + File);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Export Templates
|
||||||
|
|
||||||
|
#### Military Template
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"template": "military",
|
||||||
|
"standards": ["NATO STANAG 4172", "MIL-STD-398"],
|
||||||
|
"properties": {
|
||||||
|
"grainWeight": "NATO standard weight",
|
||||||
|
"ballisticCoefficient": "Measured at standard conditions"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Hunting Template
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"template": "hunting",
|
||||||
|
"properties": {
|
||||||
|
"expansionVelocityThreshold": "Optimal for game",
|
||||||
|
"penetrationEnergyThreshold": "Ethical hunting energy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation and Error Handling
|
||||||
|
|
||||||
|
### Data Validation
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Validation checks performed during import
|
||||||
|
struct ValidationChecks
|
||||||
|
{
|
||||||
|
bool ValidateRanges; // Check realistic value ranges
|
||||||
|
bool ValidateUnits; // Verify unit consistency
|
||||||
|
bool ValidatePhysics; // Check physics relationships
|
||||||
|
bool ValidateAssets; // Verify asset references exist
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Validation Errors
|
||||||
|
|
||||||
|
| Error | Description | Solution |
|
||||||
|
|-------|-------------|----------|
|
||||||
|
| Invalid Range | Property value outside realistic range | Check data source, adjust values |
|
||||||
|
| Missing Material | Referenced Physical Material not found | Create material or update reference |
|
||||||
|
| Unit Mismatch | Inconsistent unit usage | Convert to consistent unit system |
|
||||||
|
| Physics Violation | Impossible physics relationships | Review and correct property relationships |
|
||||||
|
|
||||||
|
### Error Reporting
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"validation": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"type": "InvalidRange",
|
||||||
|
"property": "grainWeight",
|
||||||
|
"value": -10.0,
|
||||||
|
"message": "Grain weight cannot be negative",
|
||||||
|
"suggestion": "Use positive weight value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"warnings": [
|
||||||
|
{
|
||||||
|
"type": "UncommonValue",
|
||||||
|
"property": "ballisticCoefficientG1",
|
||||||
|
"value": 2.5,
|
||||||
|
"message": "Unusually high ballistic coefficient",
|
||||||
|
"suggestion": "Verify measurement conditions"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration Examples
|
||||||
|
|
||||||
|
### External Database Integration
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Connect to online ballistic database
|
||||||
|
class FExternalBallisticDatabase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Query bullet data from external source
|
||||||
|
TOptional<FMathematicalBulletProperties> QueryBulletData(
|
||||||
|
const FString& Manufacturer,
|
||||||
|
const FString& ProductName,
|
||||||
|
const FString& LoadData
|
||||||
|
);
|
||||||
|
|
||||||
|
// Import material properties from standards database
|
||||||
|
TOptional<FMathematicalMaterialProperties> QueryMaterialProperties(
|
||||||
|
const FString& MaterialStandard,
|
||||||
|
const FString& MaterialGrade
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Format Conversion
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Convert from other ballistic software formats
|
||||||
|
class FFormatConverter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Convert from JBM Ballistics format
|
||||||
|
static FMathematicalBulletProperties ConvertFromJBM(const FString& JBMData);
|
||||||
|
|
||||||
|
// Convert from Applied Ballistics format
|
||||||
|
static FMathematicalBulletProperties ConvertFromAB(const FString& ABData);
|
||||||
|
|
||||||
|
// Convert from Shooter app format
|
||||||
|
static FMathematicalBulletProperties ConvertFromShooter(const FString& ShooterData);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow Integration
|
||||||
|
|
||||||
|
### Asset Pipeline Integration
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Automatically import during asset processing
|
||||||
|
class FAssetPostProcessor : public FAssetPostProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void OnPostProcessAsset(FAssetData& AssetData) override
|
||||||
|
{
|
||||||
|
if (AssetData.AssetClass == UEBBulletPropertiesAsset::StaticClass())
|
||||||
|
{
|
||||||
|
// Auto-validate imported bullet properties
|
||||||
|
ValidateBallisticAsset(AssetData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Version Control Integration
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Track changes for version control
|
||||||
|
struct FAssetChangeRecord
|
||||||
|
{
|
||||||
|
FString AssetPath;
|
||||||
|
FString PreviousVersion;
|
||||||
|
FString NewVersion;
|
||||||
|
TArray<FString> ChangedProperties;
|
||||||
|
FDateTime ChangeTimestamp;
|
||||||
|
FString UserName;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Data Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
BallisticData/
|
||||||
|
├── Bullets/
|
||||||
|
│ ├── Military/
|
||||||
|
│ │ ├── 556_NATO_variants.json
|
||||||
|
│ │ ├── 762_NATO_variants.json
|
||||||
|
│ │ └── 50_BMG_variants.json
|
||||||
|
│ ├── Civilian/
|
||||||
|
│ │ ├── hunting_rifle.json
|
||||||
|
│ │ └── target_pistol.json
|
||||||
|
│ └── Specialty/
|
||||||
|
│ ├── armor_piercing.json
|
||||||
|
│ └── frangible.json
|
||||||
|
├── Materials/
|
||||||
|
│ ├── Metals/
|
||||||
|
│ │ ├── steel_variants.json
|
||||||
|
│ │ └── aluminum_alloys.json
|
||||||
|
│ └── Composites/
|
||||||
|
│ ├── kevlar_aramid.json
|
||||||
|
│ └── ceramic_armor.json
|
||||||
|
└── ResponseMaps/
|
||||||
|
├── military_vehicles.json
|
||||||
|
├── civilian_structures.json
|
||||||
|
└── protective_equipment.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quality Assurance
|
||||||
|
|
||||||
|
1. **Source Documentation**: Always include data source and measurement conditions
|
||||||
|
2. **Version Control**: Track changes and maintain import history
|
||||||
|
3. **Validation Testing**: Test imported data with known scenarios
|
||||||
|
4. **Peer Review**: Have ballistic experts review imported data
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Optimize for large imports
|
||||||
|
class FBatchImportOptimizer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Process imports in background thread
|
||||||
|
void ProcessLargeBatch(const TArray<FString>& FilePaths);
|
||||||
|
|
||||||
|
// Cache validation results
|
||||||
|
void CacheValidationResults();
|
||||||
|
|
||||||
|
// Minimize asset creation overhead
|
||||||
|
void OptimizeAssetCreation();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### Import Failures
|
||||||
|
- **File Format**: Ensure JSON is valid and properly formatted
|
||||||
|
- **Encoding**: Use UTF-8 encoding for international characters
|
||||||
|
- **File Size**: Large files may need batch processing
|
||||||
|
|
||||||
|
#### Export Issues
|
||||||
|
- **Permissions**: Ensure write permissions to destination folder
|
||||||
|
- **Path Length**: Avoid extremely long file paths
|
||||||
|
- **Special Characters**: Be careful with special characters in filenames
|
||||||
|
|
||||||
|
#### Validation Problems
|
||||||
|
- **Material References**: Ensure Physical Materials exist in project
|
||||||
|
- **Value Ranges**: Check that values are within realistic ranges
|
||||||
|
- **Unit Consistency**: Maintain consistent unit systems
|
||||||
|
|
||||||
|
### Support Resources
|
||||||
|
|
||||||
|
- **Documentation**: Complete JSON schema documentation
|
||||||
|
- **Examples**: Sample JSON files for common scenarios
|
||||||
|
- **Validation Tools**: Online validators for JSON format
|
||||||
|
- **Community**: Forums and Discord for troubleshooting help
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Editor Integration](editor-integration) - General editor tools and workflows
|
||||||
|
- [Material Response System](../core-concepts/overview#material-system) - Understanding material interactions
|
||||||
|
- [Asset Organization](../getting-started/installation#asset-organization) - Best practices for asset management
|
||||||
|
- [API Reference](../api/overview) - Programming interfaces for import/export
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*The JSON Import/Export Tool enables seamless integration with external ballistic databases and facilitates easy sharing of ballistic configurations across projects and teams.*
|
||||||
@@ -0,0 +1,578 @@
|
|||||||
|
# Material Properties API Reference
|
||||||
|
|
||||||
|
Complete reference for material properties assets and the material ballistics system in EasyBallistics.
|
||||||
|
|
||||||
|
## UEBMaterialPropertiesAsset
|
||||||
|
|
||||||
|
### Class Overview
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
UCLASS(BlueprintType, BlueprintSpawnableComponent)
|
||||||
|
class EASYBALLISTICS_API UEBMaterialPropertiesAsset : public UDataAsset
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material Properties")
|
||||||
|
FMathematicalMaterialProperties MaterialProperties;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `UEBMaterialPropertiesAsset` is a data asset that stores comprehensive physical and ballistic properties for materials used in mathematical ballistics calculations.
|
||||||
|
|
||||||
|
## FMathematicalMaterialProperties
|
||||||
|
|
||||||
|
### Structure Definition
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct EASYBALLISTICS_API FMathematicalMaterialProperties
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
// Material Properties
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material Properties")
|
||||||
|
float DensityGPerCm3 = 7.85f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material Properties")
|
||||||
|
float MaterialHardness = 200.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material Properties")
|
||||||
|
float TensileStrengthMPa = 400.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material Properties")
|
||||||
|
float YieldStrengthMPa = 250.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Material Properties")
|
||||||
|
float ElasticModulusGPa = 200.0f;
|
||||||
|
|
||||||
|
// Ballistic Properties
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistic Properties")
|
||||||
|
float BallisticLimitVelocity = 2000.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistic Properties")
|
||||||
|
float PerforationCoefficient = 1.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistic Properties")
|
||||||
|
float EnergyAbsorptionCoefficient = 0.7f;
|
||||||
|
|
||||||
|
// Spalling Properties
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties")
|
||||||
|
bool EnableMathematicalSpalling = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties")
|
||||||
|
float SpallStrengthMPa = 150.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spalling Properties")
|
||||||
|
float FragmentationThreshold = 500.0f;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Property Descriptions
|
||||||
|
|
||||||
|
#### Material Properties
|
||||||
|
|
||||||
|
| Property | Type | Default | Description | Typical Range |
|
||||||
|
|----------|------|---------|-------------|---------------|
|
||||||
|
| `DensityGPerCm3` | `float` | `7.85` | Material density in grams per cubic centimeter | 0.1 - 20.0 |
|
||||||
|
| `MaterialHardness` | `float` | `200.0` | Brinell hardness (HB) | 10 - 800 |
|
||||||
|
| `TensileStrengthMPa` | `float` | `400.0` | Ultimate tensile strength in megapascals | 1 - 5000 |
|
||||||
|
| `YieldStrengthMPa` | `float` | `250.0` | Yield strength in megapascals | 1 - 3000 |
|
||||||
|
| `ElasticModulusGPa` | `float` | `200.0` | Modulus of elasticity in gigapascals | 0.01 - 1000 |
|
||||||
|
|
||||||
|
#### Ballistic Properties
|
||||||
|
|
||||||
|
| Property | Type | Default | Description | Typical Range |
|
||||||
|
|----------|------|---------|-------------|---------------|
|
||||||
|
| `BallisticLimitVelocity` | `float` | `2000.0` | Velocity required for 50% perforation probability (fps) | 100 - 10000 |
|
||||||
|
| `PerforationCoefficient` | `float` | `1.0` | Multiplier for perforation calculations | 0.1 - 5.0 |
|
||||||
|
| `EnergyAbsorptionCoefficient` | `float` | `0.7` | Fraction of kinetic energy absorbed on impact | 0.1 - 1.0 |
|
||||||
|
|
||||||
|
#### Spalling Properties
|
||||||
|
|
||||||
|
| Property | Type | Default | Description | Typical Range |
|
||||||
|
|----------|------|---------|-------------|---------------|
|
||||||
|
| `EnableMathematicalSpalling` | `bool` | `false` | Enable physics-based spalling calculations | - |
|
||||||
|
| `SpallStrengthMPa` | `float` | `150.0` | Material resistance to spalling in megapascals | 10 - 1000 |
|
||||||
|
| `FragmentationThreshold` | `float` | `500.0` | Energy threshold for fragmentation (Joules) | 10 - 10000 |
|
||||||
|
|
||||||
|
## Material Presets
|
||||||
|
|
||||||
|
### Common Material Configurations
|
||||||
|
|
||||||
|
#### Steel (ASTM A36)
|
||||||
|
```cpp
|
||||||
|
FMathematicalMaterialProperties Steel;
|
||||||
|
Steel.DensityGPerCm3 = 7.85f;
|
||||||
|
Steel.MaterialHardness = 200.0f;
|
||||||
|
Steel.TensileStrengthMPa = 400.0f;
|
||||||
|
Steel.YieldStrengthMPa = 250.0f;
|
||||||
|
Steel.ElasticModulusGPa = 200.0f;
|
||||||
|
Steel.BallisticLimitVelocity = 2000.0f;
|
||||||
|
Steel.EnableMathematicalSpalling = true;
|
||||||
|
Steel.SpallStrengthMPa = 150.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Aluminum (6061-T6)
|
||||||
|
```cpp
|
||||||
|
FMathematicalMaterialProperties Aluminum;
|
||||||
|
Aluminum.DensityGPerCm3 = 2.70f;
|
||||||
|
Aluminum.MaterialHardness = 95.0f;
|
||||||
|
Aluminum.TensileStrengthMPa = 310.0f;
|
||||||
|
Aluminum.YieldStrengthMPa = 276.0f;
|
||||||
|
Aluminum.ElasticModulusGPa = 68.9f;
|
||||||
|
Aluminum.BallisticLimitVelocity = 1500.0f;
|
||||||
|
Aluminum.EnableMathematicalSpalling = true;
|
||||||
|
Aluminum.SpallStrengthMPa = 100.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Concrete (Standard)
|
||||||
|
```cpp
|
||||||
|
FMathematicalMaterialProperties Concrete;
|
||||||
|
Concrete.DensityGPerCm3 = 2.40f;
|
||||||
|
Concrete.MaterialHardness = 20.0f;
|
||||||
|
Concrete.TensileStrengthMPa = 4.0f;
|
||||||
|
Concrete.YieldStrengthMPa = 25.0f;
|
||||||
|
Concrete.ElasticModulusGPa = 30.0f;
|
||||||
|
Concrete.BallisticLimitVelocity = 800.0f;
|
||||||
|
Concrete.EnableMathematicalSpalling = true;
|
||||||
|
Concrete.SpallStrengthMPa = 50.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kevlar (Fabric)
|
||||||
|
```cpp
|
||||||
|
FMathematicalMaterialProperties Kevlar;
|
||||||
|
Kevlar.DensityGPerCm3 = 1.44f;
|
||||||
|
Kevlar.MaterialHardness = 50.0f;
|
||||||
|
Kevlar.TensileStrengthMPa = 3620.0f;
|
||||||
|
Kevlar.YieldStrengthMPa = 3500.0f;
|
||||||
|
Kevlar.ElasticModulusGPa = 130.0f;
|
||||||
|
Kevlar.BallisticLimitVelocity = 1200.0f;
|
||||||
|
Kevlar.EnergyAbsorptionCoefficient = 0.9f;
|
||||||
|
Kevlar.EnableMathematicalSpalling = false;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Wood (Oak)
|
||||||
|
```cpp
|
||||||
|
FMathematicalMaterialProperties Wood;
|
||||||
|
Wood.DensityGPerCm3 = 0.75f;
|
||||||
|
Wood.MaterialHardness = 10.0f;
|
||||||
|
Wood.TensileStrengthMPa = 90.0f;
|
||||||
|
Wood.YieldStrengthMPa = 50.0f;
|
||||||
|
Wood.ElasticModulusGPa = 12.0f;
|
||||||
|
Wood.BallisticLimitVelocity = 400.0f;
|
||||||
|
Wood.EnergyAbsorptionCoefficient = 0.8f;
|
||||||
|
Wood.EnableMathematicalSpalling = false;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Utility Functions
|
||||||
|
|
||||||
|
### Material Property Calculations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Calculate material toughness
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static float CalculateMaterialToughness(const FMathematicalMaterialProperties& Properties)
|
||||||
|
{
|
||||||
|
// Toughness approximation: (UTS + YS) / 2
|
||||||
|
return (Properties.TensileStrengthMPa + Properties.YieldStrengthMPa) / 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate wave velocity in material
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static float CalculateWaveVelocity(const FMathematicalMaterialProperties& Properties)
|
||||||
|
{
|
||||||
|
// c = sqrt(E / ρ) where E is elastic modulus, ρ is density
|
||||||
|
float ElasticModulusPa = Properties.ElasticModulusGPa * 1e9f;
|
||||||
|
float DensityKgPerM3 = Properties.DensityGPerCm3 * 1000.0f;
|
||||||
|
return FMath::Sqrt(ElasticModulusPa / DensityKgPerM3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate ballistic limit from material properties
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static float EstimateBallisticLimit(
|
||||||
|
const FMathematicalMaterialProperties& MaterialProps,
|
||||||
|
const FMathematicalBulletProperties& BulletProps,
|
||||||
|
float ThicknessCM
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Simplified ballistic limit estimation
|
||||||
|
float MaterialResistance = MaterialProps.TensileStrengthMPa * MaterialProps.DensityGPerCm3;
|
||||||
|
float BulletPenetrator = BulletProps.GetSectionalDensity() * BulletProps.BulletHardness;
|
||||||
|
|
||||||
|
return FMath::Sqrt(MaterialResistance * ThicknessCM / BulletPenetrator) * 100.0f;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Smart Material Recognition
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Automatically configure material properties based on name
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static FMathematicalMaterialProperties GetMaterialPreset(const FString& MaterialName)
|
||||||
|
{
|
||||||
|
FString LowerName = MaterialName.ToLower();
|
||||||
|
|
||||||
|
if (LowerName.Contains("steel"))
|
||||||
|
{
|
||||||
|
return GetSteelProperties();
|
||||||
|
}
|
||||||
|
else if (LowerName.Contains("aluminum") || LowerName.Contains("aluminium"))
|
||||||
|
{
|
||||||
|
return GetAluminumProperties();
|
||||||
|
}
|
||||||
|
else if (LowerName.Contains("concrete"))
|
||||||
|
{
|
||||||
|
return GetConcreteProperties();
|
||||||
|
}
|
||||||
|
else if (LowerName.Contains("kevlar") || LowerName.Contains("aramid"))
|
||||||
|
{
|
||||||
|
return GetKevlarProperties();
|
||||||
|
}
|
||||||
|
else if (LowerName.Contains("wood") || LowerName.Contains("timber"))
|
||||||
|
{
|
||||||
|
return GetWoodProperties();
|
||||||
|
}
|
||||||
|
else if (LowerName.Contains("ceramic"))
|
||||||
|
{
|
||||||
|
return GetCeramicProperties();
|
||||||
|
}
|
||||||
|
else if (LowerName.Contains("titanium"))
|
||||||
|
{
|
||||||
|
return GetTitaniumProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to steel if unknown
|
||||||
|
return GetSteelProperties();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Physical Material Integration
|
||||||
|
|
||||||
|
### Enhanced Physical Material Properties
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Extension of UPhysicalMaterial with ballistic properties
|
||||||
|
UCLASS()
|
||||||
|
class EASYBALLISTICS_API UEBPhysicalMaterial : public UPhysicalMaterial
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Ballistic properties for this physical material
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistics")
|
||||||
|
UEBMaterialPropertiesAsset* BallisticProperties;
|
||||||
|
|
||||||
|
// Auto-generate properties based on material name
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistics")
|
||||||
|
bool AutoConfigureFromName = true;
|
||||||
|
|
||||||
|
// Override for mathematical calculations
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ballistics")
|
||||||
|
bool UseMathematicalProperties = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get effective ballistic properties (from asset or auto-generated)
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Ballistics")
|
||||||
|
FMathematicalMaterialProperties GetEffectiveProperties() const;
|
||||||
|
|
||||||
|
// Auto-configure properties from material name
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Ballistics")
|
||||||
|
void AutoConfigureProperties();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Material Editor Integration
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Custom details panel for Physical Material ballistic properties
|
||||||
|
class EASYBALLISTICSEDITOR_API FEBPhysicalMaterialCustomization : public IDetailCustomization
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Add ballistic properties section
|
||||||
|
void AddBallisticPropertiesSection(IDetailLayoutBuilder& DetailBuilder);
|
||||||
|
|
||||||
|
// Handle auto-configuration
|
||||||
|
FReply OnAutoConfigureClicked();
|
||||||
|
|
||||||
|
// Handle asset creation
|
||||||
|
FReply OnCreateBallisticPropertiesClicked();
|
||||||
|
|
||||||
|
// Validate property ranges
|
||||||
|
void ValidatePropertyRanges();
|
||||||
|
|
||||||
|
TWeakObjectPtr<UPhysicalMaterial> PhysicalMaterial;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Material Behaviors
|
||||||
|
|
||||||
|
### Temperature Effects
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Temperature-dependent material properties
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FTemperatureDependentProperties
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
float ReferenceTemperatureCelsius = 20.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
float StrengthTemperatureCoefficient = -0.001f; // per degree C
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
float HardnessTemperatureCoefficient = -0.002f; // per degree C
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate temperature-adjusted properties
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static FMathematicalMaterialProperties AdjustForTemperature(
|
||||||
|
const FMathematicalMaterialProperties& BaseProperties,
|
||||||
|
const FTemperatureDependentProperties& TempDependence,
|
||||||
|
float CurrentTemperatureCelsius
|
||||||
|
)
|
||||||
|
{
|
||||||
|
FMathematicalMaterialProperties AdjustedProperties = BaseProperties;
|
||||||
|
float TempDelta = CurrentTemperatureCelsius - TempDependence.ReferenceTemperatureCelsius;
|
||||||
|
|
||||||
|
// Adjust strength properties
|
||||||
|
float StrengthMultiplier = 1.0f + (TempDependence.StrengthTemperatureCoefficient * TempDelta);
|
||||||
|
AdjustedProperties.TensileStrengthMPa *= StrengthMultiplier;
|
||||||
|
AdjustedProperties.YieldStrengthMPa *= StrengthMultiplier;
|
||||||
|
|
||||||
|
// Adjust hardness
|
||||||
|
float HardnessMultiplier = 1.0f + (TempDependence.HardnessTemperatureCoefficient * TempDelta);
|
||||||
|
AdjustedProperties.MaterialHardness *= HardnessMultiplier;
|
||||||
|
|
||||||
|
return AdjustedProperties;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Layered Materials
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Multi-layer material system
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FLayeredMaterialProperties
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
TArray<FMaterialLayer> Layers;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
bool AccountForInterfaceEffects = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FMaterialLayer
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
FMathematicalMaterialProperties Properties;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
float ThicknessCM = 1.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
|
float AdhesionStrengthMPa = 50.0f;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Material Property Caching
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Cache material properties for performance
|
||||||
|
class EASYBALLISTICS_API FMaterialPropertyCache
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct FCachedMaterialProperties
|
||||||
|
{
|
||||||
|
FMathematicalMaterialProperties Properties;
|
||||||
|
float CacheTime;
|
||||||
|
bool bValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
TMap<TWeakObjectPtr<UPhysicalMaterial>, FCachedMaterialProperties> Cache;
|
||||||
|
float CacheValidityTime = 10.0f; // seconds
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get cached properties or calculate if needed
|
||||||
|
FMathematicalMaterialProperties GetProperties(UPhysicalMaterial* Material);
|
||||||
|
|
||||||
|
// Clear expired cache entries
|
||||||
|
void CleanCache();
|
||||||
|
|
||||||
|
// Force refresh of specific material
|
||||||
|
void InvalidateMaterial(UPhysicalMaterial* Material);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### LOD System for Material Calculations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Simplify material calculations based on importance
|
||||||
|
enum class EMaterialCalculationLOD : uint8
|
||||||
|
{
|
||||||
|
High, // Full calculations with all properties
|
||||||
|
Medium, // Essential properties only
|
||||||
|
Low, // Basic approximations
|
||||||
|
Disabled // No material effects
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get appropriate LOD based on distance and settings
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static EMaterialCalculationLOD GetMaterialLOD(
|
||||||
|
float DistanceToPlayer,
|
||||||
|
bool bIsPlayerWeapon,
|
||||||
|
bool bIsImportantActor
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (bIsPlayerWeapon || bIsImportantActor)
|
||||||
|
{
|
||||||
|
return EMaterialCalculationLOD::High;
|
||||||
|
}
|
||||||
|
else if (DistanceToPlayer < 1000.0f)
|
||||||
|
{
|
||||||
|
return EMaterialCalculationLOD::Medium;
|
||||||
|
}
|
||||||
|
else if (DistanceToPlayer < 5000.0f)
|
||||||
|
{
|
||||||
|
return EMaterialCalculationLOD::Low;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return EMaterialCalculationLOD::Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation and Testing
|
||||||
|
|
||||||
|
### Property Validation
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Validate material properties for realism
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Material Properties")
|
||||||
|
static TArray<FString> ValidateMaterialProperties(const FMathematicalMaterialProperties& Properties)
|
||||||
|
{
|
||||||
|
TArray<FString> ValidationErrors;
|
||||||
|
|
||||||
|
// Check density range
|
||||||
|
if (Properties.DensityGPerCm3 < 0.01f || Properties.DensityGPerCm3 > 30.0f)
|
||||||
|
{
|
||||||
|
ValidationErrors.Add("Density outside realistic range (0.01 - 30.0 g/cm³)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check strength relationships
|
||||||
|
if (Properties.YieldStrengthMPa > Properties.TensileStrengthMPa)
|
||||||
|
{
|
||||||
|
ValidationErrors.Add("Yield strength cannot exceed tensile strength");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check hardness correlation with strength
|
||||||
|
float ExpectedHardness = Properties.TensileStrengthMPa / 3.0f; // Rough correlation
|
||||||
|
if (FMath::Abs(Properties.MaterialHardness - ExpectedHardness) > ExpectedHardness * 0.5f)
|
||||||
|
{
|
||||||
|
ValidationErrors.Add("Hardness and tensile strength correlation seems unrealistic");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationErrors;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Scenarios
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Standard test scenarios for material validation
|
||||||
|
namespace MaterialTestScenarios
|
||||||
|
{
|
||||||
|
// NIJ Level IIIA test (9mm @ 1400 fps)
|
||||||
|
struct FNIJLevel3A
|
||||||
|
{
|
||||||
|
static constexpr float TestVelocityFPS = 1400.0f;
|
||||||
|
static constexpr float BulletMassGrains = 124.0f;
|
||||||
|
static constexpr float BulletDiameterInches = 0.355f;
|
||||||
|
};
|
||||||
|
|
||||||
|
// .30-06 AP test (armor piercing)
|
||||||
|
struct F30_06_AP
|
||||||
|
{
|
||||||
|
static constexpr float TestVelocityFPS = 2880.0f;
|
||||||
|
static constexpr float BulletMassGrains = 165.0f;
|
||||||
|
static constexpr float BulletDiameterInches = 0.308f;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Basic Material Setup
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Create and configure a steel material
|
||||||
|
UEBMaterialPropertiesAsset* SteelProperties = NewObject<UEBMaterialPropertiesAsset>();
|
||||||
|
SteelProperties->MaterialProperties = FMathematicalMaterialProperties::GetSteelProperties();
|
||||||
|
|
||||||
|
// Assign to Physical Material
|
||||||
|
UPhysicalMaterial* PhysMat = NewObject<UPhysicalMaterial>();
|
||||||
|
PhysMat->BallisticProperties = SteelProperties;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Material Interaction
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Calculate penetration through layered armor
|
||||||
|
float CalculateLayeredPenetration(
|
||||||
|
const FMathematicalBulletProperties& Bullet,
|
||||||
|
const TArray<FMaterialLayer>& Layers,
|
||||||
|
float InitialVelocityMPS
|
||||||
|
)
|
||||||
|
{
|
||||||
|
float CurrentVelocity = InitialVelocityMPS;
|
||||||
|
float TotalPenetration = 0.0f;
|
||||||
|
|
||||||
|
for (const FMaterialLayer& Layer : Layers)
|
||||||
|
{
|
||||||
|
float LayerPenetration = UEBMathematicalBallistics::CalculatePenetrationDepth(
|
||||||
|
Bullet, Layer.Properties, CurrentVelocity, 0.0f
|
||||||
|
);
|
||||||
|
|
||||||
|
TotalPenetration += LayerPenetration;
|
||||||
|
|
||||||
|
if (LayerPenetration >= Layer.ThicknessCM)
|
||||||
|
{
|
||||||
|
// Calculate residual velocity
|
||||||
|
CurrentVelocity = UEBMathematicalBallistics::CalculateResidualVelocity(
|
||||||
|
Bullet, Layer.Properties, CurrentVelocity, Layer.ThicknessCM
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Bullet stopped in this layer
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TotalPenetration;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Mathematical Ballistics](../core-concepts/mathematical-ballistics) - Physics-based calculations
|
||||||
|
- [Material Response Maps](material-response-reference) - Gameplay material responses
|
||||||
|
- [Physical Material Integration](../advanced/editor-integration#physical-material-integration) - Editor workflow
|
||||||
|
- [Ballistic Impact Component](ballistic-impact-reference) - Impact handling system
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Material properties form the foundation of realistic ballistic calculations, enabling accurate simulation of projectile-material interactions.*
|
||||||
@@ -0,0 +1,497 @@
|
|||||||
|
# Material Setup Guide
|
||||||
|
|
||||||
|
This comprehensive tutorial covers setting up realistic material interactions in EasyBallistics, from basic material properties to advanced layered armor systems.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
EasyBallistics provides two approaches to material interactions:
|
||||||
|
|
||||||
|
- **Artistic Mode**: Designer-friendly multipliers and artistic values
|
||||||
|
- **Mathematical Mode**: Physics-based calculations using real material properties
|
||||||
|
|
||||||
|
This guide covers both approaches and shows you how to create realistic material responses.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- EasyBallistics plugin enabled and configured
|
||||||
|
- Basic understanding of Physical Materials in Unreal Engine
|
||||||
|
- Access to the Content Browser and Material Editor
|
||||||
|
|
||||||
|
## Part 1: Basic Material Setup
|
||||||
|
|
||||||
|
### Step 1: Create Physical Materials
|
||||||
|
|
||||||
|
First, let's create the basic materials your projectiles will interact with.
|
||||||
|
|
||||||
|
1. **Create Steel Material**
|
||||||
|
- Content Browser → Right-click → Physics → Physical Material
|
||||||
|
- Name it `PM_Steel`
|
||||||
|
- Set basic physics properties (friction, restitution) as needed
|
||||||
|
|
||||||
|
2. **Create Wood Material**
|
||||||
|
- Create another Physical Material: `PM_Wood`
|
||||||
|
- Configure appropriate friction/restitution values
|
||||||
|
|
||||||
|
3. **Create Concrete Material**
|
||||||
|
- Create: `PM_Concrete`
|
||||||
|
- Set surface properties for concrete
|
||||||
|
|
||||||
|
### Step 2: Configure Ballistic Properties
|
||||||
|
|
||||||
|
#### Option A: Automatic Configuration (Recommended)
|
||||||
|
|
||||||
|
1. **Open Physical Material**
|
||||||
|
- Double-click `PM_Steel` to open the editor
|
||||||
|
- Look for the **Ballistic Properties** section
|
||||||
|
|
||||||
|
2. **Auto-Configure**
|
||||||
|
- Click **"Auto-Configure from Name"**
|
||||||
|
- The system automatically detects "Steel" and applies appropriate properties
|
||||||
|
- Review the generated values
|
||||||
|
|
||||||
|
#### Option B: Manual Configuration
|
||||||
|
|
||||||
|
1. **Create Material Properties Asset**
|
||||||
|
- Content Browser → Right-click → Ballistics → Material Properties
|
||||||
|
- Name it `MP_Steel_Properties`
|
||||||
|
|
||||||
|
2. **Configure Properties**
|
||||||
|
```yaml
|
||||||
|
Material Properties:
|
||||||
|
Density g/cm³: 7.85
|
||||||
|
Material Hardness: 200.0
|
||||||
|
Tensile Strength MPa: 400.0
|
||||||
|
Yield Strength MPa: 250.0
|
||||||
|
|
||||||
|
Ballistic Properties:
|
||||||
|
Ballistic Limit Velocity: 2000.0
|
||||||
|
Perforation Coefficient: 1.0
|
||||||
|
Energy Absorption: 0.7
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Assign to Physical Material**
|
||||||
|
- In `PM_Steel`, set **Ballistic Properties** to `MP_Steel_Properties`
|
||||||
|
|
||||||
|
### Step 3: Create Material Response Map
|
||||||
|
|
||||||
|
The Material Response Map defines gameplay rules for how bullets interact with materials.
|
||||||
|
|
||||||
|
1. **Create Response Map**
|
||||||
|
- Content Browser → Right-click → Ballistics → Material Response Map
|
||||||
|
- Name it `MRM_Default`
|
||||||
|
|
||||||
|
2. **Add Material Entries**
|
||||||
|
- Click **"Add Material"**
|
||||||
|
- Select `PM_Steel` from the dropdown
|
||||||
|
- Configure response parameters:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Steel Entry:
|
||||||
|
Never Penetrate: false
|
||||||
|
Penetration Depth Multiplier: 0.3
|
||||||
|
Never Ricochet: false
|
||||||
|
Ricochet Probability Multiplier: 2.0
|
||||||
|
Use Mathematical Properties: true
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Add Wood and Concrete**
|
||||||
|
- Add entries for `PM_Wood` and `PM_Concrete`
|
||||||
|
- Wood: Higher penetration multiplier (1.5), lower ricochet (0.2)
|
||||||
|
- Concrete: Medium penetration (0.8), medium ricochet (1.0)
|
||||||
|
|
||||||
|
## Part 2: Mathematical vs Artistic Setup
|
||||||
|
|
||||||
|
### Understanding the Modes
|
||||||
|
|
||||||
|
#### Artistic Mode
|
||||||
|
Best for gameplay-focused scenarios where you want direct control over penetration and ricochet behavior.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Artistic mode bullet configuration
|
||||||
|
Bullet->UseMathematicalPhysics = false;
|
||||||
|
Bullet->Mass = 0.005f; // 5 grams
|
||||||
|
Bullet->Diameter = 0.556f; // cm
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Mathematical Mode
|
||||||
|
Best for realistic simulations using real-world ballistic formulas.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Mathematical mode bullet configuration
|
||||||
|
Bullet->UseMathematicalPhysics = true;
|
||||||
|
Bullet->BulletPropertiesAsset = My556Properties;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting Up Mathematical Mode
|
||||||
|
|
||||||
|
1. **Create Bullet Properties**
|
||||||
|
- Content Browser → Ballistics → Bullet Properties
|
||||||
|
- Name: `BP_556_NATO_Mathematical`
|
||||||
|
|
||||||
|
2. **Configure Mathematical Properties**
|
||||||
|
```yaml
|
||||||
|
Basic Properties:
|
||||||
|
Grain Weight: 55.0
|
||||||
|
Diameter Inches: 0.224
|
||||||
|
Length Inches: 0.825
|
||||||
|
Bullet Type: Full Metal Jacket
|
||||||
|
|
||||||
|
Ballistics:
|
||||||
|
Ballistic Coefficient G1: 0.151
|
||||||
|
Use G7 Model: false
|
||||||
|
|
||||||
|
Penetration:
|
||||||
|
Bullet Hardness: 15.0
|
||||||
|
Penetration Energy Threshold: 58.0
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Enable Mathematical Mode**
|
||||||
|
- On your bullet class: `Use Mathematical Physics = true`
|
||||||
|
- Assign the bullet properties asset
|
||||||
|
|
||||||
|
### Setting Up Artistic Mode
|
||||||
|
|
||||||
|
1. **Configure Artistic Properties**
|
||||||
|
- On your bullet class: `Use Mathematical Physics = false`
|
||||||
|
- Set artistic properties:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Artistic Properties:
|
||||||
|
Mass: 0.0035 # kg (55 grain bullet)
|
||||||
|
Diameter: 0.556 # cm
|
||||||
|
Form Factor: 1.0
|
||||||
|
|
||||||
|
Artistic Impact:
|
||||||
|
Base Penetration: 5.0 # cm
|
||||||
|
Base Ricochet Angle: 30.0 # degrees
|
||||||
|
Energy Loss Per CM: 0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Fine-tune Response Map**
|
||||||
|
- Adjust multipliers for desired gameplay feel
|
||||||
|
- Test and iterate penetration values
|
||||||
|
|
||||||
|
## Part 3: Advanced Material Configurations
|
||||||
|
|
||||||
|
### Armor Systems
|
||||||
|
|
||||||
|
#### Basic Armor Plate
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Steel armor configuration
|
||||||
|
FMathematicalMaterialProperties ArmorSteel;
|
||||||
|
ArmorSteel.DensityGPerCm3 = 7.85f;
|
||||||
|
ArmorSteel.MaterialHardness = 400.0f; // Hardened steel
|
||||||
|
ArmorSteel.TensileStrengthMPa = 800.0f; // High strength
|
||||||
|
ArmorSteel.BallisticLimitVelocity = 2500.0f; // Resistant to penetration
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Ceramic Armor
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Ceramic armor configuration
|
||||||
|
FMathematicalMaterialProperties Ceramic;
|
||||||
|
Ceramic.DensityGPerCm3 = 3.8f; // Alumina ceramic
|
||||||
|
Ceramic.MaterialHardness = 1500.0f; // Very hard
|
||||||
|
Ceramic.TensileStrengthMPa = 300.0f; // Brittle
|
||||||
|
Ceramic.EnableMathematicalSpalling = true;
|
||||||
|
Ceramic.SpallStrengthMPa = 50.0f; // Fragments easily
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Composite Armor (Kevlar)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Kevlar configuration
|
||||||
|
FMathematicalMaterialProperties Kevlar;
|
||||||
|
Kevlar.DensityGPerCm3 = 1.44f;
|
||||||
|
Kevlar.MaterialHardness = 50.0f; // Soft but strong
|
||||||
|
Kevlar.TensileStrengthMPa = 3620.0f; // Extremely high tensile strength
|
||||||
|
Kevlar.EnergyAbsorptionCoefficient = 0.95f; // Excellent energy absorption
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environmental Materials
|
||||||
|
|
||||||
|
#### Bulletproof Glass
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Bulletproof glass setup
|
||||||
|
FMathematicalMaterialProperties BulletproofGlass;
|
||||||
|
BulletproofGlass.DensityGPerCm3 = 2.5f;
|
||||||
|
BulletproofGlass.MaterialHardness = 600.0f; // Hard surface
|
||||||
|
BulletproofGlass.TensileStrengthMPa = 50.0f; // Brittle under tension
|
||||||
|
BulletproofGlass.BallisticLimitVelocity = 1200.0f;
|
||||||
|
BulletproofGlass.EnableMathematicalSpalling = true; // Glass fragments
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Sandbags
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Sandbag fortification
|
||||||
|
FMathematicalMaterialProperties Sand;
|
||||||
|
Sand.DensityGPerCm3 = 1.6f;
|
||||||
|
Sand.MaterialHardness = 5.0f; // Very soft
|
||||||
|
Sand.TensileStrengthMPa = 0.1f; // No structural strength
|
||||||
|
Sand.EnergyAbsorptionCoefficient = 0.9f; // Excellent energy absorption
|
||||||
|
Sand.BallisticLimitVelocity = 300.0f; // Easily penetrated but absorbs energy
|
||||||
|
```
|
||||||
|
|
||||||
|
## Part 4: Spalling Configuration
|
||||||
|
|
||||||
|
Spalling adds realism by creating secondary fragments when bullets impact hard materials.
|
||||||
|
|
||||||
|
### Enable Spalling
|
||||||
|
|
||||||
|
1. **Material Response Map Setup**
|
||||||
|
```yaml
|
||||||
|
Steel Entry:
|
||||||
|
Enable Spalling: true
|
||||||
|
Spall Velocity Threshold: 1500.0 # fps
|
||||||
|
Spall Fragment Count: 8
|
||||||
|
Spall Fragment Class: BP_SpallFragment
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Bullet Configuration**
|
||||||
|
```cpp
|
||||||
|
// Enable spalling on bullets
|
||||||
|
Bullet->EnableSpalling = true;
|
||||||
|
Bullet->UseNewImpactSystem = true; // Required for spalling
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mathematical Spalling
|
||||||
|
|
||||||
|
For realistic spalling behavior, enable mathematical calculations:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Material properties for mathematical spalling
|
||||||
|
MaterialProperties.EnableMathematicalSpalling = true;
|
||||||
|
MaterialProperties.SpallStrengthMPa = 150.0f; // Steel spall strength
|
||||||
|
MaterialProperties.FragmentationThreshold = 500.0f; // Joules
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spalling Effects
|
||||||
|
|
||||||
|
1. **Create Spall Fragment Bullet**
|
||||||
|
- Duplicate your main bullet class
|
||||||
|
- Name it `BP_SpallFragment`
|
||||||
|
- Reduce mass and size:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Spall Fragment Properties:
|
||||||
|
Mass: 0.001 # kg (much lighter)
|
||||||
|
Diameter: 0.2 # cm (small fragments)
|
||||||
|
Enable Spalling: false # Fragments don't create more fragments
|
||||||
|
Lifetime: 2.0 # seconds (short-lived)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Configure Fragment Behavior**
|
||||||
|
```cpp
|
||||||
|
// Spall fragments should be less stable
|
||||||
|
Fragment->DragCoefficient = 2.0f; // Higher drag
|
||||||
|
Fragment->EnablePooling = true; // Pool for performance
|
||||||
|
```
|
||||||
|
|
||||||
|
## Part 5: Performance Optimization
|
||||||
|
|
||||||
|
### Material Response Optimization
|
||||||
|
|
||||||
|
1. **Group Similar Materials**
|
||||||
|
```yaml
|
||||||
|
# Group materials by behavior type
|
||||||
|
Metal Materials: [Steel, Aluminum, Titanium]
|
||||||
|
Soft Materials: [Wood, Fabric, Foam]
|
||||||
|
Brittle Materials: [Concrete, Ceramic, Glass]
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Use Material Inheritance**
|
||||||
|
```cpp
|
||||||
|
// Base metal properties
|
||||||
|
FMathematicalMaterialProperties BaseMetal = GetSteelProperties();
|
||||||
|
|
||||||
|
// Aluminum inherits from steel with modifications
|
||||||
|
FMathematicalMaterialProperties Aluminum = BaseMetal;
|
||||||
|
Aluminum.DensityGPerCm3 = 2.70f;
|
||||||
|
Aluminum.MaterialHardness = 95.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
### LOD System
|
||||||
|
|
||||||
|
1. **Distance-Based Quality**
|
||||||
|
```cpp
|
||||||
|
// Reduce spalling for distant impacts
|
||||||
|
float DistanceToPlayer = GetDistanceToPlayer();
|
||||||
|
if (DistanceToPlayer > 1000.0f)
|
||||||
|
{
|
||||||
|
ResponseEntry.SpallFragmentCount = 3; // Reduced fragments
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResponseEntry.SpallFragmentCount = 8; // Full fragments
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Importance-Based Processing**
|
||||||
|
```cpp
|
||||||
|
// High detail for player weapons
|
||||||
|
if (bIsPlayerWeapon)
|
||||||
|
{
|
||||||
|
Bullet->UseMathematicalPhysics = true;
|
||||||
|
Bullet->EnableSpalling = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Bullet->UseMathematicalPhysics = false; // Artistic mode
|
||||||
|
Bullet->EnableSpalling = false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Part 6: Testing and Validation
|
||||||
|
|
||||||
|
### Create Test Scenarios
|
||||||
|
|
||||||
|
1. **Basic Penetration Test**
|
||||||
|
```cpp
|
||||||
|
// Test setup for material validation
|
||||||
|
void TestMaterialPenetration()
|
||||||
|
{
|
||||||
|
// Spawn test bullet
|
||||||
|
AEBBullet* TestBullet = SpawnTestBullet();
|
||||||
|
TestBullet->Velocity = FVector(85344, 0, 0); // 2800 fps
|
||||||
|
|
||||||
|
// Test against steel plate
|
||||||
|
FVector ImpactLocation = TestBullet->GetActorLocation() + FVector(100, 0, 0);
|
||||||
|
// Verify penetration depth matches expectations
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Ballistic Limit Verification**
|
||||||
|
```cpp
|
||||||
|
// Test ballistic limit accuracy
|
||||||
|
void ValidateBallisticLimit(UPhysicalMaterial* Material, float ExpectedLimit)
|
||||||
|
{
|
||||||
|
float CalculatedLimit = CalculateBallisticLimit(Material);
|
||||||
|
float ErrorPercent = FMath::Abs(CalculatedLimit - ExpectedLimit) / ExpectedLimit;
|
||||||
|
|
||||||
|
if (ErrorPercent > 0.1f) // 10% tolerance
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Ballistic limit validation failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Visualization
|
||||||
|
|
||||||
|
1. **Enable Debug Display**
|
||||||
|
```cpp
|
||||||
|
// Show penetration calculations
|
||||||
|
Bullet->DebugEnabled = true;
|
||||||
|
Barrel->DebugImpactInfo = true;
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Material Property Display**
|
||||||
|
```cpp
|
||||||
|
// Debug widget showing material info
|
||||||
|
if (DebugWidget)
|
||||||
|
{
|
||||||
|
DebugWidget->DisplayMaterialInfo(HitMaterial, PenetrationDepth, RicochetProbability);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Part 7: Real-World Examples
|
||||||
|
|
||||||
|
### Military Vehicle Armor
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Tank Steel Armor:
|
||||||
|
Thickness: 200mm
|
||||||
|
Material: RHA Steel
|
||||||
|
Density: 7.85 g/cm³
|
||||||
|
Hardness: 300 HB
|
||||||
|
Ballistic Limit: 3000 fps (M855A1)
|
||||||
|
|
||||||
|
Reactive Armor Tile:
|
||||||
|
Explosive Layer: 2mm
|
||||||
|
Steel Plates: 5mm each
|
||||||
|
Total Effectiveness: +40% vs APFSDS
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building Materials
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Reinforced Concrete Wall:
|
||||||
|
Thickness: 300mm
|
||||||
|
Rebar Density: 150 kg/m³
|
||||||
|
Concrete Strength: 35 MPa
|
||||||
|
Ballistic Limit: 1200 fps (7.62 NATO)
|
||||||
|
|
||||||
|
Brick Wall:
|
||||||
|
Thickness: 230mm
|
||||||
|
Mortar Joints: 10mm
|
||||||
|
Brick Strength: 20 MPa
|
||||||
|
Ballistic Limit: 800 fps (5.56 NATO)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Personal Protection
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
Level IIIA Vest (Kevlar):
|
||||||
|
Layers: 30-35
|
||||||
|
Total Thickness: 15mm
|
||||||
|
Areal Density: 1.0 kg/m²
|
||||||
|
Test Standard: .44 Magnum @ 1430 fps
|
||||||
|
|
||||||
|
Level III Plate (Ceramic):
|
||||||
|
Ceramic Thickness: 12mm
|
||||||
|
Backing Material: UHMWPE
|
||||||
|
Total Weight: 1.2 kg
|
||||||
|
Test Standard: 7.62 NATO @ 2780 fps
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Issues and Solutions
|
||||||
|
|
||||||
|
### Issue: Unrealistic Penetration
|
||||||
|
|
||||||
|
**Problem**: Bullets penetrate too easily or not enough
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check material density values
|
||||||
|
2. Verify bullet mass and velocity
|
||||||
|
3. Adjust penetration multipliers in response map
|
||||||
|
4. Use mathematical mode for more accurate results
|
||||||
|
|
||||||
|
### Issue: Poor Ricochet Behavior
|
||||||
|
|
||||||
|
**Problem**: Ricochets don't look realistic
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Check impact angle calculations
|
||||||
|
2. Adjust ricochet probability multipliers
|
||||||
|
3. Verify surface normal calculations
|
||||||
|
4. Test with different bullet types
|
||||||
|
|
||||||
|
### Issue: Performance Problems
|
||||||
|
|
||||||
|
**Problem**: Frame drops with many impacts
|
||||||
|
|
||||||
|
**Solutions**:
|
||||||
|
1. Enable object pooling
|
||||||
|
2. Reduce spalling fragment count
|
||||||
|
3. Use LOD system for distant impacts
|
||||||
|
4. Disable mathematical mode for AI weapons
|
||||||
|
|
||||||
|
## Best Practices Summary
|
||||||
|
|
||||||
|
1. **Start Simple**: Begin with artistic mode, then add mathematical mode as needed
|
||||||
|
2. **Test Thoroughly**: Validate material responses against real-world data
|
||||||
|
3. **Optimize Early**: Enable pooling and LOD systems from the start
|
||||||
|
4. **Document Settings**: Keep notes on material configurations for consistency
|
||||||
|
5. **Iterate Gameplay**: Balance realism with fun gameplay
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- Explore [Advanced Weapon Systems](advanced-weapon-systems) for complex firing mechanisms
|
||||||
|
- Check [Performance Optimization](../advanced/performance-optimization) for scaling to large battles
|
||||||
|
- Review [Multiplayer Guide](../advanced/multiplayer-guide) for network considerations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This guide provides the foundation for creating realistic and performant material interactions in EasyBallistics. Experiment with different configurations to find the perfect balance for your project.*
|
||||||
@@ -40,6 +40,7 @@ const sidebars = {
|
|||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tutorials',
|
label: 'Tutorials',
|
||||||
items: [
|
items: [
|
||||||
|
'tutorials/material-setup-guide',
|
||||||
'tutorials/advanced-weapon-systems',
|
'tutorials/advanced-weapon-systems',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -51,6 +52,7 @@ const sidebars = {
|
|||||||
'advanced/performance-optimization',
|
'advanced/performance-optimization',
|
||||||
'advanced/editor-tools',
|
'advanced/editor-tools',
|
||||||
'advanced/editor-integration',
|
'advanced/editor-integration',
|
||||||
|
'advanced/json-import-export',
|
||||||
'advanced/migration-guide',
|
'advanced/migration-guide',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -60,6 +62,7 @@ const sidebars = {
|
|||||||
items: [
|
items: [
|
||||||
'api/overview',
|
'api/overview',
|
||||||
'api/bullet-reference',
|
'api/bullet-reference',
|
||||||
|
'api/material-properties-reference',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'troubleshooting',
|
'troubleshooting',
|
||||||
|
|||||||
Reference in New Issue
Block a user