Skip to content

refactor: migrate all shaders from raw GLSL to ShaderLab format#347

Open
zhuxudong wants to merge 5 commits intogalacean:dev/2.0from
zhuxudong:refactor/glsl-to-shaderlab
Open

refactor: migrate all shaders from raw GLSL to ShaderLab format#347
zhuxudong wants to merge 5 commits intogalacean:dev/2.0from
zhuxudong:refactor/glsl-to-shaderlab

Conversation

@zhuxudong
Copy link
Copy Markdown
Member

@zhuxudong zhuxudong commented Apr 20, 2026

Summary

  • Convert all 17 shader files from raw GLSL (Shader.create(name, vs, fs)) to ShaderLab format (Shader.create(shaderLabSource))
  • Replace attribute/varying/uniform with struct Attributes/Varyings and bare declarations
  • Replace #include <xxx> angle-bracket macros with explicit calculateBlendShape() / getSkinMatrix() calls
  • Replace old include paths with engine ShaderLibrary paths ("Common/Common.glsl", "Skin/Skin.glsl", etc.)
  • Fix Shader.find("pbr")Shader.find("PBR") and PBR pass index passes[0]passes[2]
  • Fix advanced-shader (Eye/SSS/Hair) include paths
  • Consolidate separate .glsl files into .ts ShaderLab strings
  • Delete 12 stale files (.glsl, global.d.ts, vertex.ts, fragment.ts)
  • Keep render states in TS material code, not in shader declarations
  • BakePBRMaterial: rewrite using #include "PBR/ForwardPassPBR.glsl" with lightmap extension

Dependencies

Test plan

  • PlainColor/Icon/Grid/Wireframe/TBN 材质渲染正常
  • Outline 高亮、FrameBuffer Picker 拾取正常
  • Line/Dash 线条渲染正常
  • Water/Waterfall/WaterRipple 水面效果正常
  • PlanarShadow 平面阴影正常
  • SkeletonViewer 骨骼可视化正常
  • BakePBR lightmap 渲染正常
  • BoxSelection 框选正常

---

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Refactor**
* Unified and modernized shader definitions across rendering materials for more consistent visuals and stability.
* Made shader registration idempotent to reduce redundant initialization and improve runtime efficiency.
* **Chores**
* Small resource-loading adjustment for icon assets to improve reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Convert all shader code to ShaderLab syntax:
- Wrap in Shader/SubShader/Pass structure
- Replace attribute/varying/uniform with struct Attributes/Varyings
- Replace #include <xxx> macros with explicit vertex transform code
- Replace old #include paths with engine ShaderLibrary paths
- Change Shader.create(name, vs, fs) to Shader.create(shaderLabSource)
- Consolidate separate .glsl files into .ts ShaderLab strings
- Fix advanced-shader include paths for future extension use
- Keep render states in TS material code (not in shader)

Deleted: 10 .glsl files, 4 global.d.ts, bake-pbr vertex/fragment.ts
BakePBRMaterial skipped (TODO: full PBR pipeline migration)
…igration

- Restore global.d.ts for *.shader and *.wasm module declarations
- Add ts-ignore for ShaderPass single-arg constructor (engine not yet published)
- Update AssetType.Texture2D to AssetType.Texture to match engine API
…ions

- PlanarShadowShaderFactory: fix lowercase "pbr" to "PBR"
- PlainColorMaterial, FramebufferPicker, BoxSelectionSSMaterial:
  add explicit struct Varyings declaration
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Walkthrough

Consolidated numerous shaders by replacing separate vertex/fragment GLSL sources and external .glsl imports with inline ShaderLab-style shader strings, migrated to typed Attributes/Varyings with vert()/frag() entry points, and made shader registration idempotent via Shader.find(...) || Shader.create(...).

Changes

Cohort / File(s) Summary
PBR / BakePBR
packages/custom-material/src/bake-pbr/BakePBRMaterial.ts, packages/custom-material/src/bake-pbr/fragment.ts, packages/custom-material/src/bake-pbr/vertex.ts
Inlined previously external vertex/fragment GLSL into a single shaderSource; removed standalone vertex.ts/fragment.ts exports; fragment logic folded into the material with explicit radiance/IBL/lightmap/transmission/emissive/fog handling; conditional shader registration added.
Grid / Plain Color / Water family
packages/custom-material/src/grid/GridMaterial.ts, packages/custom-material/src/plain-color/PlainColorMaterial.ts, packages/custom-material/src/water/... (WaterMaterial.ts, WaterRippleMaterial.ts, WaterfallMaterial.ts)
Rewrote shaders as single ShaderLab strings using Attributes/Varyings and vert()/frag() functions; preserved rendering logic (grid, plain color, water effects); switched to idempotent `Shader.find(...)
Planar Shadow
packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts
Consolidated planar shadow pass into one shader source with typed attributes/varyings; moved skinning into vert; updated PBR base shader pass index and conditional shader creation.
Lines / Dash / Line
packages/lines/src/line/material/dashShader.ts, packages/lines/src/line/material/lineShader.ts
Merged vertex/fragment into unified shader DSL, introduced Attributes/Varyings, kept fragment discard/alpha logic, and added conditional shader lookup/creation.
Geometry Sketch / TBN / Wireframe
packages/geometry-sketch/src/material/GeometryShader.ts, TBNMaterial.ts, WireframeMaterial.ts
Adjusted GLSL declarations (removed uniform qualifiers on some samplers), and consolidated several shaders into ShaderLab-style sources with structured vert()/frag() and conditional registration.
Framebuffer Picker & Globals
packages/framebuffer-picker/src/FramebufferPicker.ts, packages/framebuffer-picker/src/global.d.ts
Replaced external .glsl imports with an inline colorShaderSource and conditional creation; removed *.glsl ambient module declaration.
Outline Manager & Globals
packages/outline/src/OutlineManager.ts, packages/outline/src/global.d.ts
Inlined outline and replace shaders into OutlineManager.ts; changed to idempotent shader registration; removed *.glsl ambient module declaration.
Controls / Box Selection
packages/controls/src/box-selection/BoxSelectionSSMaterial.ts
Refactored shader creation to a single embedded shader string and replaced unconditional creation with conditional registration; preserved uniform names and fragment logic.
Gizmo / Icon
packages/gizmo/src/icon/IconMaterial.ts, packages/gizmo/src/icon/Icon.ts
Icon shader consolidated to ShaderLab-style string with vert()/frag() and structured attributes; Icon.texture loader now uses AssetType.Texture instead of AssetType.Texture2D.
Outline / Postprocess & Replace
packages/outline/src/OutlineManager.ts
Inlined postprocess and replace shaders; switched to `Shader.find(...)
Skeleton Viewer
packages/skeleton-viewer/src/SkeletonViewer.ts
Replaced vertex/fragment creation with a ShaderLab-style inline shader using Attributes/Varyings and conditional creation; removed non-functional comments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I stitched the shaders, smooth and bright,

Vert and Frag now share one light.
No loose imports rustling in the hedge,
One source, one song — I nibbled the edge.
Hooray for inline strings and tidy night!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: migration of shaders from raw GLSL to ShaderLab format, which is the primary objective across all 17 files in this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

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: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/gizmo/src/icon/Icon.ts (1)

60-71: ⚠️ Potential issue | 🟠 Major

Unhandled rejection and stale-resolver race in async texture load.

Two concerns on the URL branch:

  1. The promise has no .catch, so a failed load becomes an unhandled rejection with no recovery or diagnostic.
  2. If texture is reassigned (e.g., URL → different URL, or URL → Texture2D) before the previous load resolves, the stale resolver will still run and overwrite _material.baseTexture with the obsolete texture. Guard the assignment against this._texture === value at resolve time.
🛡️ Proposed fix
       } else {
-        this.engine.resourceManager.load({ url: value, type: AssetType.Texture }).then((texture: Texture2D) => {
-          this._material.baseTexture = texture;
-        });
+        this.engine.resourceManager
+          .load<Texture2D>({ url: value, type: AssetType.Texture })
+          .then((texture: Texture2D) => {
+            // Ignore stale result if `texture` was reassigned in the meantime.
+            if (this._texture !== value) return;
+            this._material.baseTexture = texture;
+          })
+          .catch((err) => {
+            console.error(`Icon failed to load texture: ${value}`, err);
+          });
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gizmo/src/icon/Icon.ts` around lines 60 - 71, The texture setter's
async URL branch currently lacks error handling and can be conditionally
overwritten by stale resolves; update the URL branch in the set texture(value:
string | Texture2D) method to (1) capture the expected value (e.g., const
expected = value) before calling engine.resourceManager.load({ url: value, type:
AssetType.Texture }) and in the .then handler only assign
this._material.baseTexture = texture if this._texture === expected, and (2)
attach a .catch to the promise to log or handle load errors (use process/error
logger or throw as appropriate) to avoid unhandled rejections; ensure the same
guard is used if converting to a Texture2D synchronously when value instanceof
Texture2D.
🧹 Nitpick comments (13)
packages/controls/src/box-selection/BoxSelectionSSMaterial.ts (1)

20-24: Consider initializing Varyings before returning from vert.

Line 21 creates Varyings v and returns it (Line 23) without assigning v._placeholder. While the field is not used in the fragment shader, explicitly initializing struct members before return is a defensive programming practice that can prevent portability issues on stricter GLSL backends.

Suggested improvement
       Varyings vert(Attributes attr) {
         Varyings v;
+        v._placeholder = 0.0;
         gl_Position = vec4(attr.POSITION, 1.0);
         return v;
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/controls/src/box-selection/BoxSelectionSSMaterial.ts` around lines
20 - 24, The Varyings struct instance 'v' in the vertex function 'vert' is
returned without initializing its member(s); initialize v._placeholder (or all
Varyings fields) before returning from vert to ensure defined behavior across
GLSL backends—locate the function vert and the local variable v in
BoxSelectionSSMaterial.ts and set v._placeholder (or zero/appropriate default
for each field) prior to the return statement.
packages/geometry-sketch/src/material/TBNMaterial.ts (2)

14-17: Consolidate uniform declarations at the top of the Pass.

material_BaseColor is declared on Line 87 between vert and frag, while the other uniforms (u_lineScale, camera_VPMat, u_worldMatrix, u_worldNormal) are grouped at Lines 14–17. Moving material_BaseColor up with the rest keeps uniform declarations co-located and matches the pattern used elsewhere in the PR.

♻️ Proposed grouping
       float u_lineScale;
       mat4 camera_VPMat;
       mat4 u_worldMatrix;
       mat4 u_worldNormal;
+      vec4 material_BaseColor;
...
-      vec4 material_BaseColor;
-
       void frag(Varyings v) {
         gl_FragColor = material_BaseColor;
       }

Also applies to: 87-87

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

In `@packages/geometry-sketch/src/material/TBNMaterial.ts` around lines 14 - 17,
Uniform declarations are split: move the material_BaseColor uniform declaration
so it is co-located with the other uniforms (u_lineScale, camera_VPMat,
u_worldMatrix, u_worldNormal) at the top of the Pass; locate the
material_BaseColor declaration between vert and frag and cut/paste it up with
those uniforms to keep all uniform declarations together and follow the
project's pattern.

35-37: Nit: Varyings returned uninitialized.

Varyings only contains _placeholder and vert() returns v without assigning it. The frag stage never reads it (it only uses the material_BaseColor uniform), so this is functionally safe, but you could drop the placeholder once your ShaderLab version allows an empty struct, or initialize it (Varyings v; v._placeholder = 0.0;) to silence potential driver warnings.

Also applies to: 84-84

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

In `@packages/geometry-sketch/src/material/TBNMaterial.ts` around lines 35 - 37,
The Varyings struct is left uninitialized because vert() returns a Varyings v
without assigning its _placeholder field; either initialize the struct in vert()
(e.g., set v._placeholder = 0.0 before return) or remove the placeholder field
once empty structs are supported to avoid driver warnings; apply the same fix to
the other Varyings occurrence referenced in this file so all vert() returns
return initialized Varyings instances.
packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts (2)

190-190: Prefer @ts-expect-error over @ts-ignore.

@ts-expect-error will fail the build as soon as the engine publishes the matching ShaderPass single-arg overload, guaranteeing the suppression is cleaned up. @ts-ignore silently lingers forever. Minor, but particularly useful since the comment explicitly says this is a temporary workaround.

-// `@ts-ignore` - ShaderPass single-arg constructor supported in engine but not yet published
+// `@ts-expect-error` - ShaderPass single-arg constructor supported in engine but not yet published
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts` at
line 190, Replace the inline TypeScript suppression at the ShaderPass single-arg
constructor site by changing the comment token from `@ts-ignore` to
`@ts-expect-error` so the build will fail once the engine publishes the matching
overload; update the adjacent explanatory comment (the one referencing
"ShaderPass single-arg constructor supported in engine but not yet published")
if needed to keep context while ensuring the suppression uses `@ts-expect-error`
instead of `@ts-ignore` in PlanarShadowShaderFactory where ShaderPass is
constructed.

21-22: Doc wording nit.

"Replace material Shader and initialization." / "Material to replace and initialization." reads awkwardly. Consider: "Replace the material's shader and initialize its render state." and "The material to configure."

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

In `@packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts`
around lines 21 - 22, Update the JSDoc wording to be clearer: change "Replace
material Shader and initialization." to "Replace the material's shader and
initialize its render state." and change "Material to replace and
initialization." to "The material to configure."; locate these strings in the
JSDoc for the PlanarShadowShaderFactory (or the function/method that
replaces/configures the material) and update the comment blocks accordingly to
match the suggested phrasing.
packages/custom-material/src/bake-pbr/BakePBRMaterial.ts (1)

41-107: Duplicated PBR main-loop will drift from the engine's ForwardPassPBR.

BakePBRFragment re-implements the whole surface/BSDF/shadow/direct-light/IBL/transmission/fog pipeline that PBR/ForwardPassPBR.glsl already provides, and the #include is effectively only being used to pull in helper functions. Any future engine-side change to the PBR pipeline (new BSDF inputs, additional light types, shadow API tweaks, output-format changes) won't propagate here and will silently diverge — matching the "partial/TODO" note in the PR description. Consider exposing a lightmap hook in the engine's forward pass (e.g. a weak-symbol / macro injection point like PBR_INDIRECT_DIFFUSE_OVERRIDE) so this material can reduce to just the vertex entry + a small override function instead of copy-pasting the main body.

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

In `@packages/custom-material/src/bake-pbr/BakePBRMaterial.ts` around lines 41 -
107, BakePBRFragment duplicates the entire PBR pipeline from
PBR/ForwardPassPBR.glsl (surface/BSDF/shadow/direct-light/IBL/transmission/fog)
which will diverge from the engine; instead refactor to call into the engine
forward pass and only inject the lightmap override. Replace the body of
BakePBRFragment so it uses the included forward pass entry (keep Varyings
BakePBRVertex / PBRVertex) and implement a small override hook (e.g., implement
or call a macro like PBR_INDIRECT_DIFFUSE_OVERRIDE or a provided engine hook) to
apply texture2D(u_lightMapTexture, lightMapUV) * u_lightMapIntensity *
BRDF_Diffuse_Lambert(bsdfData.diffuseColor) to the indirect/diffuse term; remove
or delegate usages of initBSDFData, evaluateDirectRadiance, evaluateIBL,
sampleShadowMap, evaluateTransmission and fog so the engine implementation
remains authoritative.
packages/framebuffer-picker/src/FramebufferPicker.ts (1)

83-85: Nit: Varyings carries an unused _placeholder field.

The fragment shader doesn't read any varying, and vert returns v without assigning _placeholder, so the interpolated value is indeterminate (harmless here, just noise). If ShaderLab permits an empty struct you could drop the field; otherwise, a short comment explaining why the placeholder exists would help future readers.

Optional tweak
       struct Varyings {
-        float _placeholder;
+        float _placeholder; // ShaderLab requires a non-empty Varyings struct; unused by frag.
       };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/framebuffer-picker/src/FramebufferPicker.ts` around lines 83 - 85,
The Varyings struct contains an unused float _placeholder which produces
indeterminate interpolants; either remove the field if ShaderLab allows an empty
varying struct, or explicitly initialize it in the vertex function (the vert
function that returns v) to a deterministic value (e.g., 0.0) and/or add a
one-line comment on why the placeholder exists so readers understand it's
intentional; update the declaration of Varyings and the vert function (or add
the comment next to _placeholder) accordingly.
packages/custom-material/src/grid/GridMaterial.ts (1)

47-47: Consider consolidating includes at the top of the Pass.

#include "Common/Transform.glsl" is placed between the vert entry function and the fragment-side uniforms/helpers. Functionally this is fine in ShaderLab (pass body is concatenated), but splitting includes makes it harder to see, at a glance, what symbols are available to vert vs frag. Moving it up next to the Common/Common.glsl include would match the convention used by the other materials migrated in this PR.

♻️ Proposed refactor
       `#include` "Common/Common.glsl"
+      `#include` "Common/Transform.glsl"
 
-      mat4 camera_ViewInvMat;
-      mat4 camera_ProjMat;
-
       struct Attributes {
@@
         return v;
       }
 
-      `#include` "Common/Transform.glsl"
-
       float u_far;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/grid/GridMaterial.ts` at line 47, The include
"#include \"Common/Transform.glsl\"" is currently placed after the vert entry
function which splits shared symbols between vertex and fragment code; move this
include up next to the existing "#include \"Common/Common.glsl\"" in
GridMaterial.ts so both the vert entry function and the fragment-side
uniforms/helpers (frag) see the same transform definitions, preserving the
original pass semantics while matching the include ordering convention used by
other materials.
packages/geometry-sketch/src/material/WireframeMaterial.ts (1)

14-33: Remove dead uniforms and redundant attribute members.

Several declarations in this shader block are unused and add confusion:

  • u_lineScale (Line 14) and u_worldNormal (Line 17) are declared but never referenced anywhere in vert/frag. They appear to be leftovers from the pre‑ShaderLab version.
  • Inside struct Attributes, the POSITION, NORMAL, and TANGENT members are dead from the vertex body's perspective: the body refers to bare POSITION / NORMAL / TANGENT on lines 52/55/57, which are locals injected by ${geometryTextureVert} (texture‑sourced geometry), not attr.POSITION etc. Keeping them in Attributes still forces the engine to look up / bind those vertex‑buffer attributes on the draw, which is wasted work for this texture‑fed geometry.

Only JOINTS_0 / WEIGHTS_0 are actually consumed (via getSkinMatrix(attr)), so the struct can shrink substantially.

♻️ Suggested cleanup
-      float u_lineScale;
       mat4 camera_VPMat;
       mat4 u_worldMatrix;
-      mat4 u_worldNormal;

       ${geometryTextureDefine}

       struct Attributes {
-        vec3 POSITION;
         `#ifdef` RENDERER_HAS_SKIN
           vec4 JOINTS_0;
           vec4 WEIGHTS_0;
         `#endif`
-        `#ifdef` RENDERER_HAS_NORMAL
-          vec3 NORMAL;
-        `#endif`
-        `#ifdef` RENDERER_HAS_TANGENT
-          vec4 TANGENT;
-        `#endif`
       };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/geometry-sketch/src/material/WireframeMaterial.ts` around lines 14 -
33, Remove the unused uniforms and redundant attribute members: delete the
declarations u_lineScale and u_worldNormal from the uniform block, and simplify
the Attributes struct to only include JOINTS_0 and WEIGHTS_0 (since POSITION,
NORMAL, and TANGENT are provided by the injected ${geometryTextureVert} locals
and not via attr.*). Keep getSkinMatrix(attr) usage intact and ensure any code
paths that expect attr.POSITION/NORMAL/TANGENT instead use the texture-sourced
POSITION/NORMAL/TANGENT provided by geometryTextureVert so the engine no longer
binds those unused vertex attributes.
packages/lines/src/line/material/lineShader.ts (2)

18-36: v_direction varying is write-only; can be removed.

v.v_direction is assigned in vert but never read in either stage, and frag doesn't reference it. It's dead state passing through the pipeline.

♻️ Proposed change
       struct Varyings {
         vec2 v_origin;
         vec2 v_position;
-        float v_direction;
         float v_part;
       };

       Varyings vert(Attributes attr) {
         Varyings v;
-        v.v_direction = attr.a_data.x;
         v.v_part = attr.a_data.y;
-        float layer_index = 1.0;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/lines/src/line/material/lineShader.ts` around lines 18 - 36, The
Varyings struct contains an unused varying v_direction which is written in vert
but never read; remove the dead varying by deleting its declaration in Varyings
and removing the assignment v.v_direction = attr.a_data.x from the vert function
(ensure no other code references v_direction or relies on attr.a_data.x in this
shader). This keeps Varyings minimal and avoids passing unused state between
stages.

44-58: Unused finalColor local.

vec4 finalColor; is declared but never written or read. Minor cleanup.

♻️ Proposed change
       void frag(Varyings v) {
-        vec4 finalColor;
         if (u_cap == 0 && v.v_part == IS_CAP) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/lines/src/line/material/lineShader.ts` around lines 44 - 58, The
fragment shader function frag declares an unused local variable vec4 finalColor;
— remove that declaration from the frag(Varyings v) function (and any related
dead code) so only needed variables like u_color, u_cap, u_join, v.v_part,
v.v_position, v.v_origin, and u_width are used; ensure gl_FragColor = u_color;
remains as the final output and run a quick build/lint to confirm no other
references to finalColor exist.
packages/lines/src/line/material/dashShader.ts (1)

20-48: v_direction varying is never read in the fragment stage.

v.v_direction is written in vert (and used locally there) but never consumed by frag. It still costs an interpolator and vertex attribute copy. Consider dropping it from Varyings and treating it as a local float inside vert instead.

♻️ Proposed change
       struct Varyings {
         vec2 v_origin;
         vec2 v_position;
-        float v_direction;
         float v_part;
         vec2 v_tex;
       };

       Varyings vert(Attributes attr) {
         Varyings v;
-        v.v_direction = attr.a_data.x;
+        float v_direction = attr.a_data.x;
         v.v_part = attr.a_data.y;
         float layer_index = 1.0;

         v.v_origin = attr.a_pos;

         float texcoord_y = 0.0;

         texcoord_y = attr.a_lengthsofar / (u_dash.x + u_dash.y);
-        if (v.v_direction == 1.0) {
+        if (v_direction == 1.0) {
           v.v_tex = vec2(1.0, texcoord_y);
         } else {
           v.v_tex = vec2(0.0, texcoord_y);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/lines/src/line/material/dashShader.ts` around lines 20 - 48, The
Varyings struct currently includes v_direction which is written in vert but
never read in frag; remove v_direction from Varyings and instead read
attr.a_data.x into a local float (e.g., direction) inside vert, then use that
local to set v.v_tex; update vert to stop assigning v.v_direction and delete the
v.v_direction declaration in Varyings so you avoid wasting an interpolator and
vertex attribute copy (leave v_part, v_origin, v_position, v_tex unchanged).
packages/custom-material/src/plain-color/PlainColorMaterial.ts (1)

58-60: Consider removing the unused _placeholder field from the empty Varyings struct. Empty Varyings structs are syntactically valid in Galacean ShaderLab, so the placeholder is unnecessary. The vertex shader doesn't populate any data, and the fragment shader doesn't use the Varyings parameter, making this field a wasteful use of an interpolator slot.

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

In `@packages/custom-material/src/plain-color/PlainColorMaterial.ts` around lines
58 - 60, The empty Varyings struct contains an unnecessary interpolator field
`_placeholder`; remove `_placeholder` from the `struct Varyings` declaration and
update the vertex and fragment shader function signatures that reference
`Varyings` (in this file's shader code) to use an empty `Varyings` type instead,
ensuring no code references `_placeholder` remain; this avoids consuming an
interpolator slot while keeping the Galacean ShaderLab-compatible empty struct
`Varyings`.
🤖 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/custom-material/src/bake-pbr/BakePBRMaterial.ts`:
- Around line 99-106: The fragment currently writes gl_FragColor directly in
BakePBRFragment without applying the documented ACES tone mapping or using an
exposure uniform; add a uniform float (e.g. uExposure) and apply it to the
accumulated HDR color, then run the ACES tone mapping helper (use the existing
acesToneMapping/ACESFilm helper or add one if missing) and convert to sRGB
(linearToSRGB or equivalent) before assigning gl_FragColor; update
BakePBRFragment to multiply color.rgb by uExposure, pass the result through the
ACES tone mapping function, then set gl_FragColor = vec4(toneMappedColor,
color.a). If tone mapping is intentionally omitted instead, update the README to
remove the ACES/exposure claims.

In `@packages/custom-material/src/grid/GridMaterial.ts`:
- Around line 11-12: Remove the redundant uniform redeclarations for
camera_ViewInvMat and camera_ProjMat from GridMaterial shader source so the
shader relies on the shared includes (e.g., Common/Common.glsl and
Common/Transform.glsl) like the other migrated shaders; specifically delete the
two lines that declare mat4 camera_ViewInvMat; and mat4 camera_ProjMat; and
ensure references to camera_ViewMat and camera_ProjectionParams remain unchanged
so the common includes supply those uniforms consistently with outline, gizmo,
plain-color, and geometry-sketch shaders.

In `@packages/custom-material/src/plain-color/PlainColorMaterial.ts`:
- Around line 81-93: The fragment shader references material_AlphaCutoff inside
the frag function under the MATERIAL_IS_ALPHA_CUTOFF guard but never declares
it; add a declaration for material_AlphaCutoff (float) next to the existing vec4
material_BaseColor variable so the shader compiles when MATERIAL_IS_ALPHA_CUTOFF
is defined — update the declarations that contain material_BaseColor to also
declare material_AlphaCutoff so frag can use it safely.

In `@packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts`:
- Around line 190-194: The module currently calls Shader.find("PBR") and
constructs new ShaderPass(planarShadowPassSource) at import time which can NPE
if PBR isn't registered and produces orphan passes; fix by moving the
ShaderPass(planarShadowPassSource) construction and the
Shader.create("planarShadowShader", ...) call inside a guarded lazy initializer
function (e.g., registerPlanarShadowShader()) that first calls
Shader.find("PBR"), checks for null, and only then accesses
.subShaders[0].passes[2] and creates the shader; update replaceShader to call
registerPlanarShadowShader() before using the shader so registration is
deterministic and import-time side-effects are eliminated.
- Around line 108-114: In the Attributes struct inside PlanarShadowShaderFactory
(the struct named Attributes that currently declares vec4 POSITION), change the
POSITION field type from vec4 to vec3 so it matches the engine's glTF attribute
binding and other ShaderLab materials; update the declaration of POSITION in
Attributes to vec3 POSITION and leave the shader code that uses
vec4(attr.POSITION.xyz, 1.0) unchanged.

In `@packages/geometry-sketch/src/material/WireframeMaterial.ts`:
- Around line 15-17: Remove or guard the local uniform declaration camera_VPMat
in WireframeMaterial to avoid shadowing the engine-provided uniform from
Common/Transform.glsl; either delete the camera_VPMat declaration or wrap it in
a macro/ifdef that only defines it when the engine does not provide it, and keep
u_worldMatrix and u_worldNormal as-is (they are custom) while continuing to use
the engine's renderer_ModelMat where appropriate.
- Around line 41-45: The shader in WireframeMaterial.ts uses gl_VertexID (seen
in the snippet with gl_VertexID, getIndicesElement, u_indicesTextureWidth) which
requires GLSL ES 3.0/WebGL2; update the shader source to either prepend
"#version 300 es" at the top to enforce WebGL2 or replace gl_VertexID usage with
an explicit vertex attribute (e.g., pass a flat int/float index attribute from
the vertex buffer and use that instead of gl_VertexID) so it will compile on
WebGL1; also update any surrounding code that constructs the program to
document/require WebGL2 if you choose the version route.

In `@packages/gizmo/src/icon/Icon.ts`:
- Line 66: The load call using this.engine.resourceManager.load({ url: value,
type: AssetType.Texture }) is using a non-existent AssetType; change the asset
type to AssetType.Texture2D so the resource manager returns a Texture2D (update
the object literal to use type: AssetType.Texture2D), keeping the existing
then((texture: Texture2D) => ...) handler in the Icon class to ensure correct
typing and runtime resolution.

In `@packages/outline/src/OutlineManager.ts`:
- Around line 176-211: The shader is missing the Varyings struct used by
outlineReplaceShaderSource's vert and frag; add a Varyings declaration above the
vert function (in the outlineReplaceShaderSource string) that defines every
varying the vertex shader writes and the fragment shader reads (e.g., any
TEXCOORD, COLOR, or custom varyings used by frag), using the correct
interpolation qualifiers/precision as used elsewhere in our shaders so field
names/types match references in vert and frag.

---

Outside diff comments:
In `@packages/gizmo/src/icon/Icon.ts`:
- Around line 60-71: The texture setter's async URL branch currently lacks error
handling and can be conditionally overwritten by stale resolves; update the URL
branch in the set texture(value: string | Texture2D) method to (1) capture the
expected value (e.g., const expected = value) before calling
engine.resourceManager.load({ url: value, type: AssetType.Texture }) and in the
.then handler only assign this._material.baseTexture = texture if this._texture
=== expected, and (2) attach a .catch to the promise to log or handle load
errors (use process/error logger or throw as appropriate) to avoid unhandled
rejections; ensure the same guard is used if converting to a Texture2D
synchronously when value instanceof Texture2D.

---

Nitpick comments:
In `@packages/controls/src/box-selection/BoxSelectionSSMaterial.ts`:
- Around line 20-24: The Varyings struct instance 'v' in the vertex function
'vert' is returned without initializing its member(s); initialize v._placeholder
(or all Varyings fields) before returning from vert to ensure defined behavior
across GLSL backends—locate the function vert and the local variable v in
BoxSelectionSSMaterial.ts and set v._placeholder (or zero/appropriate default
for each field) prior to the return statement.

In `@packages/custom-material/src/bake-pbr/BakePBRMaterial.ts`:
- Around line 41-107: BakePBRFragment duplicates the entire PBR pipeline from
PBR/ForwardPassPBR.glsl (surface/BSDF/shadow/direct-light/IBL/transmission/fog)
which will diverge from the engine; instead refactor to call into the engine
forward pass and only inject the lightmap override. Replace the body of
BakePBRFragment so it uses the included forward pass entry (keep Varyings
BakePBRVertex / PBRVertex) and implement a small override hook (e.g., implement
or call a macro like PBR_INDIRECT_DIFFUSE_OVERRIDE or a provided engine hook) to
apply texture2D(u_lightMapTexture, lightMapUV) * u_lightMapIntensity *
BRDF_Diffuse_Lambert(bsdfData.diffuseColor) to the indirect/diffuse term; remove
or delegate usages of initBSDFData, evaluateDirectRadiance, evaluateIBL,
sampleShadowMap, evaluateTransmission and fog so the engine implementation
remains authoritative.

In `@packages/custom-material/src/grid/GridMaterial.ts`:
- Line 47: The include "#include \"Common/Transform.glsl\"" is currently placed
after the vert entry function which splits shared symbols between vertex and
fragment code; move this include up next to the existing "#include
\"Common/Common.glsl\"" in GridMaterial.ts so both the vert entry function and
the fragment-side uniforms/helpers (frag) see the same transform definitions,
preserving the original pass semantics while matching the include ordering
convention used by other materials.

In `@packages/custom-material/src/plain-color/PlainColorMaterial.ts`:
- Around line 58-60: The empty Varyings struct contains an unnecessary
interpolator field `_placeholder`; remove `_placeholder` from the `struct
Varyings` declaration and update the vertex and fragment shader function
signatures that reference `Varyings` (in this file's shader code) to use an
empty `Varyings` type instead, ensuring no code references `_placeholder`
remain; this avoids consuming an interpolator slot while keeping the Galacean
ShaderLab-compatible empty struct `Varyings`.

In `@packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts`:
- Line 190: Replace the inline TypeScript suppression at the ShaderPass
single-arg constructor site by changing the comment token from `@ts-ignore` to
`@ts-expect-error` so the build will fail once the engine publishes the matching
overload; update the adjacent explanatory comment (the one referencing
"ShaderPass single-arg constructor supported in engine but not yet published")
if needed to keep context while ensuring the suppression uses `@ts-expect-error`
instead of `@ts-ignore` in PlanarShadowShaderFactory where ShaderPass is
constructed.
- Around line 21-22: Update the JSDoc wording to be clearer: change "Replace
material Shader and initialization." to "Replace the material's shader and
initialize its render state." and change "Material to replace and
initialization." to "The material to configure."; locate these strings in the
JSDoc for the PlanarShadowShaderFactory (or the function/method that
replaces/configures the material) and update the comment blocks accordingly to
match the suggested phrasing.

In `@packages/framebuffer-picker/src/FramebufferPicker.ts`:
- Around line 83-85: The Varyings struct contains an unused float _placeholder
which produces indeterminate interpolants; either remove the field if ShaderLab
allows an empty varying struct, or explicitly initialize it in the vertex
function (the vert function that returns v) to a deterministic value (e.g., 0.0)
and/or add a one-line comment on why the placeholder exists so readers
understand it's intentional; update the declaration of Varyings and the vert
function (or add the comment next to _placeholder) accordingly.

In `@packages/geometry-sketch/src/material/TBNMaterial.ts`:
- Around line 14-17: Uniform declarations are split: move the material_BaseColor
uniform declaration so it is co-located with the other uniforms (u_lineScale,
camera_VPMat, u_worldMatrix, u_worldNormal) at the top of the Pass; locate the
material_BaseColor declaration between vert and frag and cut/paste it up with
those uniforms to keep all uniform declarations together and follow the
project's pattern.
- Around line 35-37: The Varyings struct is left uninitialized because vert()
returns a Varyings v without assigning its _placeholder field; either initialize
the struct in vert() (e.g., set v._placeholder = 0.0 before return) or remove
the placeholder field once empty structs are supported to avoid driver warnings;
apply the same fix to the other Varyings occurrence referenced in this file so
all vert() returns return initialized Varyings instances.

In `@packages/geometry-sketch/src/material/WireframeMaterial.ts`:
- Around line 14-33: Remove the unused uniforms and redundant attribute members:
delete the declarations u_lineScale and u_worldNormal from the uniform block,
and simplify the Attributes struct to only include JOINTS_0 and WEIGHTS_0 (since
POSITION, NORMAL, and TANGENT are provided by the injected
${geometryTextureVert} locals and not via attr.*). Keep getSkinMatrix(attr)
usage intact and ensure any code paths that expect attr.POSITION/NORMAL/TANGENT
instead use the texture-sourced POSITION/NORMAL/TANGENT provided by
geometryTextureVert so the engine no longer binds those unused vertex
attributes.

In `@packages/lines/src/line/material/dashShader.ts`:
- Around line 20-48: The Varyings struct currently includes v_direction which is
written in vert but never read in frag; remove v_direction from Varyings and
instead read attr.a_data.x into a local float (e.g., direction) inside vert,
then use that local to set v.v_tex; update vert to stop assigning v.v_direction
and delete the v.v_direction declaration in Varyings so you avoid wasting an
interpolator and vertex attribute copy (leave v_part, v_origin, v_position,
v_tex unchanged).

In `@packages/lines/src/line/material/lineShader.ts`:
- Around line 18-36: The Varyings struct contains an unused varying v_direction
which is written in vert but never read; remove the dead varying by deleting its
declaration in Varyings and removing the assignment v.v_direction =
attr.a_data.x from the vert function (ensure no other code references
v_direction or relies on attr.a_data.x in this shader). This keeps Varyings
minimal and avoids passing unused state between stages.
- Around line 44-58: The fragment shader function frag declares an unused local
variable vec4 finalColor; — remove that declaration from the frag(Varyings v)
function (and any related dead code) so only needed variables like u_color,
u_cap, u_join, v.v_part, v.v_position, v.v_origin, and u_width are used; ensure
gl_FragColor = u_color; remains as the final output and run a quick build/lint
to confirm no other references to finalColor exist.
🪄 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: cf9cc120-dcac-4943-bb92-1c71d5dbe90e

📥 Commits

Reviewing files that changed from the base of the PR and between c76e660 and e6f912e.

⛔ Files ignored due to path filters (11)
  • packages/custom-material/src/advanced-shader/eye/EyeForwardPass.glsl is excluded by !**/*.glsl
  • packages/custom-material/src/advanced-shader/hair/HairForwardPass.glsl is excluded by !**/*.glsl
  • packages/custom-material/src/advanced-shader/hair/HairLightDirect.glsl is excluded by !**/*.glsl
  • packages/custom-material/src/advanced-shader/sss/SSSForwardPass.glsl is excluded by !**/*.glsl
  • packages/custom-material/src/advanced-shader/sss/SSSLightDirect.glsl is excluded by !**/*.glsl
  • packages/framebuffer-picker/src/color.fs.glsl is excluded by !**/*.glsl
  • packages/framebuffer-picker/src/color.vs.glsl is excluded by !**/*.glsl
  • packages/outline/src/outline.fs.glsl is excluded by !**/*.glsl
  • packages/outline/src/outline.vs.glsl is excluded by !**/*.glsl
  • packages/outline/src/replace.fs.glsl is excluded by !**/*.glsl
  • packages/outline/src/replace.vs.glsl is excluded by !**/*.glsl
📒 Files selected for processing (22)
  • packages/controls/src/box-selection/BoxSelectionSSMaterial.ts
  • packages/custom-material/src/bake-pbr/BakePBRMaterial.ts
  • packages/custom-material/src/bake-pbr/fragment.ts
  • packages/custom-material/src/bake-pbr/vertex.ts
  • packages/custom-material/src/grid/GridMaterial.ts
  • packages/custom-material/src/plain-color/PlainColorMaterial.ts
  • packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts
  • packages/custom-material/src/water/WaterMaterial.ts
  • packages/custom-material/src/water/WaterRippleMaterial.ts
  • packages/custom-material/src/water/WaterfallMaterial.ts
  • packages/framebuffer-picker/src/FramebufferPicker.ts
  • packages/framebuffer-picker/src/global.d.ts
  • packages/geometry-sketch/src/material/GeometryShader.ts
  • packages/geometry-sketch/src/material/TBNMaterial.ts
  • packages/geometry-sketch/src/material/WireframeMaterial.ts
  • packages/gizmo/src/icon/Icon.ts
  • packages/gizmo/src/icon/IconMaterial.ts
  • packages/lines/src/line/material/dashShader.ts
  • packages/lines/src/line/material/lineShader.ts
  • packages/outline/src/OutlineManager.ts
  • packages/outline/src/global.d.ts
  • packages/skeleton-viewer/src/SkeletonViewer.ts
💤 Files with no reviewable changes (4)
  • packages/framebuffer-picker/src/global.d.ts
  • packages/outline/src/global.d.ts
  • packages/custom-material/src/bake-pbr/fragment.ts
  • packages/custom-material/src/bake-pbr/vertex.ts

Comment on lines +99 to +106
vec4 color = vec4((totalDiffuseColor + totalSpecularColor).rgb, surfaceData.opacity);
color.rgb += surfaceData.emissiveColor;

#if SCENE_FOG_MODE != 0
color = fog(color, varyings.positionVS);
#endif

gl_FragColor = color;
Copy link
Copy Markdown

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:

#!/bin/bash
# Locate engine's ForwardPassPBR.glsl and inspect the final-write section to confirm
# which tone-mapping / color-space helpers the standard path applies.
fd -t f 'ForwardPassPBR.glsl'
fd -t f 'ForwardPassPBR.glsl' --exec sh -c 'echo "=== $1 ==="; tail -n 80 "$1"' _ {}
# Also look for tone-map / gamma helpers referenced by the standard pass.
rg -nP '\b(linearToGamma|gammaToLinear|HDRToLDR|toneMapping|ACESToneMap)\s*\(' -C2

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# First, let's understand the repository structure
git ls-files | head -20

Repository: galacean/engine-toolkit

Length of output: 515


🏁 Script executed:

# Look for shader files in the custom-material package
fd -t f '\.(glsl|frag|vert)$' packages/custom-material/

Repository: galacean/engine-toolkit

Length of output: 615


🏁 Script executed:

# Read the BakePBRMaterial.ts file to see the actual implementation
wc -l packages/custom-material/src/bake-pbr/BakePBRMaterial.ts

Repository: galacean/engine-toolkit

Length of output: 127


🏁 Script executed:

# Search for tone mapping related functions across the codebase
rg -i 'tone.?map|linear.?gamma|hdr.?ldr' --type glsl --type ts

Repository: galacean/engine-toolkit

Length of output: 95


🏁 Script executed:

cat -n packages/custom-material/src/bake-pbr/BakePBRMaterial.ts

Repository: galacean/engine-toolkit

Length of output: 6349


🏁 Script executed:

# Search for tone mapping functions without file type restriction
rg -i 'tone.?map|linear.?gamma|hdr.?ldr' -A2 -B2

Repository: galacean/engine-toolkit

Length of output: 1830


🏁 Script executed:

# Look for ForwardPassPBR references
rg -i 'forwardpass' -A2 -B2

Repository: galacean/engine-toolkit

Length of output: 1593


🏁 Script executed:

# Search for exposure property definitions
rg -i 'exposure' -A2 -B2 | head -60

Repository: galacean/engine-toolkit

Length of output: 1193


🏁 Script executed:

# Look at the base PBRMaterial to see what it inherits
rg -i 'class.*PBRMaterial' -A5

Repository: galacean/engine-toolkit

Length of output: 668


🏁 Script executed:

# Search for where tone mapping might be applied in forward pass or elsewhere
rg -i 'aces|tone' -A2 -B2 | head -80

Repository: galacean/engine-toolkit

Length of output: 6267


🏁 Script executed:

# Check if there are any other shader files that show how tone mapping is applied
fd -type f -name '*.glsl' -o -name '*.gs' | xargs rg -l 'gl_FragColor' | head -10

Repository: galacean/engine-toolkit

Length of output: 779


BakePBRFragment missing ACES tone mapping promised in README.

The README documents that the material "supports...ACES toneMapping to correct the highlights" with an "Exposure" parameter "adjusted by ACES toneMapping automatically." However, the BakePBRFragment function (lines 99–106) writes gl_FragColor = color directly without reading any exposure value or applying tone mapping. The fragment shader accumulates totalDiffuseColor + totalSpecularColor + emissiveColor and applies fog, but skips the tone mapping step that would compensate for HDR lighting and match the visual output of PBRMaterial in the same scene.

Either add the exposure uniform and apply ACES tone mapping to the final color before gl_FragColor assignment, or remove/update the README documentation if tone mapping is not actually intended for this material.

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

In `@packages/custom-material/src/bake-pbr/BakePBRMaterial.ts` around lines 99 -
106, The fragment currently writes gl_FragColor directly in BakePBRFragment
without applying the documented ACES tone mapping or using an exposure uniform;
add a uniform float (e.g. uExposure) and apply it to the accumulated HDR color,
then run the ACES tone mapping helper (use the existing acesToneMapping/ACESFilm
helper or add one if missing) and convert to sRGB (linearToSRGB or equivalent)
before assigning gl_FragColor; update BakePBRFragment to multiply color.rgb by
uExposure, pass the result through the ACES tone mapping function, then set
gl_FragColor = vec4(toneMappedColor, color.a). If tone mapping is intentionally
omitted instead, update the README to remove the ACES/exposure claims.

Comment on lines +11 to +12
mat4 camera_ViewInvMat;
mat4 camera_ProjMat;
Copy link
Copy Markdown

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:

#!/bin/bash
# Look for engine-side declarations of the camera uniforms used here.
rg -nP '\bcamera_(ViewInvMat|ProjMat|ViewMat|ProjectionParams)\b' -C2

# Check sibling migrated shaders in this PR to see whether they redeclare these globals.
fd -e ts -e glsl | xargs rg -nP 'mat4\s+camera_(ViewInvMat|ProjMat|ViewMat)\s*;' -C1

Repository: galacean/engine-toolkit

Length of output: 5463


🏁 Script executed:

fd -name "Common.glsl" -o -name "Transform.glsl" | head -20

Repository: galacean/engine-toolkit

Length of output: 297


🏁 Script executed:

find . -name "*.glsl" -path "*/Common/*" | head -20

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Look at other migrated .ts files in the same package to see if they also redeclare these uniforms
fd -path "*/custom-material/src/*" -name "*.ts" -type f | xargs rg -l "camera_ViewInvMat|camera_ProjMat|camera_ViewMat" | head -10

Repository: galacean/engine-toolkit

Length of output: 348


🏁 Script executed:

# Find Common.glsl and Transform.glsl files
find . -name "Common.glsl" -o -name "Transform.glsl" 2>/dev/null | head -10

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# List all .ts files in custom-material to find migrated shaders
find packages/custom-material/src -name "*.ts" | head -20

Repository: galacean/engine-toolkit

Length of output: 787


🏁 Script executed:

# Check what camera uniforms are used/declared in other migrated .ts shaders
find packages/custom-material/src -name "*.ts" -exec rg -l "camera_" {} \;

Repository: galacean/engine-toolkit

Length of output: 188


🏁 Script executed:

# Check PlanarShadowShaderFactory.ts to see how it handles camera uniforms
cat -n packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts | grep -A5 -B5 "camera_"

Repository: galacean/engine-toolkit

Length of output: 824


🏁 Script executed:

# Search for Common.glsl and Transform.glsl in the entire repository
find . -type f \( -name "Common.glsl" -o -name "Transform.glsl" \) 2>/dev/null

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Search for where camera uniforms are defined in the engine
rg "camera_ViewInvMat|camera_ProjMat" --type glsl --type ts -l 2>/dev/null | grep -v "GridMaterial\|Grid.shader\|PlanarShadow"

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Look at full GridMaterial.ts file to understand structure
cat -n packages/custom-material/src/grid/GridMaterial.ts | head -100

Repository: galacean/engine-toolkit

Length of output: 4335


🏁 Script executed:

# Search in engine core for Common.glsl
find . -path "*/engine/*" -name "Common.glsl" 2>/dev/null | head -5

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Check if there's a shader loader or path resolution in the codebase
rg "Common/Common.glsl|Common/Transform.glsl" -A2 -B2

Repository: galacean/engine-toolkit

Length of output: 6785


Remove redundant camera uniform redeclarations — inconsistent with all other migrated shaders.

Lines 11–12 explicitly declare camera_ViewInvMat and camera_ProjMat, but other camera uniforms like camera_ViewMat (used at lines 77, 83) and camera_ProjectionParams (used at line 37) are not declared locally—they come from the includes. All other migrated shaders in the codebase (e.g., outline, gizmo, plain-color, geometry-sketch) include Common/Common.glsl and Common/Transform.glsl without redeclaring these uniforms. Lines 11–12 should be removed to maintain consistency.

🛠️ Proposed fix
       `#include` "Common/Common.glsl"
 
-      mat4 camera_ViewInvMat;
-      mat4 camera_ProjMat;
-
       struct Attributes {
         vec4 POSITION_FLIP;
       };
📝 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
mat4 camera_ViewInvMat;
mat4 camera_ProjMat;
`#include` "Common/Common.glsl"
struct Attributes {
vec4 POSITION_FLIP;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/grid/GridMaterial.ts` around lines 11 - 12,
Remove the redundant uniform redeclarations for camera_ViewInvMat and
camera_ProjMat from GridMaterial shader source so the shader relies on the
shared includes (e.g., Common/Common.glsl and Common/Transform.glsl) like the
other migrated shaders; specifically delete the two lines that declare mat4
camera_ViewInvMat; and mat4 camera_ProjMat; and ensure references to
camera_ViewMat and camera_ProjectionParams remain unchanged so the common
includes supply those uniforms consistently with outline, gizmo, plain-color,
and geometry-sketch shaders.

Comment on lines +81 to +93
vec4 material_BaseColor;

void frag(Varyings v) {
vec4 baseColor = material_BaseColor;

#ifdef MATERIAL_IS_ALPHA_CUTOFF
if( baseColor.a < material_AlphaCutoff ) {
discard;
}
#endif

gl_FragColor = baseColor;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that material_AlphaCutoff is declared in any include that PlainColorMaterial pulls in.
rg -nP '\bmaterial_AlphaCutoff\b' --type=ts --type=glsl -C2

Repository: galacean/engine-toolkit

Length of output: 95


🌐 Web query:

galacean engine ShaderLibrary Common.glsl material_AlphaCutoff declaration

💡 Result:

No explicit declaration of 'material_AlphaCutoff' was found in publicly available sources for Galacean Engine's ShaderLibrary/Common.glsl file. Common.glsl is a built-in shader include file providing common macros (e.g., PI) and utility functions (e.g., pow2, gammaToLinear, sRGBToLinear) for use in custom shaders via #include "Common.glsl". It does not contain material-specific uniforms like alpha cutoff, which are typically declared in PBR-specific files such as FragmentPBR.glsl or material property blocks in ShaderLab passes (e.g., uniform float material_AlphaCutoff;). Alpha cutoff is a standard PBR material parameter used for alpha testing in cutout materials, controlling the threshold for discarding fragments (if alpha < cutoff, discard). Official docs reference PBR shaders like ForwardPassPBR for full organization, but source code details direct users to "see source code." The engine's GitHub repo (github.com/galacean/engine) contains shader-lab and shader packages where GLSL files reside, confirming 8.3% GLSL content.

Citations:


🏁 Script executed:

#!/bin/bash
# Search for material_AlphaCutoff in the codebase (fix file type handling)
rg 'material_AlphaCutoff' -C2

Repository: galacean/engine-toolkit

Length of output: 2127


🏁 Script executed:

#!/bin/bash
# Locate and examine PlainColorMaterial.ts
find . -name "PlainColorMaterial.ts" -type f

Repository: galacean/engine-toolkit

Length of output: 131


🏁 Script executed:

#!/bin/bash
# Check the directory structure around the file
fd "PlainColorMaterial" -type f

Repository: galacean/engine-toolkit

Length of output: 237


🏁 Script executed:

#!/bin/bash
# Read the PlainColorMaterial.ts file
cat -n packages/custom-material/src/plain-color/PlainColorMaterial.ts

Repository: galacean/engine-toolkit

Length of output: 4765


Add missing material_AlphaCutoff uniform declaration.

The fragment shader at line 87 references material_AlphaCutoff under #ifdef MATERIAL_IS_ALPHA_CUTOFF, but this uniform is never declared in the shader. The includes (Common/Common.glsl, Transform.glsl, Skin.glsl, BlendShape.glsl) do not provide it. When the MATERIAL_IS_ALPHA_CUTOFF macro is enabled, the shader will fail to compile.

Add the declaration alongside material_BaseColor at line 81:

vec4 material_BaseColor;
float material_AlphaCutoff;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/plain-color/PlainColorMaterial.ts` around lines
81 - 93, The fragment shader references material_AlphaCutoff inside the frag
function under the MATERIAL_IS_ALPHA_CUTOFF guard but never declares it; add a
declaration for material_AlphaCutoff (float) next to the existing vec4
material_BaseColor variable so the shader compiles when MATERIAL_IS_ALPHA_CUTOFF
is defined — update the declarations that contain material_BaseColor to also
declare material_AlphaCutoff so frag can use it safely.

Comment on lines +108 to +114
struct Attributes {
vec4 POSITION;
#ifdef RENDERER_HAS_SKIN
attribute vec4 JOINTS_0;
attribute vec4 WEIGHTS_0;
vec4 JOINTS_0;
vec4 WEIGHTS_0;
#endif
};
Copy link
Copy Markdown

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:

#!/bin/bash
# Check how POSITION is declared in other ShaderLab-migrated factories in this PR.
rg -nP --type=ts -C2 '\b(vec3|vec4)\s+POSITION\b' -g '!**/node_modules/**'

Repository: galacean/engine-toolkit

Length of output: 5554


🏁 Script executed:

sed -n '145,165p' packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts

Repository: galacean/engine-toolkit

Length of output: 982


Change POSITION from vec4 to vec3 to match the engine's attribute binding and all other materials in this PR.

Every other ShaderLab-migrated material declares POSITION as vec3 (WaterMaterial, PlainColorMaterial, OutlineManager, etc.), but this file declares it as vec4. While the code vec4(attr.POSITION.xyz, 1.0) works regardless of the declaration type, the struct field should match how the engine actually binds the glTF attribute (as vec3). Change line 109 from vec4 POSITION; to vec3 POSITION; for consistency.

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

In `@packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts`
around lines 108 - 114, In the Attributes struct inside
PlanarShadowShaderFactory (the struct named Attributes that currently declares
vec4 POSITION), change the POSITION field type from vec4 to vec3 so it matches
the engine's glTF attribute binding and other ShaderLab materials; update the
declaration of POSITION in Attributes to vec3 POSITION and leave the shader code
that uses vec4(attr.POSITION.xyz, 1.0) unchanged.

Comment on lines +190 to +194
// @ts-ignore - ShaderPass single-arg constructor supported in engine but not yet published
const planarShadow = new ShaderPass(planarShadowPassSource);

// shadow color
color = u_planarShadowColor;
color.a *= falloff;
}
`,
`
varying vec4 color;
void main() {
gl_FragColor = color;
}
`
);
Shader.create("planarShadowShader", [Shader.find("pbr").subShaders[0].passes[0], planarShadow]);
if (!Shader.find("planarShadowShader")) {
Shader.create("planarShadowShader", [Shader.find("PBR").subShaders[0].passes[2], planarShadow]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Module-load ordering: unguarded Shader.find("PBR") can NPE.

Shader.find("PBR") is called at import time and its result is dereferenced as .subShaders[0].passes[2] without a null check. If this module is imported before the PBR shader is registered (e.g., depending on bundler/side-effect import order, or in a test environment), Shader.find("PBR") returns null and the whole module load crashes — and because the work sits at top level, there's no way for a caller to recover.

A few related concerns in the same block:

  • new ShaderPass(planarShadowPassSource) on Line 191 runs on every import even when planarShadowShader was already created by a previous load, producing an orphan ShaderPass. Move it inside the if (!Shader.find(...)) guard.
  • Consider wrapping the whole registration in a lazy init function invoked from replaceShader (or a single registerPlanarShadowShader() export), so shader creation is deterministic and ordered with respect to PBR registration rather than implicit on module import.
🛠️ Suggested fix
-// `@ts-ignore` - ShaderPass single-arg constructor supported in engine but not yet published
-const planarShadow = new ShaderPass(planarShadowPassSource);
-
-if (!Shader.find("planarShadowShader")) {
-  Shader.create("planarShadowShader", [Shader.find("PBR").subShaders[0].passes[2], planarShadow]);
-}
+if (!Shader.find("planarShadowShader")) {
+  const pbr = Shader.find("PBR");
+  if (!pbr) {
+    throw new Error(
+      `Cannot create "planarShadowShader": base "PBR" shader is not registered yet. ` +
+        `Ensure the engine's built-in shaders are initialized before importing PlanarShadowShaderFactory.`
+    );
+  }
+  // `@ts-expect-error` - ShaderPass single-arg constructor supported in engine but not yet published
+  const planarShadow = new ShaderPass(planarShadowPassSource);
+  Shader.create("planarShadowShader", [pbr.subShaders[0].passes[2], planarShadow]);
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/planar-shadow/PlanarShadowShaderFactory.ts`
around lines 190 - 194, The module currently calls Shader.find("PBR") and
constructs new ShaderPass(planarShadowPassSource) at import time which can NPE
if PBR isn't registered and produces orphan passes; fix by moving the
ShaderPass(planarShadowPassSource) construction and the
Shader.create("planarShadowShader", ...) call inside a guarded lazy initializer
function (e.g., registerPlanarShadowShader()) that first calls
Shader.find("PBR"), checks for null, and only then accesses
.subShaders[0].passes[2] and creates the shader; update replaceShader to call
registerPlanarShadowShader() before using the shader so registration is
deterministic and import-time side-effects are eliminated.

Comment on lines +15 to +17
mat4 camera_VPMat;
mat4 u_worldMatrix;
mat4 u_worldNormal;
Copy link
Copy Markdown

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:

#!/bin/bash
# Check what Common/Transform.glsl and Common/Common.glsl expose for the VP / world matrices
fd -i -e glsl Transform
fd -i -e glsl Common
# And search the engine ShaderLab library for the canonical names
rg -nP '\b(camera_VPMat|u_worldMatrix|renderer_ModelMat|camera_ViewProjection)\b' -C2

Repository: galacean/engine-toolkit

Length of output: 7026


🌐 Web query:

galacean engine ShaderLab built-in uniforms camera_VPMat u_worldMatrix Transform.glsl

💡 Result:

In Galacean Engine's ShaderLab system, built-in uniforms for transformation matrices and camera matrices are provided automatically. Key relevant uniforms include: Renderer uniforms (model transform): - renderer_LocalMat: mat4 - Model local coordinate matrix - renderer_ModelMat: mat4 - Model world coordinate matrix (equivalent to world matrix or u_worldMatrix) - renderer_MVMat: mat4 - Model view matrix - renderer_MVPMat: mat4 - Model view projection matrix (commonly used as gl_Position = renderer_MVPMat * attr.POSITION) - renderer_NormalMat: mat4 - Normal matrix Camera uniforms: - camera_ViewMat: mat4 - View matrix - camera_ProjMat: mat4 - Projection matrix - camera_VPMat: mat4 - View projection matrix These are declared directly in the Pass block or included via snippets like #include "Transform.glsl", which likely defines or exposes these matrices (used in examples for skinned animation and basic shaders). No explicit "u_worldMatrix" uniform is named, but renderer_ModelMat serves this role as the object-to-world transform. Transform.glsl is an engine-provided include file for transformation-related code, enabling modular use of these matrices.

Citations:


🏁 Script executed:

# Read the beginning of WireframeMaterial.ts to see the include and uniform declarations
head -25 packages/geometry-sketch/src/material/WireframeMaterial.ts

# Check SketchRenderer.ts to see how these uniforms are set
grep -A5 -B5 "_worldMatrixProp\|_worldNormalProp" packages/geometry-sketch/src/SketchRenderer.ts

Repository: galacean/engine-toolkit

Length of output: 2061


🏁 Script executed:

# Check if there are any references or documentation about these custom uniforms
# Look for comments or commit messages explaining the choice
rg -i "camera_VPMat|u_worldMatrix" packages/geometry-sketch/src/ -B2 -A2 | head -50

# Also check if there's any specific reason these are custom vs using engine built-ins
grep -r "renderer_ModelMat" packages/geometry-sketch/src/ || echo "No renderer_ModelMat found"
grep -r "renderer_MVPMat" packages/geometry-sketch/src/ || echo "No renderer_MVPMat found"

Repository: galacean/engine-toolkit

Length of output: 2725


Remove or guard camera_VPMat to avoid shadowing the engine's provided uniform.

camera_VPMat is already exposed by the included Common/Transform.glsl (line 11) as a built-in engine uniform. Redeclaring it locally shadows the engine's canonical definition and can lead to unexpected behavior or conflicts as the engine evolves.

u_worldMatrix and u_worldNormal appear to be intentionally custom uniforms (not standard engine uniforms, which uses renderer_ModelMat instead), so those are acceptable.

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

In `@packages/geometry-sketch/src/material/WireframeMaterial.ts` around lines 15 -
17, Remove or guard the local uniform declaration camera_VPMat in
WireframeMaterial to avoid shadowing the engine-provided uniform from
Common/Transform.glsl; either delete the camera_VPMat declaration or wrap it in
a macro/ifdef that only defines it when the engine does not provide it, and keep
u_worldMatrix and u_worldNormal as-is (they are custom) while continuing to use
the engine's renderer_ModelMat where appropriate.

Comment on lines +41 to +45
int indicesIndex = gl_VertexID / 3;
int indicesRow = indicesIndex / int(u_indicesTextureWidth);
int indicesCol = indicesIndex % int(u_indicesTextureWidth);
vec3 triangleIndices = getIndicesElement(float(indicesRow), float(indicesCol));
int subIndex = gl_VertexID % 3;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Galacean engine ShaderLab gl_VertexID WebGL1 support

💡 Result:

Galacean Engine's ShaderLab does not support gl_VertexID in WebGL1. Galacean Engine supports both WebGL1.0 and WebGL2.0 via WebGLEngine.create with graphicDeviceOptions.webGLMode to control the version. ShaderLab is a custom shader language that compiles to GLSL ES for WebGL, using explicit vertex attributes like POSITION, NORMAL, TEXCOORD_0 in Attributes structs passed to vertex shaders (e.g., Varyings vert(Attributes attr)). No official documentation mentions gl_VertexID or vertex index input; vertex processing relies on per-vertex attributes from meshes, not built-in vertex ID. gl_VertexID is a GLSL ES 3.0 (WebGL2) built-in not available in GLSL ES 1.0 (WebGL1), and since ShaderLab examples avoid it and use attribute-based input, it lacks support, especially in WebGL1 mode. For vertex ID needs, manually pass as custom attribute (TEXCOORD_n) or use WebGL2 if available.

Citations:


🏁 Script executed:

# Find WireframeMaterial and examine its full context
find . -name "WireframeMaterial.ts" -type f

Repository: galacean/engine-toolkit

Length of output: 127


🏁 Script executed:

# Search for any WebGL version checks or documentation in the geometry-sketch package
fd -t f . packages/geometry-sketch/src/material/ | head -20

Repository: galacean/engine-toolkit

Length of output: 281


🏁 Script executed:

# Look for gl_VertexID usage in the codebase and any version guards
rg "gl_VertexID" --type ts --type glsl --type js -B2 -A2

Repository: galacean/engine-toolkit

Length of output: 95


🏁 Script executed:

# Check for any `#version` directives or WebGL mode enforcement in material shaders
rg "#version|webGLMode|WebGLMode|WebGL1|WebGL2" packages/geometry-sketch/src/material/ -A2

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Read the WireframeMaterial.ts file
cat -n packages/geometry-sketch/src/material/WireframeMaterial.ts

Repository: galacean/engine-toolkit

Length of output: 4057


🏁 Script executed:

# Search for gl_VertexID in the entire repo without file type restriction
rg "gl_VertexID" -B3 -A3

Repository: galacean/engine-toolkit

Length of output: 4109


🏁 Script executed:

# Check if there are any WebGL version checks or guards around shader compilation
rg "version|WebGL|webGLMode" packages/geometry-sketch/src/material/ -B2 -A2

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Search for Shader.create implementation and any version enforcement
rg "Shader\s*\.create|class Shader" --type ts | head -20

Repository: galacean/engine-toolkit

Length of output: 2059


🏁 Script executed:

# Check if there's any WebGL version detection or fallback logic
rg "webGLMode|getWebGLVersion|WebGL.*version" --type ts | head -20

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

# Look for any shader compilation guards or error handling related to gl_VertexID
rg "gl_VertexID|compileShader|version.*es" | head -20

Repository: galacean/engine-toolkit

Length of output: 703


🏁 Script executed:

# Check if there's any shader validation or version handling in the geometry-sketch package
rg "version|Version|WebGL|webGL" packages/geometry-sketch/ -A2 -B2

Repository: galacean/engine-toolkit

Length of output: 387


🏁 Script executed:

# Look at the GeometryShader.ts to see if it provides any version directives
cat -n packages/geometry-sketch/src/material/GeometryShader.ts | head -50

Repository: galacean/engine-toolkit

Length of output: 2191


gl_VertexID is not supported in WebGL1 — add explicit WebGL2 version requirement or provide fallback.

The shader uses gl_VertexID (lines 41, 45), which requires GLSL ES 3.0 (WebGL2). Galacean Engine supports WebGL1 contexts, and this shader will fail to compile if instantiated in a WebGL1 pipeline without explicit version enforcement. Add #version 300 es at the shader entry point or document a hard requirement for WebGL2. Consider using a vertex attribute instead to maintain WebGL1 compatibility, per ShaderLab design patterns.

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

In `@packages/geometry-sketch/src/material/WireframeMaterial.ts` around lines 41 -
45, The shader in WireframeMaterial.ts uses gl_VertexID (seen in the snippet
with gl_VertexID, getIndicesElement, u_indicesTextureWidth) which requires GLSL
ES 3.0/WebGL2; update the shader source to either prepend "#version 300 es" at
the top to enforce WebGL2 or replace gl_VertexID usage with an explicit vertex
attribute (e.g., pass a flat int/float index attribute from the vertex buffer
and use that instead of gl_VertexID) so it will compile on WebGL1; also update
any surrounding code that constructs the program to document/require WebGL2 if
you choose the version route.

this._material.baseTexture = value;
} else {
this.engine.resourceManager.load({ url: value, type: AssetType.Texture2D }).then((texture: Texture2D) => {
this.engine.resourceManager.load({ url: value, type: AssetType.Texture }).then((texture: Texture2D) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

galacean engine AssetType.Texture vs Texture2D resourceManager.load return type

💡 Result:

In Galacean Engine, use AssetType.Texture2D to load 2D textures via resourceManager.load, which returns a Texture2D object. There is no AssetType.Texture; official documentation consistently uses AssetType.Texture2D for image files (.png, .jpg, .webp) that create 2D textures. Texture refers to the general concept (including 2D, CubeTexture), while Texture2D is the specific class and asset type for 2D textures. Example from official docs: engine.resourceManager.load({ type: AssetType.Texture2D, url: 'image url' }).then((texture: Texture2D) => { ... }); AssetType values include Texture2D (for 2D images), with separate types like GLTF for models and Scene for scenes. Editor assets list "Texture" as UI label for 2D texture uploads, but script loading specifies AssetType.Texture2D.

Citations:


🏁 Script executed:

cat packages/gizmo/src/icon/Icon.ts | head -80 | tail -20

Repository: galacean/engine-toolkit

Length of output: 650


🏁 Script executed:

rg "enum AssetType|type AssetType" --type ts -A 10 -B 2

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

rg "AssetType\." --type ts | head -20

Repository: galacean/engine-toolkit

Length of output: 211


🏁 Script executed:

rg "AssetType" packages/gizmo/src/icon/Icon.ts -B 5 | head -30

Repository: galacean/engine-toolkit

Length of output: 367


🏁 Script executed:

rg "export.*enum.*AssetType|export.*const.*AssetType" -type ts

Repository: galacean/engine-toolkit

Length of output: 94


🏁 Script executed:

rg "Texture" packages/gizmo/src/icon/Icon.ts | head -10

Repository: galacean/engine-toolkit

Length of output: 445


🏁 Script executed:

rg "AssetType\s*[=:{]" --type ts -A 30 | head -100

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

fd "AssetType" --type ts

Repository: galacean/engine-toolkit

Length of output: 236


🏁 Script executed:

find . -name "*.ts" -o -name "*.d.ts" | xargs grep -l "enum AssetType\|export.*AssetType" | head -5

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

rg "AssetType\s*=" --type-list

Repository: galacean/engine-toolkit

Length of output: 456


🏁 Script executed:

rg "AssetType\." . -A 2 -B 2 | grep -E "(Texture|AssetType)" | sort -u | head -20

Repository: galacean/engine-toolkit

Length of output: 437


🏁 Script executed:

cat packages/gizmo/package.json | grep -A 10 -B 2 "galacean"

Repository: galacean/engine-toolkit

Length of output: 956


🏁 Script executed:

rg "import.*AssetType" packages/gizmo/src/icon/Icon.ts -B 5 -A 5

Repository: galacean/engine-toolkit

Length of output: 49


🏁 Script executed:

head -30 packages/gizmo/src/icon/Icon.ts

Repository: galacean/engine-toolkit

Length of output: 760


Use AssetType.Texture2D instead of AssetType.Texture.

The code passes AssetType.Texture, but Galacean engine documentation specifies AssetType.Texture2D for loading 2D texture assets. There is no AssetType.Texture in the engine; the correct asset type for image files (.png, .jpg, .webp) is AssetType.Texture2D, which properly resolves to Texture2D objects via resourceManager.load().

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

In `@packages/gizmo/src/icon/Icon.ts` at line 66, The load call using
this.engine.resourceManager.load({ url: value, type: AssetType.Texture }) is
using a non-existent AssetType; change the asset type to AssetType.Texture2D so
the resource manager returns a Texture2D (update the object literal to use type:
AssetType.Texture2D), keeping the existing then((texture: Texture2D) => ...)
handler in the Icon class to ensure correct typing and runtime resolution.

Comment on lines +176 to +211
Varyings vert(Attributes attr) {
Varyings v;

vec4 position = vec4(attr.POSITION, 1.0);

#ifdef RENDERER_HAS_NORMAL
vec3 normal = vec3(attr.NORMAL);
#ifdef RENDERER_HAS_TANGENT
vec4 tangent = vec4(attr.TANGENT);
#endif
#endif

#ifdef RENDERER_HAS_BLENDSHAPE
calculateBlendShape(attr, position
#ifdef RENDERER_HAS_NORMAL
, normal
#ifdef RENDERER_HAS_TANGENT
, tangent
#endif
#endif
);
#endif

#ifdef RENDERER_HAS_SKIN
mat4 skinMatrix = getSkinMatrix(attr);
position = skinMatrix * position;
#endif

gl_Position = renderer_MVPMat * position;

return v;
}

vec4 camera_OutlineReplaceColor;

void frag(Varyings v) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify that the outline replacement shader declares Varyings when it uses Varyings.

python - <<'PY'
from pathlib import Path

path = Path("packages/outline/src/OutlineManager.ts")
text = path.read_text()

start = text.index("const outlineReplaceShaderSource")
end = text.index("`;", start)
shader = text[start:end]

uses_varyings = "Varyings vert" in shader or "frag(Varyings" in shader
declares_varyings = "struct Varyings" in shader

print(f"uses Varyings: {uses_varyings}")
print(f"declares Varyings: {declares_varyings}")

if uses_varyings and not declares_varyings:
    raise SystemExit("outlineReplaceShaderSource uses Varyings without declaring struct Varyings")
PY

Repository: galacean/engine-toolkit

Length of output: 203


🏁 Script executed:

# Check the OutlineManager.ts file around lines 176-211 and search for Varyings declarations
python - <<'PY'
from pathlib import Path

path = Path("packages/outline/src/OutlineManager.ts")
content = path.read_text()
lines = content.split('\n')

# Find the outlineReplaceShaderSource definition
start_idx = None
for i, line in enumerate(lines):
    if "const outlineReplaceShaderSource" in line:
        start_idx = i
        break

if start_idx is None:
    print("ERROR: Could not find outlineReplaceShaderSource")
else:
    # Find the end of the shader source (the closing backtick)
    end_idx = None
    for i in range(start_idx, len(lines)):
        if "`;" in lines[i]:
            end_idx = i
            break
    
    print(f"outlineReplaceShaderSource found at line {start_idx + 1}")
    print(f"Shader source ends at line {end_idx + 1}")
    print(f"\nTotal lines in shader: {end_idx - start_idx + 1}")
    
    # Extract the shader source
    shader_lines = lines[start_idx:end_idx+1]
    
    # Check for struct declarations
    print("\n=== Struct declarations in shader source ===")
    for i, line in enumerate(shader_lines, start=start_idx+1):
        if "struct " in line:
            print(f"Line {i}: {line.strip()}")
    
    # Check for Varyings usage
    print("\n=== Varyings usage in shader source ===")
    for i, line in enumerate(shader_lines, start=start_idx+1):
        if "Varyings" in line:
            print(f"Line {i}: {line.strip()}")
    
    # Check what's around line 176
    print("\n=== Lines 176-211 context ===")
    for i in range(max(0, 175), min(len(lines), 211)):
        print(f"Line {i+1}: {lines[i]}")
PY

Repository: galacean/engine-toolkit

Length of output: 1657


🏁 Script executed:

# Search for Varyings struct definitions elsewhere in the codebase
rg "struct Varyings" -A 3

# Also check if there are other shader sources that might show the pattern
rg "Varyings vert\(" -B 5 -A 10

Repository: galacean/engine-toolkit

Length of output: 25113


Add missing Varyings struct declaration in outlineReplaceShaderSource.

The outlineReplaceShaderSource shader uses Varyings in the vert and frag functions but never declares the struct. This will cause shader compilation to fail and break the outline replacement pass.

🐛 Proposed fix
       };
 
+      struct Varyings {
+        float _placeholder;
+      };
+
       Varyings vert(Attributes attr) {
         Varyings v;
+        v._placeholder = 0.0;
 
         vec4 position = vec4(attr.POSITION, 1.0);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/outline/src/OutlineManager.ts` around lines 176 - 211, The shader is
missing the Varyings struct used by outlineReplaceShaderSource's vert and frag;
add a Varyings declaration above the vert function (in the
outlineReplaceShaderSource string) that defines every varying the vertex shader
writes and the fragment shader reads (e.g., any TEXCOORD, COLOR, or custom
varyings used by frag), using the correct interpolation qualifiers/precision as
used elsewhere in our shaders so field names/types match references in vert and
frag.

- Replace inline struct Attributes with #include "Common/Attributes.glsl"
- Add #ifdef guards for unconditional attribute usage
- Replace PBR/AttributesPBR.glsl refs in ForwardPass shaders
- Use void vert/frag signature for shaders without varyings
- Affected: TBNMaterial, WireframeMaterial, FramebufferPicker,
  PlainColorMaterial, BoxSelectionSSMaterial
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: 3

♻️ Duplicate comments (1)
packages/custom-material/src/plain-color/PlainColorMaterial.ts (1)

31-43: ⚠️ Potential issue | 🔴 Critical

Declare material_AlphaCutoff before using it.

Line 37 references material_AlphaCutoff, but this shader source only declares material_BaseColor. Enabling MATERIAL_IS_ALPHA_CUTOFF can fail shader compilation.

Proposed fix
       vec4 material_BaseColor;
+      float material_AlphaCutoff;
 
       void frag() {

To verify the declaration is still missing:

#!/bin/bash
# Description: Confirm `material_AlphaCutoff` references/declarations in the repo.
# Expected: PlainColorMaterial references it in frag; a declaration should exist in the shader source or included shader library.

sed -n '25,43p' packages/custom-material/src/plain-color/PlainColorMaterial.ts
rg -nP '\bmaterial_AlphaCutoff\b' -C2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/plain-color/PlainColorMaterial.ts` around lines
31 - 43, The shader uses material_AlphaCutoff inside the frag() function guarded
by MATERIAL_IS_ALPHA_CUTOFF but never declares it, causing compile errors when
that define is enabled; add a GLSL declaration for material_AlphaCutoff (e.g., a
float uniform or varying depending on how materials are passed) alongside the
existing material_BaseColor declaration in PlainColorMaterial so the symbol
material_AlphaCutoff is defined when MATERIAL_IS_ALPHA_CUTOFF is used in frag();
update the declarations block that contains material_BaseColor in the
PlainColorMaterial shader source to include this new material_AlphaCutoff
declaration.
🤖 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/custom-material/src/water/WaterMaterial.ts`:
- Around line 22-56: The vert(Attributes attr) function leaves v.v_color,
v.waterTexCoords and v.normalTexCoords uninitialized when
RENDERER_HAS_UV/RENDERER_ENABLE_VERTEXCOLOR are not defined, while frag() always
reads those varyings (v.v_color, v.waterTexCoords, v.normalTexCoords); to fix,
set safe default values at the start of Varyings vert(Attributes attr) (e.g.
v.v_color = vec4(1.0), v.waterTexCoords = vec2(0.0), v.normalTexCoords =
vec2(0.0)) before any conditional assignments so the fragment shader always
receives defined values.

In `@packages/custom-material/src/water/WaterRippleMaterial.ts`:
- Around line 22-51: The Varyings struct fields used in frag (v.normalTexCoords,
v.waterTexCoords, v.v_color) are only set inside conditional blocks in vert and
can be left uninitialized when RENDERER_HAS_UV or RENDERER_ENABLE_VERTEXCOLOR
are disabled; update vert(Attributes attr) to initialize v.normalTexCoords,
v.waterTexCoords, and v.v_color to safe defaults (e.g., zero vec2/vec4 or
neutral values) before the `#ifdef` blocks so frag() always reads defined values
and avoids undefined behavior.

In `@packages/skeleton-viewer/src/SkeletonViewer.ts`:
- Around line 29-49: The frag shader reads v.v_normal unconditionally while vert
only writes it when RENDERER_HAS_NORMAL is defined, so make the usage symmetric:
either initialize v.v_normal with a safe default in Varyings/vert (e.g., set
v.v_normal = vec3(0,1,0) before the `#ifdef` in the vert function) or wrap the
dot() and related code in frag with `#ifdef` RENDERER_HAS_NORMAL to provide a
fallback diffuse (use a constant color or compute ndl=1.0). Update the Varyings
struct/vert/frag symbols (Varyings, vert, frag, v_normal, RENDERER_HAS_NORMAL)
accordingly so v.v_normal is never read uninitialized.

---

Duplicate comments:
In `@packages/custom-material/src/plain-color/PlainColorMaterial.ts`:
- Around line 31-43: The shader uses material_AlphaCutoff inside the frag()
function guarded by MATERIAL_IS_ALPHA_CUTOFF but never declares it, causing
compile errors when that define is enabled; add a GLSL declaration for
material_AlphaCutoff (e.g., a float uniform or varying depending on how
materials are passed) alongside the existing material_BaseColor declaration in
PlainColorMaterial so the symbol material_AlphaCutoff is defined when
MATERIAL_IS_ALPHA_CUTOFF is used in frag(); update the declarations block that
contains material_BaseColor in the PlainColorMaterial shader source to include
this new material_AlphaCutoff declaration.
🪄 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: 78ef16c9-8467-485a-b6e1-3ee71a879b91

📥 Commits

Reviewing files that changed from the base of the PR and between e6f912e and 18253f4.

⛔ Files ignored due to path filters (3)
  • packages/custom-material/src/advanced-shader/eye/EyeForwardPass.glsl is excluded by !**/*.glsl
  • packages/custom-material/src/advanced-shader/hair/HairForwardPass.glsl is excluded by !**/*.glsl
  • packages/custom-material/src/advanced-shader/sss/SSSForwardPass.glsl is excluded by !**/*.glsl
📒 Files selected for processing (11)
  • packages/controls/src/box-selection/BoxSelectionSSMaterial.ts
  • packages/custom-material/src/plain-color/PlainColorMaterial.ts
  • packages/custom-material/src/water/WaterMaterial.ts
  • packages/custom-material/src/water/WaterRippleMaterial.ts
  • packages/custom-material/src/water/WaterfallMaterial.ts
  • packages/framebuffer-picker/src/FramebufferPicker.ts
  • packages/geometry-sketch/src/material/TBNMaterial.ts
  • packages/geometry-sketch/src/material/WireframeMaterial.ts
  • packages/gizmo/src/icon/IconMaterial.ts
  • packages/outline/src/OutlineManager.ts
  • packages/skeleton-viewer/src/SkeletonViewer.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/controls/src/box-selection/BoxSelectionSSMaterial.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/outline/src/OutlineManager.ts
  • packages/framebuffer-picker/src/FramebufferPicker.ts
  • packages/custom-material/src/water/WaterfallMaterial.ts
  • packages/geometry-sketch/src/material/WireframeMaterial.ts
  • packages/gizmo/src/icon/IconMaterial.ts
  • packages/geometry-sketch/src/material/TBNMaterial.ts

Comment on lines +22 to +56
Varyings vert(Attributes attr) {
Varyings v;
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);

#ifdef RENDERER_HAS_UV
v.waterTexCoords = attr.TEXCOORD_0 + vec2(u_water_speed.x * sin(u_time), u_water_speed.y * cos(u_time));
v.normalTexCoords = attr.TEXCOORD_0 + vec2(u_distorsion_speed.x * cos(u_time), u_distorsion_speed.y * sin(u_time));
#endif

#ifdef RENDERER_ENABLE_VERTEXCOLOR
v.v_color = attr.COLOR_0;
#endif
return v;
}

#include "Common/Common.glsl"

sampler2D material_NormalTexture;
sampler2D u_waterTex;
sampler2D u_edgeTex;

vec4 u_edgeColor;
vec2 u_edgeParam;
float u_distorsion_amount;

void frag(Varyings v) {
vec4 normalTex = texture2D(material_NormalTexture, v.normalTexCoords) * 2.0 - 1.0;
vec4 waterTex = texture2D(u_waterTex, v.waterTexCoords + (normalTex.rg * u_distorsion_amount));
vec4 edgeTex = texture2D(u_edgeTex, v.waterTexCoords + (normalTex.rg * u_distorsion_amount));

float edge = pow((v.v_color.r + edgeTex.r) * v.v_color.r, 2.0);
edge = saturate(1.0 - smoothstep(u_edgeParam.x - u_edgeParam.y, u_edgeParam.x + u_edgeParam.y, edge));
vec4 finalCol = mix(waterTex, u_edgeColor, edge);

gl_FragColor = finalCol;
Copy link
Copy Markdown

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:

find . -name "WaterMaterial.ts" -type f

Repository: galacean/engine-toolkit

Length of output: 120


🏁 Script executed:

cat -n packages/custom-material/src/water/WaterMaterial.ts | head -100

Repository: galacean/engine-toolkit

Length of output: 3987


🏁 Script executed:

# Check if there are other shader files using similar patterns to understand the convention
find . -name "*.ts" -path "*/material*" -type f | head -10

Repository: galacean/engine-toolkit

Length of output: 489


🏁 Script executed:

cat -n packages/custom-material/src/water/WaterMaterial.ts | sed -n '47,60p'

Repository: galacean/engine-toolkit

Length of output: 789


🏁 Script executed:

# Check other shader files to see if they use similar patterns or guard against undefined varyings
grep -r "Varyings\|struct.*{" packages/geometry-sketch/src/material/*.ts packages/lines/src/line/material/*.ts -A 5 | head -50

Repository: galacean/engine-toolkit

Length of output: 4250


Initialize varyings to defaults before conditional assignment.

The vert() function conditionally initializes waterTexCoords, normalTexCoords (lines 27–28 under RENDERER_HAS_UV), and v_color (line 32 under RENDERER_ENABLE_VERTEXCOLOR), but frag() unconditionally reads all three varyings (lines 48–52). When these macros are absent, varyings propagate undefined values to the fragment shader, causing unpredictable rendering.

Initialize all varyings to defaults at the start of vert():

Varyings vert(Attributes attr) {
  Varyings v;
  v.v_color = vec4(1.0);
  v.waterTexCoords = vec2(0.0);
  v.normalTexCoords = vec2(0.0);
  gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
  // ... rest of function
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/water/WaterMaterial.ts` around lines 22 - 56,
The vert(Attributes attr) function leaves v.v_color, v.waterTexCoords and
v.normalTexCoords uninitialized when RENDERER_HAS_UV/RENDERER_ENABLE_VERTEXCOLOR
are not defined, while frag() always reads those varyings (v.v_color,
v.waterTexCoords, v.normalTexCoords); to fix, set safe default values at the
start of Varyings vert(Attributes attr) (e.g. v.v_color = vec4(1.0),
v.waterTexCoords = vec2(0.0), v.normalTexCoords = vec2(0.0)) before any
conditional assignments so the fragment shader always receives defined values.

Comment on lines +22 to +51
Varyings vert(Attributes attr) {
Varyings v;
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
#ifdef RENDERER_HAS_UV
v.waterTexCoords = attr.TEXCOORD_0 + vec2(u_foam_speed.x * u_time, u_foam_speed.y * u_time);
v.normalTexCoords = attr.TEXCOORD_0 + vec2(u_distorsion_speed.x * cos(u_time), u_distorsion_speed.y * sin(u_time));
#endif
#ifdef RENDERER_ENABLE_VERTEXCOLOR
v.v_color = attr.COLOR_0;
#endif
return v;
}

#include "Common/Common.glsl"

sampler2D material_NormalTexture;
sampler2D u_foamTex;
vec3 u_foamColor;
vec2 u_foam_param;
float u_distorsion_amount;

void frag(Varyings v) {
vec4 normalTex = texture2D(material_NormalTexture, v.normalTexCoords) * 2.0 - 1.0;
vec4 waterTex = texture2D(u_foamTex, v.waterTexCoords + (normalTex.rg * u_distorsion_amount));
float alphaComp = v.v_color.r * waterTex.r * u_foam_param.x;
float alpha = pow(alphaComp, 2.0);
alpha = smoothstep(0.5 - u_foam_param.y, 0.5 + u_foam_param.y, alpha);
alpha = saturate(alpha);

gl_FragColor = vec4(u_foamColor.rgb, alpha);
Copy link
Copy Markdown

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:

find . -path "*/packages/custom-material/src/water/WaterRippleMaterial.ts" -type f

Repository: galacean/engine-toolkit

Length of output: 126


🏁 Script executed:

cat -n ./packages/custom-material/src/water/WaterRippleMaterial.ts

Repository: galacean/engine-toolkit

Length of output: 6177


🏁 Script executed:

rg "RENDERER_HAS_UV|RENDERER_ENABLE_VERTEXCOLOR" --type glsl -A 2 -B 2

Repository: galacean/engine-toolkit

Length of output: 95


🏁 Script executed:

rg "RENDERER_HAS_UV|RENDERER_ENABLE_VERTEXCOLOR" -A 2 -B 2 --max-count=20

Repository: galacean/engine-toolkit

Length of output: 9311


🏁 Script executed:

cat -n ./packages/custom-material/src/water/WaterMaterial.ts | head -60

Repository: galacean/engine-toolkit

Length of output: 2375


🏁 Script executed:

cat -n ./packages/custom-material/src/water/WaterfallMaterial.ts | head -70

Repository: galacean/engine-toolkit

Length of output: 2942


🏁 Script executed:

rg "struct Varyings" -A 10 packages/custom-material/src/water/ | head -80

Repository: galacean/engine-toolkit

Length of output: 2818


Initialize varyings to prevent undefined behavior when conditionals are disabled.

v.normalTexCoords, v.waterTexCoords, and v.v_color are only assigned when RENDERER_HAS_UV or RENDERER_ENABLE_VERTEXCOLOR are enabled (lines 25–31), but are unconditionally read in the fragment shader (lines 44–46). When these macros are disabled, undefined values propagate to the fragment shader, causing unstable foam rendering that may vary across GPUs.

Initialize all varyings to safe defaults before the conditional blocks:

Suggested fix
       Varyings vert(Attributes attr) {
         Varyings v;
+        v.waterTexCoords = vec2(0.0);
+        v.normalTexCoords = vec2(0.0);
+        v.v_color = vec4(1.0);
         gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
         `#ifdef` RENDERER_HAS_UV
           v.waterTexCoords = attr.TEXCOORD_0 + vec2(u_foam_speed.x * u_time, u_foam_speed.y * u_time);
           v.normalTexCoords = attr.TEXCOORD_0 + vec2(u_distorsion_speed.x * cos(u_time), u_distorsion_speed.y * sin(u_time));
📝 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
Varyings vert(Attributes attr) {
Varyings v;
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
#ifdef RENDERER_HAS_UV
v.waterTexCoords = attr.TEXCOORD_0 + vec2(u_foam_speed.x * u_time, u_foam_speed.y * u_time);
v.normalTexCoords = attr.TEXCOORD_0 + vec2(u_distorsion_speed.x * cos(u_time), u_distorsion_speed.y * sin(u_time));
#endif
#ifdef RENDERER_ENABLE_VERTEXCOLOR
v.v_color = attr.COLOR_0;
#endif
return v;
}
#include "Common/Common.glsl"
sampler2D material_NormalTexture;
sampler2D u_foamTex;
vec3 u_foamColor;
vec2 u_foam_param;
float u_distorsion_amount;
void frag(Varyings v) {
vec4 normalTex = texture2D(material_NormalTexture, v.normalTexCoords) * 2.0 - 1.0;
vec4 waterTex = texture2D(u_foamTex, v.waterTexCoords + (normalTex.rg * u_distorsion_amount));
float alphaComp = v.v_color.r * waterTex.r * u_foam_param.x;
float alpha = pow(alphaComp, 2.0);
alpha = smoothstep(0.5 - u_foam_param.y, 0.5 + u_foam_param.y, alpha);
alpha = saturate(alpha);
gl_FragColor = vec4(u_foamColor.rgb, alpha);
Varyings vert(Attributes attr) {
Varyings v;
v.waterTexCoords = vec2(0.0);
v.normalTexCoords = vec2(0.0);
v.v_color = vec4(1.0);
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
`#ifdef` RENDERER_HAS_UV
v.waterTexCoords = attr.TEXCOORD_0 + vec2(u_foam_speed.x * u_time, u_foam_speed.y * u_time);
v.normalTexCoords = attr.TEXCOORD_0 + vec2(u_distorsion_speed.x * cos(u_time), u_distorsion_speed.y * sin(u_time));
`#endif`
`#ifdef` RENDERER_ENABLE_VERTEXCOLOR
v.v_color = attr.COLOR_0;
`#endif`
return v;
}
`#include` "Common/Common.glsl"
sampler2D material_NormalTexture;
sampler2D u_foamTex;
vec3 u_foamColor;
vec2 u_foam_param;
float u_distorsion_amount;
void frag(Varyings v) {
vec4 normalTex = texture2D(material_NormalTexture, v.normalTexCoords) * 2.0 - 1.0;
vec4 waterTex = texture2D(u_foamTex, v.waterTexCoords + (normalTex.rg * u_distorsion_amount));
float alphaComp = v.v_color.r * waterTex.r * u_foam_param.x;
float alpha = pow(alphaComp, 2.0);
alpha = smoothstep(0.5 - u_foam_param.y, 0.5 + u_foam_param.y, alpha);
alpha = saturate(alpha);
gl_FragColor = vec4(u_foamColor.rgb, alpha);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/custom-material/src/water/WaterRippleMaterial.ts` around lines 22 -
51, The Varyings struct fields used in frag (v.normalTexCoords,
v.waterTexCoords, v.v_color) are only set inside conditional blocks in vert and
can be left uninitialized when RENDERER_HAS_UV or RENDERER_ENABLE_VERTEXCOLOR
are disabled; update vert(Attributes attr) to initialize v.normalTexCoords,
v.waterTexCoords, and v.v_color to safe defaults (e.g., zero vec2/vec4 or
neutral values) before the `#ifdef` blocks so frag() always reads defined values
and avoids undefined behavior.

Comment on lines +29 to +49
struct Varyings {
vec3 v_normal;
};

Varyings vert(Attributes attr) {
Varyings v;
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
#ifdef RENDERER_HAS_NORMAL
v.v_normal = normalize( mat3(renderer_NormalMat) * attr.NORMAL );
#endif
return v;
}

vec3 u_colorMin;
vec3 u_colorMax;

void frag(Varyings v) {
float ndl = dot(v.v_normal, vec3(0, 1, 0)) * 0.5 + 0.5;
vec3 diffuse = mix(u_colorMin, u_colorMax, ndl);
gl_FragColor = vec4(diffuse, 1.0);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unguarded read of v_normal when RENDERER_HAS_NORMAL is not defined.

v.v_normal is only written inside #ifdef RENDERER_HAS_NORMAL (Line 36–38), but frag unconditionally uses it in dot(v.v_normal, vec3(0, 1, 0)) (Line 46). When the renderer/mesh lacks a normal attribute, the varying is undefined, producing garbage shading (and on some drivers, NaNs).

Since _createSpur/PrimitiveMesh.createSphere both upload normals, the skeleton viewer's own meshes will set this macro; but the failure mode is silent if that ever changes. Either guard the frag read symmetrically or supply a safe default.

🛡️ Proposed fix
       Varyings vert(Attributes attr) {
         Varyings v;
         gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
         `#ifdef` RENDERER_HAS_NORMAL
           v.v_normal = normalize( mat3(renderer_NormalMat) * attr.NORMAL );
+        `#else`
+          v.v_normal = vec3(0.0, 1.0, 0.0);
         `#endif`
         return v;
       }
📝 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
struct Varyings {
vec3 v_normal;
};
Varyings vert(Attributes attr) {
Varyings v;
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
#ifdef RENDERER_HAS_NORMAL
v.v_normal = normalize( mat3(renderer_NormalMat) * attr.NORMAL );
#endif
return v;
}
vec3 u_colorMin;
vec3 u_colorMax;
void frag(Varyings v) {
float ndl = dot(v.v_normal, vec3(0, 1, 0)) * 0.5 + 0.5;
vec3 diffuse = mix(u_colorMin, u_colorMax, ndl);
gl_FragColor = vec4(diffuse, 1.0);
}
struct Varyings {
vec3 v_normal;
};
Varyings vert(Attributes attr) {
Varyings v;
gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0);
`#ifdef` RENDERER_HAS_NORMAL
v.v_normal = normalize( mat3(renderer_NormalMat) * attr.NORMAL );
`#else`
v.v_normal = vec3(0.0, 1.0, 0.0);
`#endif`
return v;
}
vec3 u_colorMin;
vec3 u_colorMax;
void frag(Varyings v) {
float ndl = dot(v.v_normal, vec3(0, 1, 0)) * 0.5 + 0.5;
vec3 diffuse = mix(u_colorMin, u_colorMax, ndl);
gl_FragColor = vec4(diffuse, 1.0);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/skeleton-viewer/src/SkeletonViewer.ts` around lines 29 - 49, The
frag shader reads v.v_normal unconditionally while vert only writes it when
RENDERER_HAS_NORMAL is defined, so make the usage symmetric: either initialize
v.v_normal with a safe default in Varyings/vert (e.g., set v.v_normal =
vec3(0,1,0) before the `#ifdef` in the vert function) or wrap the dot() and
related code in frag with `#ifdef` RENDERER_HAS_NORMAL to provide a fallback
diffuse (use a constant color or compute ndl=1.0). Update the Varyings
struct/vert/frag symbols (Varyings, vert, frag, v_normal, RENDERER_HAS_NORMAL)
accordingly so v.v_normal is never read uninitialized.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant