# How to Configure Strain Limiting Parameters to Prevent Mesh Deformation in PPF Contact Solver

> Prevent mesh deformation in the PPF Contact Solver by configuring strain limiting parameters. Learn how to set enable_strain_limit and strain_limit values effectively.

- Repository: [ZOZO, Inc./ppf-contact-solver](https://github.com/st-tech/ppf-contact-solver)
- Tags: how-to-guide
- Published: 2026-05-27

---

**To configure strain limiting in the PPF Contact Solver, set `enable_strain_limit` to `True` and specify a `strain_limit` value (e.g., `0.05` for 5% stretch), but you must keep `shrink_x` and `shrink_y` at `1.0` to avoid validation conflicts that raise a `ValueError`.**

The st-tech/ppf-contact-solver repository implements strain limiting as a per-material constraint that prevents shell and rod meshes from stretching beyond defined thresholds during physics simulation. Configuring these parameters correctly ensures your simulations maintain mesh integrity without inverted faces or excessive distortion.

## Understanding Strain Limiting Parameters

Strain limiting in PPF Contact Solver acts as a **hard constraint** on edge-length changes during simulation. The system stores these parameters per object group (shell or rod) and validates configurations at scene-build time to prevent incompatible settings.

According to [`blender_addon/models/groups.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/blender_addon/models/groups.py), every object group initializes with conservative defaults:

- `enable_strain_limit = False` (feature disabled by default)
- `strain_limit = 0.05` (5% maximum stretch when enabled)

The Python `ParamHolder` class defined in [`frontend/_param_.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/frontend/_param_.py) wraps the Rust backing store, exposing typed `set()` and `get()` methods for these parameters. When you configure strain limiting, you are setting a **multiplicative factor**—for example, a `strain_limit` of `0.08` permits up to 8% elongation from the rest shape before the solver intervenes.

## Configuring Strain Limiting via Python API

When working headless or scripting simulation setups, use the `SceneBuilder` API to configure strain constraints programmatically.

First, enable strain limiting and set the threshold:

```python
from frontend import SceneBuilder

builder = SceneBuilder()
scene = builder.load("simulation_scene.json")

# Access your shell object

cloth = scene.object["cloth_shell"]

# Enable strain limiting with an 8% stretch tolerance

cloth.param.set("enable_strain_limit", True)
cloth.param.set("strain_limit", 0.08)

```

Then, ensure shrink parameters remain neutral to pass validation:

```python

# Required: keep shrink at unity when strain limiting is active

cloth.param.set("shrink_x", 1.0)
cloth.param.set("shrink_y", 1.0)

# Build and solve

solution = scene.solve()

```

For quick testing, you can also use the hyphenated key variant that the Rust side normalizes:

```python

# Alternative key syntax (also valid)

cloth.param.set("strain-limit", 0.04)

```

## Configuring Strain Limiting via Blender UI

The Blender addon exposes these parameters in the **Object Group** panel without requiring code. According to [`blender_addon/ui/object_group.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/blender_addon/ui/object_group.py) and [`blender_addon/ui/dynamics/panels.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/blender_addon/ui/dynamics/panels.py), you can configure settings through the interface:

1. Select your cloth object group in the Outliner
2. In the **Object Group** panel, tick **"Enable Strain Limit"**
3. Adjust the **"Strain Limit"** slider (e.g., `0.05` for 5% stretch)
4. Verify that **"Shrink X"** and **"Shrink Y"** are both set to `1.0`

The UI writes directly to the same underlying `ParamHolder` instances used by the solver, ensuring consistency between visual configuration and batch processing.

## Resolving Shrink/Strain Limit Conflicts

The scene builder validates strain limiting configurations in [`frontend/_scene_.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/frontend/_scene_.py) (lines 10005–10021) to prevent contradictory inputs. The solver treats **shrink operations** (non-unit `shrink_x` or `shrink_y`) as pre-scales of the rest shape, which conflicts with active strain constraints.

If you attempt to build a scene where `shrink_x` or `shrink_y` differs from `1.0` while `strain_limit` is greater than zero, the code invokes the Rust helper `scene_shell_shrink_strain_limit_conflict` and raises a `ValueError` with a descriptive message.

To resolve this, choose one of two approaches:

- **Approach A:** Keep shrink/extend neutral (`shrink_x = 1.0`, `shrink_y = 1.0`) and use strain limiting to control deformation during simulation.
- **Approach B:** Disable strain limiting (`enable_strain_limit = False`) if you require non-unit shrink values for pre-scaling the rest geometry.

## Summary

- **Default behavior** in [`blender_addon/models/groups.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/blender_addon/models/groups.py) disables strain limiting (`enable_strain_limit = False`) with a conservative `0.05` threshold.
- **Validation logic** in [`frontend/_scene_.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/frontend/_scene_.py) prevents simultaneous use of strain limiting and non-unit shrink/extend values.
- **Configuration** requires setting both the enable flag and limit value, then ensuring `shrink_x` and `shrink_y` equal `1.0`.
- **API access** is available through `frontend._param_.PyParamHolder.set()` for Python scripts and via Blender UI panels defined in [`blender_addon/ui/object_group.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/blender_addon/ui/object_group.py).

## Frequently Asked Questions

### What is the default strain limit value in PPF Contact Solver?

The default value is `0.05` (5% stretch), defined in [`blender_addon/models/groups.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/blender_addon/models/groups.py) for all shell and rod object groups. However, the feature is disabled by default (`enable_strain_limit = False`), so you must explicitly enable it for the constraint to take effect.

### Why do I get a ValueError when enabling strain limits with shrink parameters?

The validation code in [`frontend/_scene_.py`](https://github.com/st-tech/ppf-contact-solver/blob/main/frontend/_scene_.py) (lines 10005–10021) raises a `ValueError` when it detects that `shrink_x` or `shrink_y` differs from `1.0` while `strain_limit` is greater than zero. This prevents the solver from receiving contradictory inputs, as shrink operations pre-scale the rest shape while strain limits constrain deformation relative to that rest shape.

### Can I use strain limiting with pre-scaled or non-uniform meshes?

You cannot use strain limiting simultaneously with non-unit shrink values (`shrink_x != 1.0` or `shrink_y != 1.0`). If your mesh requires pre-scaling, either apply the scale to the geometry before importing (baking it into the rest shape) and keep shrink values at `1.0`, or disable strain limiting entirely by setting `enable_strain_limit = False`.

### How does the solver enforce the strain limit during simulation?

Once configured, the Rust solver backend enforces the maximum allowable edge-length change each timestep, preventing any edge from stretching beyond the specified multiplicative factor relative to its rest-length. This occurs automatically during the `scene.solve()` call without requiring additional Python callbacks.