Skip to content

optimize TrailRenderer texture scale and remove widthMultiplier#2889

Open
GuoLei1990 wants to merge 5 commits intogalacean:dev/2.0from
GuoLei1990:feat/opt-textureScale
Open

optimize TrailRenderer texture scale and remove widthMultiplier#2889
GuoLei1990 wants to merge 5 commits intogalacean:dev/2.0from
GuoLei1990:feat/opt-textureScale

Conversation

@GuoLei1990
Copy link
Member

@GuoLei1990 GuoLei1990 commented Feb 8, 2026

Summary

  • Changed textureScale from number to Vector2, enabling independent X/Y texture scaling (along the trail vs across the trail)
  • Removed widthMultiplier API — trail width is now fully controlled by widthCurve, simplifying the API
  • Reorganized renderer_TrailParams shader uniform layout: x → textureMode, y → textureScaleX, z → textureScaleY
  • Updated e2e and unit tests to match new API

Breaking Changes

  • widthMultiplier removed: Use widthCurve instead. e.g. trail.widthMultiplier = 2.0 with CurveKey(0, 1)CurveKey(0, 2) directly
  • textureScale type changed: From number to Vector2, enabling separate X/Y scale control

Test plan

  • e2e trail rendering screenshot test passed
  • Unit tests passed (constructor, textureMode, textureScale, widthCurve, bounds)
  • Visual verification of trail width and texture scaling

Summary by CodeRabbit

  • Refactor
    • Trail renderer API refactored: the width property has been removed and replaced with widthCurve for width control. textureScale property changed from a scalar number to a Vector2, providing separate x and y components for texture scale adjustment.

@GuoLei1990 GuoLei1990 self-assigned this Feb 8, 2026
@GuoLei1990 GuoLei1990 added the enhancement New feature or request label Feb 8, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Walkthrough

TrailRenderer API and internals updated: public width getter/setter removed (width now driven by widthCurve), textureScale changed from a scalar to a Vector2, internal _textureScale and a sync hook were added, and bounds calculation was adjusted to use the maximum width multiplier. Tests and an e2e case were updated to match.

Changes

Cohort / File(s) Summary
TrailRenderer core
packages/core/src/trail/TrailRenderer.ts
Removed public width getter/setter; changed textureScale type from scalar to Vector2 and introduced private _textureScale with _onTextureScaleChanged to sync _trailParams; adjusted textureMode mapping and bounds calculation to use maximum width multiplier and updated internal trail parameter layout.
Unit tests
tests/src/core/Trail.test.ts
Refactored tests to stop using TrailRenderer.width; use widthCurve for width checks; updated textureScale initialization and assertions to use Vector2 (x/y) and .set(...).
E2E example
e2e/case/trailRenderer-basic.ts
Replaced direct trail.width assignment with constructing/applying a tapered widthCurve scaled by config width; width baked into curve keys instead of using a width property.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇
I hopped through lines both new and old,
Split one scale into a pair so bold,
X and Y now dance in tune,
Curves decide how wide the rune,
A whiskered cheer for changes rolled.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title mentions 'remove widthMultiplier' but the changes show removal of the 'width' property and changes to 'textureScale' API; widthMultiplier is not directly addressed in the code changes. Update title to 'Support separate X/Y texture scale for TrailRenderer' or 'Convert TrailRenderer textureScale to Vector2 for independent X/Y scaling' to accurately reflect the main changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into dev/2.0

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@GuoLei1990 GuoLei1990 added the effect Effect related functions label Feb 8, 2026
@GuoLei1990 GuoLei1990 added this to the 2.0 milestone Feb 8, 2026
@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.03%. Comparing base (d68166b) to head (4f9399d).

Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #2889      +/-   ##
===========================================
- Coverage    83.03%   83.03%   -0.01%     
===========================================
  Files          796      796              
  Lines        90449    90450       +1     
  Branches      9503     9497       -6     
===========================================
- Hits         75107    75101       -6     
- Misses       15260    15267       +7     
  Partials        82       82              
Flag Coverage Δ
unittests 83.03% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/core/src/trail/TrailRenderer.ts`:
- Around line 161-167: The cloned TrailRenderer's deep-cloned _textureScale
Vector2 loses its _onValueChanged handler so changes to textureScale won't
propagate; add an override of _cloneTo on TrailRenderer that calls
super._cloneTo(target, srcRoot, targetRoot) and then re-wire the handler by
setting target._textureScale._onValueChanged =
target._onTextureScaleChanged.bind(target) (use the _textureScale,
_onValueChanged, and _onTextureScaleChanged symbols to locate fields/methods).
🧹 Nitpick comments (1)
tests/src/core/Trail.test.ts (1)

107-119: Good test coverage of both mutation paths (setter and direct .set()).

This validates that both textureScale = new Vector2(...) and textureScale.set(...) correctly update the property. Consider also adding a test that mutates individual components (e.g., textureScale.x = 3.0) to fully cover the _onValueChanged handler, though this is optional.

Comment on lines 161 to 167
constructor(entity: Entity) {
super(entity);
// @ts-ignore
this._textureScale._onValueChanged = this._onTextureScaleChanged.bind(this);
this._onTextureScaleChanged();
this._initGeometry();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the TrailRenderer class structure
cat -n packages/core/src/trail/TrailRenderer.ts | head -200

Repository: galacean/engine

Length of output: 8156


🏁 Script executed:

# Check the parent class (Renderer) to understand cloning behavior
fd -e ts -p "Renderer" packages/core/src | head -20

Repository: galacean/engine

Length of output: 442


🏁 Script executed:

# Look for _onClone or similar clone lifecycle methods
rg -n "_onClone|_cloneTo|clone\(" --type=ts packages/core/src | head -30

Repository: galacean/engine

Length of output: 2937


🏁 Script executed:

# Check for _onValueChanged usage patterns
rg -n "_onValueChanged" --type=ts -C 2 packages/core/src | head -50

Repository: galacean/engine

Length of output: 4078


🏁 Script executed:

# Search for _cloneTo in TrailRenderer
rg -n "_cloneTo" packages/core/src/trail/TrailRenderer.ts

Repository: galacean/engine

Length of output: 41


🏁 Script executed:

# Check the Renderer base class for cloning
cat -n packages/core/src/Renderer.ts | head -100

Repository: galacean/engine

Length of output: 4595


🏁 Script executed:

# Look at CloneManager to understand how `@deepClone` works
rg -n "deepClone|@deepClone" packages/core/src/clone/CloneManager.ts | head -40

Repository: galacean/engine

Length of output: 239


🏁 Script executed:

# Check ComponentCloner to see how cloning is done for components
cat -n packages/core/src/clone/ComponentCloner.ts

Repository: galacean/engine

Length of output: 1667


🏁 Script executed:

# Search for Renderer._cloneTo method
rg -n "_cloneTo" packages/core/src/Renderer.ts -A 15

Repository: galacean/engine

Length of output: 498


🏁 Script executed:

# Examine CloneManager.cloneProperty to understand how `@deepClone` works
rg -n "cloneProperty" packages/core/src/clone/CloneManager.ts -A 20 | head -100

Repository: galacean/engine

Length of output: 2380


🏁 Script executed:

# Look for the deepCloneObject implementation
rg -n "deepCloneObject" packages/core/src/clone/CloneManager.ts -A 30 | head -80

Repository: galacean/engine

Length of output: 323


Cloning bug: _onValueChanged handler won't be re-wired on the cloned _textureScale.

When a TrailRenderer is cloned, the deep-cloned _textureScale Vector2 lacks the _onValueChanged callback that's set up in the constructor. Since the constructor is not invoked during cloning, mutations to the clone's textureScale (e.g., .set(...) or .x = ...) will silently fail to sync to _trailParams.z/w.

Add a _cloneTo override to re-wire the callback on the cloned instance:

override _cloneTo(target: TrailRenderer, srcRoot: Entity, targetRoot: Entity): void {
  super._cloneTo(target, srcRoot, targetRoot);
  // `@ts-ignore`
  target._textureScale._onValueChanged = target._onTextureScaleChanged.bind(target);
}
🤖 Prompt for AI Agents
In `@packages/core/src/trail/TrailRenderer.ts` around lines 161 - 167, The cloned
TrailRenderer's deep-cloned _textureScale Vector2 loses its _onValueChanged
handler so changes to textureScale won't propagate; add an override of _cloneTo
on TrailRenderer that calls super._cloneTo(target, srcRoot, targetRoot) and then
re-wire the handler by setting target._textureScale._onValueChanged =
target._onTextureScaleChanged.bind(target) (use the _textureScale,
_onValueChanged, and _onTextureScaleChanged symbols to locate fields/methods).

@GuoLei1990 GuoLei1990 changed the title feat: update trail texture scaling to support separate X and Y scales Update trail texture scaling to support separate X and Y scales Feb 9, 2026
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x: widthMultiplier

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@GuoLei1990 GuoLei1990 changed the title Update trail texture scaling to support separate X and Y scales Support separate X/Y texture scale for TrailRenderer` Feb 16, 2026
@GuoLei1990 GuoLei1990 changed the title Support separate X/Y texture scale for TrailRenderer` optimize TrailRenderer texture scale and remove widthMultiplier Feb 16, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/core/src/trail/TrailRenderer.ts`:
- Around line 604-609: Remove the meaningless `@ignoreClone` decorator from the
method declaration of _onTextureScaleChanged because `@ignoreClone` is a property
decorator for instance fields and has no effect on prototype methods; edit the
TrailRenderer class to delete the `@ignoreClone` annotation above the private
method _onTextureScaleChanged so the method remains unchanged in behavior but no
longer includes an incorrect decorator.
🧹 Nitpick comments (1)
tests/src/core/Trail.test.ts (1)

94-106: Good coverage of both assignment and mutation paths.

Consider adding a clone test for TrailRenderer that verifies textureScale changes on the cloned instance propagate correctly — this would catch the _onValueChanged re-wiring bug flagged above.

Comment on lines +604 to +609

@ignoreClone
private _onTextureScaleChanged(): void {
this._trailParams.y = this._textureScale.x;
this._trailParams.z = this._textureScale.y;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the `@ignoreClone` decorator definition and understand its implementation
rg -n 'export.*ignoreClone|function.*ignoreClone|const.*ignoreClone' --type=ts -A 5 packages/core

Repository: galacean/engine

Length of output: 534


🏁 Script executed:

# Check the provided script - search for `@ignoreClone` on methods
rg -nP '@ignoreClone\s*\n\s*(private|protected|public)?\s+\w+\(' --type=ts packages/core/src | head -20

Repository: galacean/engine

Length of output: 41


🏁 Script executed:

# Also look for `@ignoreClone` usage on properties vs methods to understand the pattern
rg -n '@ignoreClone' --type=ts -B 1 packages/core/src | head -40

Repository: galacean/engine

Length of output: 2567


🏁 Script executed:

# Verify how CloneManager.registerCloneMode works - check if it could affect methods
rg -n 'registerCloneMode|CloneMode\.Ignore' --type=ts -B 2 -A 2 packages/core/src/clone/CloneManager.ts | head -30

Repository: galacean/engine

Length of output: 986


🏁 Script executed:

# Check if there's any special handling for methods in the clone logic
rg -n 'clone|cloneMode' --type=ts packages/core/src/clone/CloneManager.ts | head -20

Repository: galacean/engine

Length of output: 1114


🏁 Script executed:

# Double-check the specific method in TrailRenderer.ts to confirm it's a method
sed -n '604,609p' packages/core/src/trail/TrailRenderer.ts

Repository: galacean/engine

Length of output: 217


Remove @ignoreClone from the method — it has no effect.

@ignoreClone is a property decorator designed for instance properties. Methods are shared across instances via the prototype and are never cloned, so this decorator is a no-op and should be removed.

Proposed fix
-  `@ignoreClone`
   private _onTextureScaleChanged(): void {
     this._trailParams.y = this._textureScale.x;
     this._trailParams.z = this._textureScale.y;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@ignoreClone
private _onTextureScaleChanged(): void {
this._trailParams.y = this._textureScale.x;
this._trailParams.z = this._textureScale.y;
}
private _onTextureScaleChanged(): void {
this._trailParams.y = this._textureScale.x;
this._trailParams.z = this._textureScale.y;
}
🤖 Prompt for AI Agents
In `@packages/core/src/trail/TrailRenderer.ts` around lines 604 - 609, Remove the
meaningless `@ignoreClone` decorator from the method declaration of
_onTextureScaleChanged because `@ignoreClone` is a property decorator for instance
fields and has no effect on prototype methods; edit the TrailRenderer class to
delete the `@ignoreClone` annotation above the private method
_onTextureScaleChanged so the method remains unchanged in behavior but no longer
includes an incorrect decorator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effect Effect related functions enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments