Skip to content

feat(particle): add transform to shape module#2965

Merged
cptbtptpbcptdtptp merged 20 commits intogalacean:dev/2.0from
hhhhkrx:feat/particle-shape-transform
Apr 16, 2026
Merged

feat(particle): add transform to shape module#2965
cptbtptpbcptdtptp merged 20 commits intogalacean:dev/2.0from
hhhhkrx:feat/particle-shape-transform

Conversation

@hhhhkrx
Copy link
Copy Markdown
Contributor

@hhhhkrx hhhhkrx commented Apr 15, 2026

Summary

  • Add position (Vector3) and rotation (Vector3, euler degrees) properties to BaseShape, enabling per-shape local transform offset for particle emission
  • Wrap subclass generation/bounds methods with transform-aware versions (_generateTransformedPositionAndDirection, _getTransformedPositionRange, _getTransformedDirectionRange)
  • Use Arvo method for tight rotated AABB bounds calculation
  • Zero overhead fast path when position/rotation are default (0,0,0)
  • Zero subclass modifications required

Test plan

  • All 51 existing particle tests pass with no regressions
  • Manual test: set shape.position.set(2, 0, 0) and verify emission offset
  • Manual test: set shape.rotation.set(0, 0, 90) and verify rotated emission area

Summary by CodeRabbit

  • New Features

    • Particle emission shapes now support position offsets, rotation (specified in Euler angles), and scale transformations. Both emitted particles and computed bounding boxes correctly account for applied transforms.
  • Tests

    • Added comprehensive testing for shape transformations, covering individual position/rotation/scale transforms and combined scenarios, with validation of bounding box calculations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Added transform (position, rotation, scale) support to particle emission shapes. BaseShape now defines public transform properties with automatic change detection, delegates shape-specific generation and range logic to new abstract "Local" methods, and applies matrix-based transformations to emitted positions/directions and bounding boxes. All shape subclasses renamed their core methods accordingly. Added comprehensive test coverage and an E2E validation test.

Changes

Cohort / File(s) Summary
Transform Architecture
packages/core/src/particle/modules/shape/BaseShape.ts
Added public position, rotation, scale properties with private backing fields and change detection. Made _generatePositionAndDirection, _getPositionRange, _getDirectionRange concrete and transform-aware; introduced new protected abstract _generateLocalPositionAndDirection, _getLocalPositionRange, _getLocalDirectionRange. Implemented _cloneTo, matrix building (_getMatrix), and AABB transformation helpers (_transformBoundingBox). Transform changes dispatch via _updateManager and affect emission/query results.
Shape Subclass Refactoring
packages/core/src/particle/modules/shape/MeshShape.ts, BoxShape.ts, CircleShape.ts, ConeShape.ts, HemisphereShape.ts, SphereShape.ts
Renamed three internal methods in each class to use Local prefix: _generatePositionAndDirection_generateLocalPositionAndDirection, _getPositionRange_getLocalPositionRange, _getDirectionRange_getLocalDirectionRange. MeshShape._cloneTo now calls super._cloneTo(target) and includes override modifier.
Test Coverage
tests/src/core/particle/ParticleBoundingBox.test.ts, ParticleShapeTransform.test.ts
Added 4 new bounding-box test cases validating BoxShape under position, rotation, scale, and combined transforms. Added comprehensive ParticleShapeTransform test suite (7 test cases) covering position/direction generation under transforms, range calculations with rotation/scale, transform order validation, default-transform optimization, cloning behavior, and quaternion reconstruction.
E2E Test & Config
e2e/case/particleRenderer-shape-transform.ts, e2e/config.ts
Added new E2E test case script spawning four particle entities with cone/box shapes configured with varying transforms (position offset, rotation, scale, combined). Updated e2e/config.ts to register Particle.shapeTransform test case with threshold: 0 and diffPercentage: 0.

Sequence Diagram

sequenceDiagram
    participant Emitter as ParticleRenderer<br/>(Emitter)
    participant Shape as BaseShape<br/>(Shape)
    participant SubShape as Concrete Shape<br/>(e.g., BoxShape)
    participant Transform as Transform<br/>Logic
    participant Output as Particle<br/>(Output)

    Emitter->>Shape: _generatePositionAndDirection()
    Shape->>SubShape: _generateLocalPositionAndDirection()
    SubShape->>SubShape: Generate local position & direction
    SubShape-->>Shape: Return local values
    alt Has Transform
        Shape->>Transform: _getMatrix() (scale, rotation, position)
        Transform-->>Shape: Affine transform matrix
        Shape->>Transform: Apply matrix to position & direction
        Transform-->>Shape: Transformed position & direction
    else No Transform
        Shape->>Shape: Use local values as-is
    end
    Shape-->>Emitter: Final position & direction
    Emitter->>Output: Emit particle with transformed values
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Transforms bloom in particle space,
Position, rotation, scale embrace,
Matrices dance where shapes now play,
Each subclass finds its local way.
Tests flourish to light the path,
No emission escapes the math!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding transform (position, rotation, and scale) capabilities to the shape module for particles.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@hhhhkrx hhhhkrx self-assigned this Apr 15, 2026
@hhhhkrx hhhhkrx added this to Particle Apr 15, 2026
@hhhhkrx hhhhkrx added this to the 2.0 milestone Apr 15, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

❌ Patch coverage is 73.26007% with 73 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.10%. Comparing base (8557031) to head (59946be).
⚠️ Report is 2 commits behind head on dev/2.0.

Files with missing lines Patch % Lines
e2e/case/particleRenderer-shape-transform.ts 0.00% 54 Missing and 1 partial ⚠️
...kages/core/src/particle/modules/shape/BaseShape.ts 92.10% 12 Missing ⚠️
e2e/config.ts 0.00% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #2965      +/-   ##
===========================================
- Coverage    77.54%   77.10%   -0.45%     
===========================================
  Files          900      901       +1     
  Lines        98724    98869     +145     
  Branches      9802     9848      +46     
===========================================
- Hits         76560    76228     -332     
- Misses       21998    22471     +473     
- Partials       166      170       +4     
Flag Coverage Δ
unittests 77.10% <73.26%> (-0.45%) ⬇️

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
Copy Markdown

@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.

🧹 Nitpick comments (2)
packages/core/src/particle/ParticleGenerator.ts (1)

281-283: Please add automated coverage for the new transformed shape path.

These lines are now the sole integration points for translated/rotated shapes in both emission and bounds, but the PR notes those scenarios are still manual-only. A small regression test for shape.position and another for shape.rotation/rotated bounds would make this change much safer to evolve.

Also applies to: 1231-1232

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/particle/ParticleGenerator.ts` around lines 281 - 283, Add
automated unit tests that exercise the transformed-shape code path triggered by
shape._generateTransformedPositionAndDirection: create a Shape with a non-zero
shape.position and assert emitted particle positions are translated by that
offset, and create a Shape with a non-zero shape.rotation and/or rotated bounds
and assert emitted particle positions/directions reflect the rotation (use
ParticleGenerator or the emission code that calls
shape._generateTransformedPositionAndDirection, passing an emission._shapeRand
and a fixed playTime, position, direction, and positionScale). In each test seed
the RNG (emission._shapeRand) or use deterministic inputs, call the same method
path used in production (so the multiply(positionScale) and
normalize()/multiply(positionScale) lines execute), and assert the resulting
position and direction vectors match expected transformed values (translation
and rotation) within a tight tolerance.
packages/core/src/particle/modules/shape/BaseShape.ts (1)

23-30: Harden the cached rotation state against clone rehydration paths.

_rotationQuaternion is derived from _rotation, but _rotationDirty starts false and both are marked @ignoreClone. During cloning, _rotation is deep cloned as a new Vector3 instance, but the callback binding established in the constructor (this._rotation._onValueChanged = this._onRotationChanged.bind(this)) is not replayed on the cloned Vector3. This means a cloned shape's rotation cache can become stale: if the cloned shape's rotation is modified, the cache won't be invalidated because the callback is missing.

Initializing _rotationDirty = true or implementing a _cloneTo hook to rebind the vector callback would make this robust.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/particle/modules/shape/BaseShape.ts` around lines 23 - 30,
The cloned shape can have a stale rotation cache because _rotation is
deep-cloned but its callback binding (this._rotation._onValueChanged =
this._onRotationChanged.bind(this)) is not reapplied; fix by either (A)
initialize private _rotationDirty = true so any clone recomputes the quaternion
on first use (update the field on BaseShape), or (B) implement a _cloneTo(clone:
BaseShape) hook that rebinds the cloned vector's callback (call
clone._rotation._onValueChanged = clone._onRotationChanged.bind(clone)) and
ensure clone._rotationDirty is set appropriately; reference the fields
_rotation, _rotationQuaternion, _rotationDirty and the method _onRotationChanged
when applying the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/particle/modules/shape/BaseShape.ts`:
- Around line 23-30: The cloned shape can have a stale rotation cache because
_rotation is deep-cloned but its callback binding
(this._rotation._onValueChanged = this._onRotationChanged.bind(this)) is not
reapplied; fix by either (A) initialize private _rotationDirty = true so any
clone recomputes the quaternion on first use (update the field on BaseShape), or
(B) implement a _cloneTo(clone: BaseShape) hook that rebinds the cloned vector's
callback (call clone._rotation._onValueChanged =
clone._onRotationChanged.bind(clone)) and ensure clone._rotationDirty is set
appropriately; reference the fields _rotation, _rotationQuaternion,
_rotationDirty and the method _onRotationChanged when applying the change.

In `@packages/core/src/particle/ParticleGenerator.ts`:
- Around line 281-283: Add automated unit tests that exercise the
transformed-shape code path triggered by
shape._generateTransformedPositionAndDirection: create a Shape with a non-zero
shape.position and assert emitted particle positions are translated by that
offset, and create a Shape with a non-zero shape.rotation and/or rotated bounds
and assert emitted particle positions/directions reflect the rotation (use
ParticleGenerator or the emission code that calls
shape._generateTransformedPositionAndDirection, passing an emission._shapeRand
and a fixed playTime, position, direction, and positionScale). In each test seed
the RNG (emission._shapeRand) or use deterministic inputs, call the same method
path used in production (so the multiply(positionScale) and
normalize()/multiply(positionScale) lines execute), and assert the resulting
position and direction vectors match expected transformed values (translation
and rotation) within a tight tolerance.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5f28acea-0f9a-45a5-84ab-e0d12fd47470

📥 Commits

Reviewing files that changed from the base of the PR and between 8557031 and c2fd806.

📒 Files selected for processing (2)
  • packages/core/src/particle/ParticleGenerator.ts
  • packages/core/src/particle/modules/shape/BaseShape.ts

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/particle/modules/shape/BaseShape.ts`:
- Around line 23-30: The clone lifecycle is broken because deep-cloned Vector3
fields (_position and _rotation) lose their _onValueChanged hooks and rotation
cache fields (_rotationDirty and _rotationQuaternion) are excluded from cloning;
implement a _cloneTo(target: BaseShape) method on BaseShape that rebinds the
callbacks on the cloned target (set target._position._onValueChanged to
target._updateManager.dispatch.bind(target._updateManager) and
target._rotation._onValueChanged to target._onRotationChanged.bind(target)) and
set target._rotationDirty = true so the cloned instance recomputes
_rotationQuaternion; reference the existing symbols _position, _rotation,
_rotationDirty, _rotationQuaternion, _onValueChanged, _updateManager.dispatch
and _onRotationChanged when adding the hook.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e861800c-0b64-43fb-aee1-f4d6b1c9b2d9

📥 Commits

Reviewing files that changed from the base of the PR and between c2fd806 and 97d6719.

📒 Files selected for processing (1)
  • packages/core/src/particle/modules/shape/BaseShape.ts

Comment thread packages/core/src/particle/modules/shape/BaseShape.ts Outdated
GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/particle/modules/shape/BaseShape.ts`:
- Around line 136-165: Current code uses _hasShapeTransform() as a single gate
which causes unnecessary quaternion transforms and bounding-box rotations when
only translation (_position) is set; change each helper to split rotation vs
translation checks: in _generateTransformedPositionAndDirection call
_generatePositionAndDirection first, then if a rotation is present (e.g. replace
or augment _hasShapeTransform() with a rotation-specific check or test whether
_getRotationQuaternion() returns a non-identity), apply the quaternion via
_getRotationQuaternion() and Vector3.transformByQuat to position and direction,
and after that if a translation (_position) is non-zero add this._position to
position; in _getTransformedPositionRange call _getPositionRange, then only call
_rotateBoundingBox(outMin,outMax) when rotation is present and afterward add
this._position to outMin/outMax only when translation is present; in
_getTransformedDirectionRange call _getDirectionRange and only call
_rotateBoundingBox(outMin,outMax) when rotation is present (do not add
translation to directions). Use the existing symbols
(_generatePositionAndDirection, _getRotationQuaternion, _rotateBoundingBox,
_position, _getPositionRange, _getDirectionRange) to locate and implement these
checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 36601127-7868-49c2-bbae-21c4d2bb2904

📥 Commits

Reviewing files that changed from the base of the PR and between 97d6719 and 11f0695.

📒 Files selected for processing (2)
  • packages/core/src/particle/modules/shape/BaseShape.ts
  • packages/core/src/particle/modules/shape/MeshShape.ts

Comment thread packages/core/src/particle/modules/shape/BaseShape.ts Outdated
GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

Add Vector3 scale (default 1,1,1) to shape transform, aligning with
Unity ParticleSystem.ShapeModule's full position/rotation/scale TRS.
Scale is applied before rotation in emission and bounds calculation.
Use arrow properties for callbacks and @ignoreClone + manual copyFrom
in _cloneTo, consistent with Transform's clone pattern.
GuoLei1990

This comment was marked as outdated.

GuoLei1990 and others added 5 commits April 15, 2026 20:17
Shape transform logic is now inside the original _generatePositionAndDirection
/ _getPositionRange / _getDirectionRange methods. Subclass implementations
renamed to _generateLocalPositionAndDirection etc. ParticleGenerator callers
unchanged.
Replace separate scale multiply + quaternion rotate with a cached
Matrix3x3 RS matrix. Both emission and Arvo AABB transform share
the same matrix, rebuilt only when position/rotation/scale changes.
Replace Matrix3x3 with Matrix, use affineTransformation to build TRS
matrix, transformToVec3 for position and transformNormal for direction.
Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
tests/src/core/particle/ParticleShapeTransform.test.ts (1)

6-9: Reset the mutable test fixtures per case.

Rand is stateful, so sharing it across the whole suite makes generation assertions order-dependent. Recreate rand alongside position and direction in beforeEach() to keep the tests isolated.

♻️ Small cleanup
 describe("ParticleShapeTransform", function () {
-  const position = new Vector3();
-  const direction = new Vector3();
-  const rand = new Rand(0, 1234);
+  let position: Vector3;
+  let direction: Vector3;
+  let rand: Rand;
   const epsilon = 1e-5;
+
+  beforeEach(() => {
+    position = new Vector3();
+    direction = new Vector3();
+    rand = new Rand(0, 1234);
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/src/core/particle/ParticleShapeTransform.test.ts` around lines 6 - 9,
The test suite currently shares a single Rand instance across cases which makes
tests order-dependent; move creation of the mutable fixtures into a beforeEach
block so each test gets a fresh Rand and fresh Vector3s. Specifically, in
ParticleShapeTransform.test.ts, initialize position, direction and rand inside
beforeEach (recreating Rand with new Rand(0, 1234)), rather than as top-level
constants, so tests using position, direction and rand are isolated and
deterministic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/particle/modules/shape/BaseShape.ts`:
- Around line 147-174: The direction AABB logic is inconsistent with generation:
_generatePositionAndDirection applies the full transform (including scale) to
direction then normalizes, but _getDirectionRange/_transformBoundingBox only
uses the scaled AABB, causing under-estimated ranges when scale != 1. Fix by
making direction transforms scale-agnostic: either (a) apply rotation-only part
of the matrix to directions (extract rotation from _getMatrix() or zero out
scale in the matrix) in both _generatePositionAndDirection and in the direction-
range path so _getLocalDirectionRange/_getDirectionRange use the same
rotation-only transform, or (b) compute the direction range by transforming the
local direction AABB corners with the full matrix and normalizing each
transformed vector before expanding the outMin/outMax; update
_getDirectionRange, _generatePositionAndDirection, and any helper like
_transformBoundingBox or add a new _transformDirectionBoundingBox to ensure both
generation and reported ranges match.

---

Nitpick comments:
In `@tests/src/core/particle/ParticleShapeTransform.test.ts`:
- Around line 6-9: The test suite currently shares a single Rand instance across
cases which makes tests order-dependent; move creation of the mutable fixtures
into a beforeEach block so each test gets a fresh Rand and fresh Vector3s.
Specifically, in ParticleShapeTransform.test.ts, initialize position, direction
and rand inside beforeEach (recreating Rand with new Rand(0, 1234)), rather than
as top-level constants, so tests using position, direction and rand are isolated
and deterministic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cb4ab1c8-fb7f-4ea3-9b82-e79bb4d67c55

📥 Commits

Reviewing files that changed from the base of the PR and between b659648 and 110f35c.

⛔ Files ignored due to path filters (1)
  • e2e/fixtures/originImage/Particle_particleRenderer-shape-transform.jpg is excluded by !**/*.jpg
📒 Files selected for processing (11)
  • e2e/case/particleRenderer-shape-transform.ts
  • e2e/config.ts
  • packages/core/src/particle/modules/shape/BaseShape.ts
  • packages/core/src/particle/modules/shape/BoxShape.ts
  • packages/core/src/particle/modules/shape/CircleShape.ts
  • packages/core/src/particle/modules/shape/ConeShape.ts
  • packages/core/src/particle/modules/shape/HemisphereShape.ts
  • packages/core/src/particle/modules/shape/MeshShape.ts
  • packages/core/src/particle/modules/shape/SphereShape.ts
  • tests/src/core/particle/ParticleBoundingBox.test.ts
  • tests/src/core/particle/ParticleShapeTransform.test.ts
✅ Files skipped from review due to trivial changes (2)
  • e2e/config.ts
  • tests/src/core/particle/ParticleBoundingBox.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/particle/modules/shape/MeshShape.ts

Comment thread packages/core/src/particle/modules/shape/BaseShape.ts
GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

@hhhhkrx hhhhkrx force-pushed the feat/particle-shape-transform branch from 8128fc9 to d53a708 Compare April 15, 2026 13:37
Replace center+extent+abs approach with direct min/max Arvo method.
Eliminates getCenter/getExtent/subtract/add intermediate steps since
BoundingBox already stores min/max. Mathematically equivalent with
slightly better floating-point precision.
GuoLei1990

This comment was marked as outdated.

Change _getPositionRange to accept BoundingBox directly, eliminating
intermediate copies. Direction range keeps RS-only Arvo method.
Also optimize BoundingBox.transform with Arvo min/max method.
GuoLei1990

This comment was marked as outdated.

- _getPositionRange accepts BoundingBox directly, reuses BoundingBox.transform
- BoundingBox.transform adds zero-guard to avoid 0 * Infinity = NaN
- Update tests for new _getPositionRange signature and edge cases
@hhhhkrx hhhhkrx changed the title feat(particle): add position and rotation transform to shape module feat(particle): add transform to shape module Apr 15, 2026
GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

// @ts-ignore
scale._onValueChanged = target._onTransformChanged;
target._transformDirty = true;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

如果将 this._position,this._rotation 和 this._scale 设置为 deepclone ,这十七行代码可以都干掉。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

@ignoreClone
private _scale = new Vector3(1, 1, 1);
@ignoreClone
private _rotationQuaternion = new Quaternion();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个你只做临时变量的话,可以使用静态变量 static _rotationQuaternion 代替

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread packages/core/src/particle/modules/shape/BaseShape.ts
return this._matrix;
}

private _hasShapeTransform(): boolean {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

_hasShapeTransform 改成一个 boolean 值,在 _onTransformChanged 中初始化。

GuoLei1990

This comment was marked as outdated.

static _tempVector30 = new Vector3();
/** @internal */
static _tempVector31 = new Vector3();
private static _tempQuaternion = new Quaternion();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

静态声明放在类的顶部。

Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp cptbtptpbcptdtptp left a comment

Choose a reason for hiding this comment

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

+1

@cptbtptpbcptdtptp cptbtptpbcptdtptp merged commit 7c5d468 into galacean:dev/2.0 Apr 16, 2026
10 of 12 checks passed
@github-project-automation github-project-automation Bot moved this to Done in Particle Apr 16, 2026
Copy link
Copy Markdown
Member

@GuoLei1990 GuoLei1990 left a comment

Choose a reason for hiding this comment

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

已关闭问题清单

# 问题 状态
1 clone 后 _onValueChanged 回调丢失、_rotationDirty 默认 false ✅ 已修复(@deepClone + constructor 绑定回调,clone 时 copyFrom 触发回调链自动设置 dirty 和 _hasShapeTransform
2 setter dispatch 建议 ✅ 已关闭(Vector3.copyFrom 内部触发 _onValueChanged
3 _rotateBoundingBox 可直接从四元数提取旋转矩阵列 ✅ 已关闭(最终方案用 Matrix.affineTransformation + 矩阵 elements 直接取)

总结

为粒子 BaseShape 添加 positionrotationscale 局部变换(TRS),完整对齐 Unity ParticleSystem.ShapeModule

自上次 review 以来新增 3 个 commit,均来自 cptbtptpbcptdtptp 的 inline review 反馈:

  1. 22dbc68 — 将 _hasShapeTransform() 方法改为 _hasShapeTransform boolean 缓存字段,在 _onTransformChanged 回调中更新。移除 _cloneTo——因为 @deepClonecopyFrom 会触发 _onValueChanged_onTransformChanged,自动设置 _transformDirty = true 和正确的 _hasShapeTransform 值,_cloneTo 不再需要。经 CloneManager 源码验证:target 已有 Vector3(constructor 中创建并绑定回调),@deepClonecopyFrom 路径,回调不丢失。
  2. 4328fe5 + 59946be — 将静态声明移到类顶部,符合 cptbtptpbcptdtptp 要求的代码风格。

最终设计简洁完整:

  • 零子类改动:基类 wrapper 包装 _generateLocalPositionAndDirection 等抽象方法
  • 零开销快路径_hasShapeTransform boolean 缓存,默认 false 直接短路
  • 矩阵缓存_transformDirty 标记,仅 TRS 变化时重建矩阵
  • clone 安全@deepClone + constructor 绑定回调,copyFrom 自动触发 _onTransformChanged 设置 dirty 和 _hasShapeTransform,无需 _cloneTo
  • position range 复用 BoundingBox.transform:统一 Arvo AABB 变换
  • BoundingBox.transform 零值守卫:避免 0 * Infinity = NaN

问题

无新问题。

LGTM,代码质量高,已合入。

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

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants