Skip to content

Fix some shaderlab bug#2946

Draft
zhuxudong wants to merge 30 commits intodev/2.0from
fix/shaderlab
Draft

Fix some shaderlab bug#2946
zhuxudong wants to merge 30 commits intodev/2.0from
fix/shaderlab

Conversation

@zhuxudong
Copy link
Copy Markdown
Member

@zhuxudong zhuxudong commented Mar 26, 2026

Summary

  • Fix texture()/textureCube()/texture2DLod() etc. builtin functions returning incorrect generic type
    (GVec4 resolved to sampler type instead of vec4), causing "No overload function type found" errors
  • Fix normalize() etc. generic builtins returning raw enum value (200) instead of TypeAny when args
    are unresolved, breaking downstream overload matching
  • Add missing texture2DLod builtin function registration
  • Fix #define values containing struct member access (e.g. #define UV o.v_uv) not being transformed
    during CodeGen, causing invalid GLSL output
  • Support cross-stage (vertex + fragment) struct variable map for global #define transformation

Test plan

  • Add generic return type test cases (texture-generic.shader)
  • Add #define struct access transformation tests with expected GLSL output verification
  • Add macro usage assertions: as RHS in multiplication, LHS in assignment, function argument, multiple
    varying properties

Summary by CodeRabbit

  • New Features

    • Member-access macros are now detected and expanded to reference struct properties in both globals and functions, with deduplicated varying/property tracking and improved macro-driven identifier rewriting.
  • Bug Fixes

    • Fixed generic texture return-type resolution for sampler variants and LOD/cube forms.
    • Prevented incorrect type inference for identifiers produced by member-access macros.
    • Avoided emitting empty/falsy global declarations when macros reduce to nothing.
  • Tests

    • Added tests for generic texture returns and macro/struct-access expansions, including emitted GLSL checks.

zhuxudong and others added 4 commits March 26, 2026 16:18
…tin functions

texture(sampler2D, vec2) returns GVec4 which was incorrectly resolved to
the sampler type instead of vec4, causing "No overload function type found"
when passing the result to user-defined functions like decode32(vec4).

Add resolveGenericReturnType() to correctly map GSampler* → GVec4:
  sampler2D/sampler3D/samplerCube → vec4
  isampler2D/isampler3D/...       → ivec4
  usampler2D/usampler3D/...       → uvec4
…exture2DLod signatures

- Simplify resolveGenericReturnType: remove genericParamType param, only
  check if return type is GVec4
- Fix textureCube/textureCubeLod return type: SAMPLER_CUBE → VEC4
- Add missing texture2DLod builtin function registration
- Add texture2DLod test cases to texture-generic.shader
* feat: implement HorizontalBillboard render mode
… type

When a builtin generic function (e.g. normalize) receives TypeAny args,
resolvedReturnType stays TypeAny. Previously the else branch returned
the raw EGenType enum value (200), which is neither a concrete type nor
a wildcard, causing downstream user-function overload matching to fail.
@zhuxudong zhuxudong added the bug Something isn't working label Mar 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 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

Classify dotted member-access macro values, track struct-variable→role mappings at function and global scope, transform macro #define expressions to reference struct properties during codegen, resolve generic builtin texture return types, and add tests validating these behaviors.

Changes

Cohort / File(s) Summary
Macro Member Access Support
packages/shader-lab/src/Preprocessor.ts
Added MacroValueType.MemberAccess, a regex to detect dotted member-access macro values, and updated getReferenceSymbolNames to extract root identifiers from member-access macros.
Macro Transformation in Code Generation
packages/shader-lab/src/codeGen/CodeGenVisitor.ts
Added protected _transformMacroDefineValue(lexeme, overrideMap?) to rewrite MACRO_DEFINE_EXPRESSION values using struct-role maps; updated emission of macro define tokens; added helpers to collect struct-var→role mappings from function params and local declarations and to extract identifier names from declarator lists.
Global Struct Mapping & Pre-registration
packages/shader-lab/src/codeGen/GLESVisitor.ts
Builds context._globalStructVarMap from vertex/fragment entry functions, pre-registers macro member-access references before emitting stage globals, and uses _transformMacroDefineValue(..., context._globalStructVarMap) when emitting global macros; refactors some global symbol emission logic.
Struct Variable and Role Tracking API
packages/shader-lab/src/codeGen/VisitorContext.ts
Added _structVarMap and _globalStructVarMap fields; getStructRole, registerStructVar, and referenceStructPropByName methods; adjusted reset behavior to manage these maps.
Builtin Function Generic Return Types
packages/shader-lab/src/parser/builtin/functions.ts
Added resolveGenericReturnType() used by BuiltinFunction.getFn() to compute concrete return types for generic overloads; adjusted texture-related overload return types (e.g., texture2DLod, textureCube*).
Type Inference Guard for Member-Access Macros
packages/shader-lab/src/parser/AST.ts
Prevent inferring concrete typeInfo for identifiers originating from member-access macros by keeping TypeAny; added helper to detect member-access macro usage and imported MacroValueType.
Tests
tests/src/shader-lab/ShaderLab.test.ts, tests/src/shader-lab/expected/*.vert.glsl, tests/src/shader-lab/expected/*.frag.glsl
Added ShaderLab tests covering generic texture returns and macro-driven struct-property access; tests include exact GLSL output comparisons and content-based assertions validating macro expansion, builtin usage, and varying deduplication.

Sequence Diagram

sequenceDiagram
    participant Preprocessor as Preprocessor.ts
    participant CodeGen as CodeGenVisitor.ts
    participant Context as VisitorContext.ts
    participant GLESGen as GLESVisitor.ts

    rect rgba(100,150,200,0.5)
    note over Preprocessor: Classify macro values, detect member-access forms
    Preprocessor->>Preprocessor: Identify "identifier.member" macros
    Preprocessor->>Context: expose reference root identifiers
    end

    rect rgba(100,150,200,0.5)
    note over CodeGen,Context: Collect struct-var → role mappings
    CodeGen->>Context: getStructRole(typeLexeme)
    Context-->>CodeGen: role or undefined
    CodeGen->>Context: populate _structVarMap from params & locals
    end

    rect rgba(150,100,200,0.5)
    note over GLESGen,Context: Build global mapping & pre-register macro refs
    GLESGen->>GLESGen: build _globalStructVarMap from entry funcs
    GLESGen->>Preprocessor: scan global macros for member-access
    GLESGen->>Context: referenceStructPropByName(role, prop)
    Context->>Context: record referenced property
    end

    rect rgba(150,200,100,0.5)
    note over CodeGen,Context: Transform and emit macro defines
    CodeGen->>CodeGen: _transformMacroDefineValue(lexeme, overrideMap)
    CodeGen->>Context: consult _structVarMap/_globalStructVarMap
    CodeGen->>Context: referenceStructPropByName for matches
    CodeGen->>CodeGen: emit transformed macro text
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I nibble dots in macro fields so bright,

I map each struct and role by night,
I hop through params, locals, global maps too,
I rewrite defines so props find you,
A tiny rabbit cheering shaders new 🎨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "Fix some shaderlab bug" is vague and generic, using non-descriptive language that fails to convey the specific nature of the changes in this multi-faceted PR. Revise the title to be more specific and descriptive, such as: "Fix ShaderLab generic texture return types and struct member access in macros" to accurately reflect the main changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/shaderlab

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.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 26, 2026

Codecov Report

❌ Patch coverage is 96.58537% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.51%. Comparing base (2f88c2f) to head (bfe4e9e).
⚠️ Report is 4 commits behind head on dev/2.0.

Files with missing lines Patch % Lines
packages/shader-lab/src/codeGen/CodeGenVisitor.ts 92.24% 9 Missing ⚠️
packages/shader-lab/src/codeGen/GLESVisitor.ts 98.48% 3 Missing ⚠️
...ackages/shader-lab/src/parser/builtin/functions.ts 95.45% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #2946      +/-   ##
===========================================
+ Coverage    77.26%   77.51%   +0.25%     
===========================================
  Files          899      899              
  Lines        98275    98616     +341     
  Branches      9670     9763      +93     
===========================================
+ Hits         75928    76442     +514     
+ Misses       22179    22007     -172     
+ Partials       168      167       -1     
Flag Coverage Δ
unittests 77.51% <96.58%> (+0.25%) ⬆️

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.

…tin functions

texture(sampler2D, vec2) returns GVec4 which was incorrectly resolved to
the sampler type instead of vec4, causing "No overload function type found"
when passing the result to user-defined functions like decode32(vec4).

Add resolveGenericReturnType() to correctly map GSampler* → GVec4:
  sampler2D/sampler3D/samplerCube → vec4
  isampler2D/isampler3D/...       → ivec4
  usampler2D/usampler3D/...       → uvec4
…exture2DLod signatures

- Simplify resolveGenericReturnType: remove genericParamType param, only
  check if return type is GVec4
- Fix textureCube/textureCubeLod return type: SAMPLER_CUBE → VEC4
- Add missing texture2DLod builtin function registration
- Add texture2DLod test cases to texture-generic.shader
… type

When a builtin generic function (e.g. normalize) receives TypeAny args,
resolvedReturnType stays TypeAny. Previously the else branch returned
the raw EGenType enum value (200), which is neither a concrete type nor
a wildcard, causing downstream user-function overload matching to fail.
…ing CodeGen

When #define values contain struct member access like `o.v_uv` (where `o` is
a Varyings/Attributes/MRT struct variable), the CodeGen now correctly transforms
them to just the property name (e.g. `v_uv`), matching the behavior of direct
struct member access in regular code. Closes #2944.
…uct-access

Verify the actual CodeGen output instead of just checking GLSL compilation:
- #define values with struct member access are correctly transformed
- varying/attribute declarations are emitted for referenced properties
…ions

Add assertions for macro usage in expressions (not just #define transformation):
- Macro as RHS in multiplication, as LHS in assignment
- Macro as function argument in dot(), texture2D()
- Multiple varying properties (v_uv, v_normal) referenced via #define
…ransform

Build a combined _globalStructVarMap in visitShaderProgram by scanning
both vertex and fragment entry functions, so global #define values like
`attr.POSITION` or `o.v_uv` are correctly transformed in all stages.

Rewrite define-struct-access tests to use snapshot file comparison
against expected/ GLSL outputs for clearer verification.
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 (3)
packages/shader-lab/src/parser/builtin/functions.ts (2)

39-60: Well-designed helper for GVec4 resolution.

The mapping logic for sampler variants to vec4/ivec4/uvec4 is correct. One minor inconsistency: when actualParamType is TypeAny, GVec4 defaults to VEC4 rather than returning TypeAny. This differs from non-GVec4 cases (e.g., GenType) which would preserve TypeAny.

If unresolved sampler types should propagate uncertainty downstream, consider:

💡 Optional: Preserve TypeAny for unresolved sampler types
 function resolveGenericReturnType(
   genericReturnType: EGenType,
   actualParamType: NonGenericGalaceanType
 ): NonGenericGalaceanType {
+  if (actualParamType === TypeAny) {
+    return TypeAny;
+  }
   if (genericReturnType === EGenType.GVec4) {
     switch (actualParamType) {

This is likely acceptable as-is since VEC4 is a reasonable default assumption for most shader code.

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

In `@packages/shader-lab/src/parser/builtin/functions.ts` around lines 39 - 60,
The resolveGenericReturnType function treats EGenType.GVec4 specially but
force-defaults unknown/TypeAny sampler inputs to Keyword.VEC4; update
resolveGenericReturnType to preserve uncertainty by checking if actualParamType
=== TypeAny (or the project’s Any type symbol) and return TypeAny immediately
when genericReturnType === EGenType.GVec4, otherwise keep the existing
sampler->IVEC4/UVEC4/VEC4 mapping; refer to resolveGenericReturnType,
EGenType.GVec4, actualParamType, and Keyword.VEC4/IVEC4/UVEC4 to locate where to
add the TypeAny short-circuit.

129-133: Shared state mutation on BuiltinFunction instance is limited to debug-only code path.

The concern about mutating fn._realReturnType on a shared BuiltinFunctionTable instance is technically valid, but has limited scope: getFn() is called in only one location at AST.ts:759, within a #if _VERBOSE debug/verbose-only preprocessor block. The actual type analysis path uses symbolTableStack.lookup() instead.

If the same function is queried with different parameter types within a single analysis pass, earlier resolutions would be overwritten. However, since this code executes only in debug mode and doesn't cache or persist the returned BuiltinFunction reference, the practical risk is minimal.

Consider refactoring to avoid shared state mutation if this debug code ever becomes part of the main analysis path:

♻️ Suggested refactor: return a result tuple
-  static getFn(ident: string, parameterTypes: NonGenericGalaceanType[]): BuiltinFunction | undefined {
+  static getFn(ident: string, parameterTypes: NonGenericGalaceanType[]): { fn: BuiltinFunction; realReturnType: NonGenericGalaceanType } | undefined {
     const list = BuiltinFunctionTable.get(ident);
     if (list) {
       for (let length = list.length, i = 0; i < length; i++) {
         const fn = list[i];
         // ... matching logic ...
         if (found) {
-          fn._realReturnType = isGenericType(fn._returnType)
-            ? resolvedReturnType
-            : (fn._returnType as NonGenericGalaceanType);
-          return fn;
+          const realReturnType = isGenericType(fn._returnType)
+            ? resolvedReturnType
+            : (fn._returnType as NonGenericGalaceanType);
+          return { fn, realReturnType };
         }
       }
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shader-lab/src/parser/builtin/functions.ts` around lines 129 - 133,
The debug path mutates shared BuiltinFunction state by assigning
fn._realReturnType in getFn; instead avoid modifying the shared instance—change
getFn (and callers) to return an immutable result (e.g., a tuple/object like {
fn: BuiltinFunction, resolvedReturnType: GalaceanType }) or return a
shallow-cloned BuiltinFunction with the resolved return type attached, so
callers that need the debug-resolved type use the returned resolvedReturnType
(or the clone) instead of mutating fn._realReturnType; update the call site that
currently expects a BuiltinFunction to accept the new shape and consume
resolvedReturnType for verbose output only.
packages/shader-lab/src/codeGen/VisitorContext.ts (1)

75-88: Silent no-op when property doesn't exist in struct list.

Unlike referenceVarying/referenceAttribute/referenceMRTProp which return errors when the property is not found, this method silently does nothing if propName doesn't exist in the target list.

This is likely intentional for macro-based references (macros can reference properties conditionally via #ifdef), but consider adding a debug log for diagnostics if this causes issues during development.

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

In `@packages/shader-lab/src/codeGen/VisitorContext.ts` around lines 75 - 88, The
method referenceStructPropByName currently silently returns when propName is not
found; update it to emit a debug/diagnostic log before returning so missing
conditional references are visible during development — keep the no-op behavior
but call the VisitorContext's existing logging/diagnostic facility (e.g.,
this.logger or this.diagnostics) with a message that includes role and propName;
modify referenceStructPropByName and ensure the log is at debug/verbose level
and only triggers when props.length === 0.
🤖 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/shader-lab/src/codeGen/VisitorContext.ts`:
- Around line 75-88: The method referenceStructPropByName currently silently
returns when propName is not found; update it to emit a debug/diagnostic log
before returning so missing conditional references are visible during
development — keep the no-op behavior but call the VisitorContext's existing
logging/diagnostic facility (e.g., this.logger or this.diagnostics) with a
message that includes role and propName; modify referenceStructPropByName and
ensure the log is at debug/verbose level and only triggers when props.length ===
0.

In `@packages/shader-lab/src/parser/builtin/functions.ts`:
- Around line 39-60: The resolveGenericReturnType function treats EGenType.GVec4
specially but force-defaults unknown/TypeAny sampler inputs to Keyword.VEC4;
update resolveGenericReturnType to preserve uncertainty by checking if
actualParamType === TypeAny (or the project’s Any type symbol) and return
TypeAny immediately when genericReturnType === EGenType.GVec4, otherwise keep
the existing sampler->IVEC4/UVEC4/VEC4 mapping; refer to
resolveGenericReturnType, EGenType.GVec4, actualParamType, and
Keyword.VEC4/IVEC4/UVEC4 to locate where to add the TypeAny short-circuit.
- Around line 129-133: The debug path mutates shared BuiltinFunction state by
assigning fn._realReturnType in getFn; instead avoid modifying the shared
instance—change getFn (and callers) to return an immutable result (e.g., a
tuple/object like { fn: BuiltinFunction, resolvedReturnType: GalaceanType }) or
return a shallow-cloned BuiltinFunction with the resolved return type attached,
so callers that need the debug-resolved type use the returned resolvedReturnType
(or the clone) instead of mutating fn._realReturnType; update the call site that
currently expects a BuiltinFunction to accept the new shape and consume
resolvedReturnType for verbose output only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: abd38781-e816-40bf-a49c-fc2c7f48470d

📥 Commits

Reviewing files that changed from the base of the PR and between af98e0b and 828752d.

⛔ Files ignored due to path filters (8)
  • tests/src/shader-lab/expected/define-struct-access-global.frag.glsl is excluded by !**/*.glsl
  • tests/src/shader-lab/expected/define-struct-access-global.vert.glsl is excluded by !**/*.glsl
  • tests/src/shader-lab/expected/define-struct-access.frag.glsl is excluded by !**/*.glsl
  • tests/src/shader-lab/expected/define-struct-access.vert.glsl is excluded by !**/*.glsl
  • tests/src/shader-lab/shaders/define-struct-access-global.shader is excluded by !**/*.shader
  • tests/src/shader-lab/shaders/define-struct-access.shader is excluded by !**/*.shader
  • tests/src/shader-lab/shaders/generic-return-type.shader is excluded by !**/*.shader
  • tests/src/shader-lab/shaders/texture-generic.shader is excluded by !**/*.shader
📒 Files selected for processing (7)
  • packages/shader-lab/src/Preprocessor.ts
  • packages/shader-lab/src/codeGen/CodeGenVisitor.ts
  • packages/shader-lab/src/codeGen/GLESVisitor.ts
  • packages/shader-lab/src/codeGen/VisitorContext.ts
  • packages/shader-lab/src/parser/AST.ts
  • packages/shader-lab/src/parser/builtin/functions.ts
  • tests/src/shader-lab/ShaderLab.test.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/src/shader-lab/ShaderLab.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shader-lab/src/codeGen/GLESVisitor.ts

…cro scanning

- Suppress `uniform` output for global struct-typed variables (e.g. `Varyings o;`)
- Register global struct vars in both per-function and cross-stage maps
- Unify macro member access scanning into callback-based _forEachMacroMemberAccess
- Add registerStructVar() encapsulation in VisitorContext
- Add Cocos VSOutput pattern test (global-varying-var)
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/shader-lab/src/codeGen/CodeGenVisitor.ts`:
- Around line 408-426: The function-local macro limitation is caused by
_collectStructVars wiping context._structVarMap (so function scope loses
globals) while visitGlobalVariableDeclaration stores globals in
context._globalStructVarMap; fix by making struct resolution fall back to
globals or by merging maps: either update _transformMacroDefineValue (used by
defaultCodeGen) to resolve structVarMap as overrideMap ?? context._structVarMap
?? context._globalStructVarMap, or change _collectStructVars to preserve/merge
entries from context._globalStructVarMap into context._structVarMap (so global
struct variables remain available for function-local `#define`), keeping
visitGlobalVariableDeclaration behavior unchanged.
🪄 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: 07e3a56a-3c7c-41dd-b970-efc5baa53b31

📥 Commits

Reviewing files that changed from the base of the PR and between f37867e and 80e6e3e.

⛔ Files ignored due to path filters (1)
  • tests/src/shader-lab/shaders/global-varying-var.shader is excluded by !**/*.shader
📒 Files selected for processing (4)
  • packages/shader-lab/src/codeGen/CodeGenVisitor.ts
  • packages/shader-lab/src/codeGen/GLESVisitor.ts
  • packages/shader-lab/src/codeGen/VisitorContext.ts
  • tests/src/shader-lab/ShaderLab.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/src/shader-lab/ShaderLab.test.ts
  • packages/shader-lab/src/codeGen/VisitorContext.ts
  • packages/shader-lab/src/codeGen/GLESVisitor.ts

zhuxudong and others added 4 commits March 27, 2026 01:06
…version

GLES100 visitJumpStatement converted `return expr;` to `gl_FragColor = expr`
without a trailing semicolon, causing WebGL compilation errors. Only triggered
when fragment entry returns vec4 (Cocos pattern), not void (standard Galacean).
zhuxudong and others added 10 commits March 27, 2026 17:55
…eprocessor

#if !0 and similar expressions now work correctly, matching C/GLSL preprocessor behavior.
…atrix

The viewMatrix getter intentionally ignores the camera entity's world scale
(using Matrix.rotationTranslation), but _getInvViewProjMat() was using the
full entity.transform.worldMatrix which includes inherited scale. This
inconsistency causes screenPointToRay to produce incorrect world-space rays
when the camera inherits scale from a parent entity (e.g. UICanvas in
ScreenSpaceCamera mode with camera as a child of canvas).

Closes #2748

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify that screenPointToRay and viewport-world round-trip produce
correct results when the camera inherits non-identity scale from a
parent entity. Without the fix, the round-trip deviates by the
inherited scale factor (e.g. 105 -> 107.5 at scale 1.5).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ReflectionParser 解析 IComponentRef(entityPath + componentType)时,
目标组件可能在 GLB clone 的子 entity 上而非 clone 根 entity 自身。
getComponents 找不到时 fallback 到 getComponentsIncludeChildren。
CloneManager: 当 source 和 target 属性是同类型 Object 实例(如 Vector4)时,
自动升级为 DeepClone,避免 prefab 模板的引用覆盖克隆体的独立实例。
新增 Map/Set 类型的 deep clone 支持。

ModelMesh: throw string 改为 throw Error 以获得正确堆栈。
AnimatorState.speed is part of the shared AnimatorController asset.
Modifying it at runtime pollutes all Animator instances sharing the
same controller, causing animation speed corruption after cloning.

- Add speed field to AnimatorStatePlayData, initialized from AnimatorState.speed on reset
- Add proxy properties (name/clip/wrapMode/transitions/addStateMachineScript)
- Change speed calculation to playData.speed * animator.speed
- findAnimatorState now returns per-instance AnimatorStatePlayData
- Export AnimatorStatePlayData for consumer code
When sizeMode is set to Automatic, the UITransform size is automatically
synchronized to the sprite's natural dimensions when the sprite changes.
This matches Cocos Creator's Sprite.SizeMode.TRIMMED behavior.

- Add SpriteSizeMode enum (Custom / Automatic)
- Add sizeMode property to Image with getter/setter
- Sync UITransform.size in set sprite and _onSpriteChange
- Export SpriteSizeMode from component index
@GuoLei1990 GuoLei1990 marked this pull request as draft April 4, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants