Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pbr support transmission #2478

Merged
merged 39 commits into from
Dec 26, 2024
Merged

pbr support transmission #2478

merged 39 commits into from
Dec 26, 2024

Conversation

hhhhkrx
Copy link
Contributor

@hhhhkrx hhhhkrx commented Dec 25, 2024

Please check if the PR fulfills these requirements

  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)

What is the current behavior? (You can also link to an open issue here)

What is the new behavior (if this is a feature change)?

Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)

Other information:

Summary by CodeRabbit

  • New Features

    • Introduced new properties for enhanced refraction, transmission, and absorption effects in materials.
    • Added support for volumetric materials in the GLTF format through new interfaces and classes.
    • Expanded shader capabilities to manage transmission effects with new properties.
  • Bug Fixes

    • Improved handling of texture transforms for transmission and thickness textures.
  • Documentation

    • Added comments to new enum values for clarity on refraction modes.
  • Chores

    • Updated exports to include new enums and interfaces for better modularity.

Copy link

coderabbitai bot commented Dec 25, 2024

Walkthrough

This pull request introduces extensive enhancements to the PBRMaterial class and related components, focusing on advanced handling of refraction, transmission, and absorption properties. Key additions include new properties, an enumeration for refraction modes, and GLTF extension parsers to support volumetric materials. Shader capabilities are also expanded with new properties for managing transmission effects. These changes collectively improve the realism and versatility of material rendering within the Physically Based Rendering (PBR) system.

Changes

File Change Summary
packages/core/src/material/PBRMaterial.ts Added properties for refractionMode, transmission, transmissionTexture, attenuationColor, attenuationDistance, thickness, and thicknessTexture. Introduced private method _setRefractionMode.
packages/core/src/material/enums/Refraction.ts Introduced RefractionMode enum with Sphere, Plane, and Thin modes.
packages/core/src/material/index.ts Exported RefractionMode from the enums module.
packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts Added IKHRMaterialsVolume interface for volumetric material properties. Updated GLTFExtensionSchema to include this interface.
packages/loader/src/gltf/extensions/KHR_materials_transmission.ts Added KHR_materials_transmission class for handling material transmission properties.
packages/loader/src/gltf/extensions/KHR_materials_volume.ts Added KHR_materials_volume class for handling material volume properties.
packages/shader-shaderlab/src/shaders/PBR.gs Added shader properties material_Transmission and material_TransmissionTexture for managing transmission effects.
packages/shader-shaderlab/src/shaders/shadingPBR/index.ts Added imports for Refraction and BTDF, expanding shader functionality.
packages/core/src/material/BaseMaterial.ts Changed access level of _alphaCutoffProp and _isTransparent to protected. Added methods _seIsTransparent and _setAlphaCutoff.

Possibly related PRs

Suggested labels

shader, glTF, material

Suggested reviewers

  • zhuxudong

Poem

🐰 Hop into the light, with transmission so bright,
Refraction dances, materials take flight!
Volumes and textures, a shader's delight,
Rendering magic, pure rendering might!
CodeRabbit's rendering, a technical sight! 🌈

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (13)
packages/loader/src/gltf/extensions/KHR_materials_transmission.ts (2)

7-12: Ensure consistency with user-defined refraction behavior
The code sets material.refractionMode to RefractionMode.Plane unconditionally. If there's a need to allow other refraction shapes (e.g., sphere, thin), consider making this configurable or derived from the GLTF schema to avoid hardcoding a single refraction mode.


14-20: Handle potential texture loading errors
The asynchronous call to retrieve transmissionTexture lacks error handling. If the texture fails to load, the material might remain in an undefined state. Consider adding a .catch() block or a fallback mechanism to handle texture load failures gracefully.

packages/loader/src/gltf/extensions/KHR_materials_volume.ts (2)

9-15: Use schema-defined refraction if applicable
Like KHR_materials_transmission, this code sets material.refractionMode to RefractionMode.Plane by default. If the volume schema supports different refraction modes, consider making this assignment more flexible to accommodate varying use cases.


26-32: Consolidate texture error handling
As with KHR_materials_transmission, carefully handle potential texture load failures. Consider adding .catch() or a fallback strategy if the texture is invalid or the call fails.

packages/core/src/material/PBRMaterial.ts (8)

310-317: Documentation for refraction behavior
The doc comment is accurate but concise. Consider expanding it to clarify how different refraction modes affect the material’s transparency and final rendered appearance.


330-336: Transparent override
If isTransparent is set to true, it overrides the internal queue logic, or vice versa. Ensure that users understand that refractionMode also forces transparency. Consider clarifying in documentation to avoid confusion.


366-381: Transmission texture consistency
Enabling the macro whenever transmissionTexture is set is correct. Ensure the actual channel usage (red channel for transmission) is documented, so artists and pipeline developers can supply textures appropriately.


383-398: Attenuation color usage
Ensure that developers understand existing gamma or linear workflows. Consider clarifying in docs whether attenuation colors are specified in linear or gamma space.


400-409: Attenuation distance edge cases
Although you clamp to a minimum of 0, Infinity is an allowed default. Ensure that logic in shading handles infinite distances gracefully and doesn’t accidentally produce NaN.


431-446: Separate thickness texture
Using the green channel for thickness is workable, but might cause confusion if teams have standard channel usage. Document it clearly or ensure ext docs specify it.


462-468: Initialize absorption macro
Line 467 always enables _absorptionMacro. If a material starts with [1,1,1] attenuation color, it’s effectively no absorption. You toggle it off later if the color changes to zero sum, but consider the overhead of enabling macros by default.


487-498: Absorption toggling
The logic to compare the sum of [r, g, b] to 0 is simple and effective, though borderline user cases (like [0.0001, 0, 0]) might be flagged differently than if it were truly zero. If sensitivity becomes an issue, consider a small epsilon check.

packages/shader-shaderlab/src/shaders/PBR.gs (1)

58-61: Consider making these property names more explicit.

Your new properties, material_Transmission and material_TransmissionTexture, suitably extend the shader for handling refraction. However, consider refactoring names to make their usage even clearer, for example:

  • TransmissionFactor to emphasize that the property is a blend factor.
  • TransmissionTexture to clarify that it is a texture controlling how light transmits.

If you'd like a sample rename to clarify these properties’ roles, let me know!

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90c3228 and 2764f86.

⛔ Files ignored due to path filters (7)
  • packages/shader-shaderlab/src/shaders/Common.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/BRDF.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/Refraction.glsl is excluded by !**/*.glsl
📒 Files selected for processing (8)
  • packages/core/src/material/PBRMaterial.ts (6 hunks)
  • packages/core/src/material/enums/Refraction.ts (1 hunks)
  • packages/core/src/material/index.ts (1 hunks)
  • packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts (2 hunks)
  • packages/loader/src/gltf/extensions/KHR_materials_transmission.ts (1 hunks)
  • packages/loader/src/gltf/extensions/KHR_materials_volume.ts (1 hunks)
  • packages/shader-shaderlab/src/shaders/PBR.gs (1 hunks)
  • packages/shader-shaderlab/src/shaders/shadingPBR/index.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/core/src/material/enums/Refraction.ts
🔇 Additional comments (14)
packages/loader/src/gltf/extensions/KHR_materials_volume.ts (1)

17-24: Convert attenuation color carefully
The code correctly converts linear-to-gamma space for the attenuation color. Verify that any user-facing values or GLTF schema usage clarifies that input colors are linear, to avoid confusion about color space.

packages/core/src/material/PBRMaterial.ts (9)

32-37: Macros naming consistency
The newly added macros (_refractionMacro, _transmissionMacro, _thicknessMacro, _absorptionMacro, etc.) follow a clear pattern. Keep future macros consistent in naming and usage to avoid confusion and improve maintainability.


38-44: Shader property references
These new shader properties (_transmissionProp, _transmissionTextureProp, etc.) are well-organized. Verify that these names are synced with the shader code to avoid mismatches or typos.


45-51: Preserve backward compatibility
The new _refractionMode field changes how rendering queues are managed. Confirm that existing code without setting refractionMode will continue to behave as expected (e.g., defaulting to RefractionMode.None).


318-328: Dynamic render queue adjustment
When refractionMode changes from or to None, the renderQueueType is toggled between transparent and the last known queue. This logic is intuitive, but watch for scenarios where the user might require a specific queue while still using partial refraction.


338-344: Alpha cutoff synergy
The alpha cutoff logic also reverts the render queue to transparent if refraction is enabled. This is correct for many workflows, but confirm with design if alpha-cut transparency plus refraction is a valid combination for all cases.


346-364: Transmission factor logic
The macro is enabled or disabled based on a zero vs. non-zero check. This is an efficient approach, but be sure any intermediate fractional values near zero (like 0.0001) behave as intended.


411-429: Thickness macro toggling
Like transmission, thickness toggles its macro by checking zero vs non-zero. Confirm partial thickness values effectively trigger the correct macros.


470-474: Range recalculations
Iridescence thickness range triggers a recalculation in _onValueChanged. This is a good pattern. Confirm the performance is acceptable for frequent updates, especially if driven by animations or user interactions.
[approve]


510-528: Refraction macro management
Disabling _refractionMacro in the None case is correct, but the “REFRACTION_MODE” macro might remain set. Confirm that enabling _refractionMacro with a different define overwrites the old define, or explicitly clear it to avoid stale states.

packages/core/src/material/index.ts (1)

11-11: Exporting the RefractionMode enum
Exporting RefractionMode here is a clean approach for increasing accessibility. Confirm that this new export does not introduce naming collisions or overshadow existing symbols.

packages/shader-shaderlab/src/shaders/shadingPBR/index.ts (2)

11-12: New shader imports
Adding Refraction and BTDF is logical given the new material capabilities. Ensure the included GLSL files compile correctly under all rendering backends.


24-26: Extended shader pipeline
Appending slices for Refraction and BTDF in the exported array improves readability and keeps them in a clear layering near ReflectionLobe. Looks good.

packages/loader/src/gltf/extensions/GLTFExtensionSchema.ts (1)

Line range hint 191-220: Ensure consistent usage of optional fields in calling code.

The newly introduced IKHRMaterialsVolume interface includes multiple optional fields (e.g., thicknessFactor, attenuationDistance). This design is flexible, but ensure that all calling code checks for undefined when handling these fields to avoid runtime errors or unexpected behaviors.

Search for usage of IKHRMaterialsVolume to ensure that calling code properly handles null/undefined fields:

✅ Verification successful

Let me gather more information about how the texture is handled.


Let me try a different pattern to get the implementation.


Let me check one more thing about the texture handling.


Optional fields are properly handled in the implementation

After reviewing the implementation in KHR_materials_volume.ts, I can confirm that all optional fields from IKHRMaterialsVolume are handled safely:

  • Default values are provided for optional numeric fields: thicknessFactor = 0 and attenuationDistance = Infinity
  • attenuationColor is checked with an if condition before use: if (attenuationColor) { ... }
  • thicknessTexture is checked with an if condition before use: if (thicknessTexture) { ... }

The implementation in PBRMaterial class also handles the texture property safely with proper null checks in the setter:

set thicknessTexture(value: Texture2D) {
  this.shaderData.setTexture(PBRMaterial._thicknessTextureProp, value);
  if (value) {
    this.shaderData.enableMacro(PBRMaterial._thicknessTextureMacro);
  } else {
    this.shaderData.disableMacro(PBRMaterial._thicknessTextureMacro);
  }
}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Use ast-grep or rg to look for interface usage and references to these properties
rg -A 5 'IKHRMaterialsVolume'

Length of output: 1885


Script:

#!/bin/bash
# Check the full implementation of KHR_materials_volume to see texture handling
ast-grep --pattern 'class KHR_materials_volume {
  $$$
}'

Length of output: 59


Script:

#!/bin/bash
# Check the full implementation of KHR_materials_volume
rg -A 15 "class KHR_materials_volume"

Length of output: 1696


Script:

#!/bin/bash
# Check for texture handling in the rest of the implementation
rg -A 10 "thicknessTexture"

Length of output: 6326

@GuoLei1990 GuoLei1990 added enhancement New feature or request Rendering Rendering related functions labels Dec 26, 2024
// @ts-ignore
this._iridescenceRange._onValueChanged = this._onIridescenceRangeChanged.bind(this);
this._iridescenceRange._onValueChanged = () => {
Copy link
Member

Choose a reason for hiding this comment

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

Use bind this is more readability

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
packages/core/src/material/PBRMaterial.ts (1)

Line range hint 470-498: Consider using a type-safe approach instead of @ts-ignore.

The current implementation uses @ts-ignore to bypass TypeScript checks. Consider creating proper interfaces or types for the value change handlers.

+interface ValueChangeNotifier {
+  _onValueChanged?: () => void;
+}

+class ObservableVector2 extends Vector2 implements ValueChangeNotifier {
+  _onValueChanged?: () => void;
+}

+class ObservableColor extends Color implements ValueChangeNotifier {
+  _onValueChanged?: () => void;
+}

   constructor(engine: Engine) {
     // ...
-    // @ts-ignore
-    this._iridescenceRange._onValueChanged = () => {
+    (this._iridescenceRange as ValueChangeNotifier)._onValueChanged = () => {
🧹 Nitpick comments (5)
packages/core/src/material/PBRMaterial.ts (5)

318-328: Add input validation for refractionMode.

Consider adding null/undefined check and type validation to ensure the refractionMode value is valid.

 set refractionMode(value: RefractionMode) {
+  if (value === undefined || value === null) {
+    value = RefractionMode.None;
+  }
+  if (!Object.values(RefractionMode).includes(value)) {
+    throw new Error(`Invalid RefractionMode value: ${value}`);
+  }
   if (value !== this._refractionMode) {
     if (value) {

330-344: Consider extracting common queue type logic.

Both override methods share similar logic for handling render queue type. Consider extracting this into a private method to improve maintainability.

+  private _updateRenderQueueType(): void {
+    this._lastRenderQueueType = this.renderState.renderQueueType;
+    if (this.refractionMode !== RefractionMode.None) {
+      this.renderState.renderQueueType = RenderQueueType.Transparent;
+    }
+  }

   override set isTransparent(value: boolean) {
     super.isTransparent = value;
-    this._lastRenderQueueType = this.renderState.renderQueueType;
-    if (this.refractionMode !== RefractionMode.None) {
-      this.renderState.renderQueueType = RenderQueueType.Transparent;
-    }
+    this._updateRenderQueueType();
   }

   override set alphaCutoff(value: number) {
     super.alphaCutoff = value;
-    this._lastRenderQueueType = this.renderState.renderQueueType;
-    if (this.refractionMode !== RefractionMode.None) {
-      this.renderState.renderQueueType = RenderQueueType.Transparent;
-    }
+    this._updateRenderQueueType();
   }

383-409: Consider using a constant for the default attenuation color.

For better maintainability and to avoid magic values, consider defining a constant for the default white color (1,1,1).

+  private static readonly DEFAULT_ATTENUATION_COLOR = new Color(1, 1, 1);

   constructor(engine: Engine) {
     // ...
-    const attenuationColor = new Color(1, 1, 1);
+    const attenuationColor = PBRMaterial.DEFAULT_ATTENUATION_COLOR.clone();
     // ...
   }

462-468: Consider using constants for default values.

For better maintainability and to avoid magic values, consider defining constants for default transmission, thickness, and attenuation distance values.

+  private static readonly DEFAULT_TRANSMISSION = 0;
+  private static readonly DEFAULT_THICKNESS = 0;
+  private static readonly DEFAULT_ATTENUATION_DISTANCE = Infinity;

   constructor(engine: Engine) {
     // ...
-    shaderData.setFloat(PBRMaterial._transmissionProp, 0);
-    shaderData.setFloat(PBRMaterial._thicknessProp, 0);
-    shaderData.setFloat(PBRMaterial._attenuationDistanceProp, Infinity);
+    shaderData.setFloat(PBRMaterial._transmissionProp, PBRMaterial.DEFAULT_TRANSMISSION);
+    shaderData.setFloat(PBRMaterial._thicknessProp, PBRMaterial.DEFAULT_THICKNESS);
+    shaderData.setFloat(PBRMaterial._attenuationDistanceProp, PBRMaterial.DEFAULT_ATTENUATION_DISTANCE);

510-528: Consider using a map for refraction mode configurations.

The switch statement could be replaced with a map to make it more maintainable and easier to extend.

+  private static readonly REFRACTION_MODE_CONFIG = {
+    [RefractionMode.None]: {
+      enableRefraction: false,
+      mode: null
+    },
+    [RefractionMode.Sphere]: {
+      enableRefraction: true,
+      mode: "SPHERE"
+    },
+    [RefractionMode.Plane]: {
+      enableRefraction: true,
+      mode: "PLANE"
+    },
+    [RefractionMode.Thin]: {
+      enableRefraction: true,
+      mode: "THIN"
+    }
+  };

   private _setRefractionMode(refractionMode: RefractionMode): void {
-    switch (refractionMode) {
-      case RefractionMode.None:
-        this.shaderData.disableMacro(PBRMaterial._refractionMacro);
-        break;
-      case RefractionMode.Sphere:
-        this.shaderData.enableMacro(PBRMaterial._refractionMacro);
-        this.shaderData.enableMacro("REFRACTION_MODE", "SPHERE");
-        break;
-      case RefractionMode.Plane:
-        this.shaderData.enableMacro(PBRMaterial._refractionMacro);
-        this.shaderData.enableMacro("REFRACTION_MODE", "PLANE");
-        break;
-      case RefractionMode.Thin:
-        this.shaderData.enableMacro(PBRMaterial._refractionMacro);
-        this.shaderData.enableMacro("REFRACTION_MODE", "THIN");
-        break;
+    const config = PBRMaterial.REFRACTION_MODE_CONFIG[refractionMode];
+    if (config.enableRefraction) {
+      this.shaderData.enableMacro(PBRMaterial._refractionMacro);
+      if (config.mode) {
+        this.shaderData.enableMacro("REFRACTION_MODE", config.mode);
+      }
+    } else {
+      this.shaderData.disableMacro(PBRMaterial._refractionMacro);
     }
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2764f86 and 141095a.

⛔ Files ignored due to path filters (6)
  • packages/shader-shaderlab/src/shaders/shadingPBR/BRDF.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/Refraction.glsl is excluded by !**/*.glsl
📒 Files selected for processing (2)
  • packages/core/src/material/PBRMaterial.ts (6 hunks)
  • packages/shader-shaderlab/src/shaders/PBR.gs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shader-shaderlab/src/shaders/PBR.gs
🔇 Additional comments (3)
packages/core/src/material/PBRMaterial.ts (3)

32-50: LGTM! Well-organized shader properties and macros.

The static properties and private fields are well-structured and follow consistent naming conventions.


346-381: LGTM! Well-implemented transmission properties.

The implementation includes proper value validation, efficient macro handling, and clear documentation.


411-446: LGTM! Well-implemented thickness properties.

The implementation includes proper value validation, efficient macro handling, and clear documentation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/core/src/material/PBRMaterial.ts (3)

309-327: Consider initializing _lastRenderQueueType in the constructor.

While the refractionMode handling is correct, _lastRenderQueueType should be initialized in the constructor to ensure it has a valid value before the first mode change.

 constructor(engine: Engine) {
   super(engine, Shader.find("pbr"));
+  this._lastRenderQueueType = this.renderState.renderQueueType;
   // ... rest of the constructor
 }

329-343: Extract common render queue type logic to reduce duplication.

The logic for updating renderQueueType is duplicated in both isTransparent and alphaCutoff setters.

+ private _updateRenderQueueType(): void {
+   this._lastRenderQueueType = this.renderState.renderQueueType;
+   if (this.refractionMode !== RefractionMode.None) {
+     this.renderState.renderQueueType = RenderQueueType.Transparent;
+   }
+ }

  override set isTransparent(value: boolean) {
    super.isTransparent = value;
-   this._lastRenderQueueType = this.renderState.renderQueueType;
-   if (this.refractionMode !== RefractionMode.None) {
-     this.renderState.renderQueueType = RenderQueueType.Transparent;
-   }
+   this._updateRenderQueueType();
  }

  override set alphaCutoff(value: number) {
    super.alphaCutoff = value;
-   this._lastRenderQueueType = this.renderState.renderQueueType;
-   if (this.refractionMode !== RefractionMode.None) {
-     this.renderState.renderQueueType = RenderQueueType.Transparent;
-   }
+   this._updateRenderQueueType();
  }

Line range hint 470-498: Consider improving type definitions to avoid @ts-ignore.

The use of @ts-ignore for accessing _onValueChanged suggests that the type definitions could be improved to properly type these event handlers.

Consider defining an interface for the value change notification:

interface ValueChangeNotifier {
  _onValueChanged?: () => void;
}

class Vector2 implements ValueChangeNotifier {
  _onValueChanged?: () => void;
}

class Color implements ValueChangeNotifier {
  _onValueChanged?: () => void;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 141095a and 36c994c.

📒 Files selected for processing (4)
  • packages/core/src/material/PBRMaterial.ts (6 hunks)
  • packages/core/src/material/enums/Refraction.ts (1 hunks)
  • packages/loader/src/gltf/extensions/KHR_materials_transmission.ts (1 hunks)
  • packages/loader/src/gltf/extensions/KHR_materials_volume.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/loader/src/gltf/extensions/KHR_materials_transmission.ts
  • packages/loader/src/gltf/extensions/KHR_materials_volume.ts
  • packages/core/src/material/enums/Refraction.ts
🔇 Additional comments (5)
packages/core/src/material/PBRMaterial.ts (5)

32-44: LGTM! Well-organized shader properties and macros.

The new static properties for transmission, thickness, and absorption features follow consistent naming patterns and are properly typed.


345-380: LGTM! Well-implemented transmission properties.

The implementation includes proper value clamping, correct shader macro handling, and clear documentation.


382-408: LGTM! Proper implementation of attenuation properties.

The implementation includes appropriate value validation and consistent color handling.


410-445: LGTM! Well-implemented thickness properties.

The implementation includes proper value validation, correct shader macro handling, and clear documentation.


461-468: LGTM! Proper initialization of new properties.

The constructor properly initializes all new properties with sensible default values.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/core/src/material/PBRMaterial.ts (1)

513-525: ⚠️ Potential issue

Improve refraction mode handling.

This implementation has the same issues as previously identified:

  1. It doesn't handle RefractionMode.None
  2. It doesn't disable the previously enabled macro before setting a new one

Please refer to the previous review comment for the suggested fix.

🧹 Nitpick comments (2)
packages/core/src/material/PBRMaterial.ts (2)

329-345: Reduce code duplication in transparency handling.

The logic for handling transmission-based transparency is duplicated in both isTransparent and alphaCutoff setters.

Consider extracting the common logic:

+private _updateTransparencyQueue(): void {
+  this._lastRenderQueueType = this.renderState.renderQueueType;
+  if (this.transmission > 0) {
+    // If transmission enabled, always use transparent queue to ensure get correct opaque texture
+    this.renderState.renderQueueType = RenderQueueType.Transparent;
+  }
+}

 override set isTransparent(value: boolean) {
   super.isTransparent = value;
-  this._lastRenderQueueType = this.renderState.renderQueueType;
-  if (this.transmission > 0) {
-    // If transmission enabled, always use transparent queue to ensure get correct opaque texture
-    this.renderState.renderQueueType = RenderQueueType.Transparent;
-  }
+  this._updateTransparencyQueue();
 }

 override set alphaCutoff(value: number) {
   super.alphaCutoff = value;
-  this._lastRenderQueueType = this.renderState.renderQueueType;
-  if (this.transmission > 0) {
-    // If transmission enabled, always use transparent queue to ensure get correct opaque texture
-    this.renderState.renderQueueType = RenderQueueType.Transparent;
-  }
+  this._updateTransparencyQueue();
 }

Line range hint 473-501: Consider improving type safety in event handlers.

The current implementation uses @ts-ignore to bypass TypeScript type checking, which might hide potential issues.

Consider using proper TypeScript features:

  1. Define proper types for the event handlers:
interface ValueChangeHandler {
  _onValueChanged: () => void;
}

class Vector2 implements ValueChangeHandler {
  _onValueChanged?: () => void;
  // ... rest of the implementation
}

class Color implements ValueChangeHandler {
  _onValueChanged?: () => void;
  // ... rest of the implementation
}
  1. Remove the @ts-ignore comments once proper types are in place.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36c994c and 2928dcc.

📒 Files selected for processing (1)
  • packages/core/src/material/PBRMaterial.ts (6 hunks)
🔇 Additional comments (4)
packages/core/src/material/PBRMaterial.ts (4)

32-50: LGTM! Well-structured static properties and fields.

The new static properties and fields are well-organized and follow consistent naming conventions.


347-383: LGTM! Well-implemented transmission properties.

The transmission properties are well-implemented with proper value validation, macro handling, and clear documentation.


385-448: LGTM! Well-implemented attenuation and thickness properties.

The properties are well-implemented with proper value validation, macro handling, and clear documentation.


464-471: LGTM! Good initialization of new properties.

The constructor properly initializes all new properties with sensible default values.

packages/core/src/material/PBRMaterial.ts Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/core/src/material/PBRMaterial.ts (3)

44-49: Consider initializing _refractionMode with RefractionMode.None.

The _refractionMode field is declared but not initialized with a default value. Consider initializing it with RefractionMode.None for better type safety.

- private _refractionMode: RefractionMode;
+ private _refractionMode: RefractionMode = RefractionMode.None;

348-359: Consider adding early return for unchanged values.

The transmission setter could be optimized by adding an early return when the value hasn't changed.

 set transmission(value: number) {
   value = MathUtil.clamp(value, 0, 1);
+  const currentValue = this.shaderData.getFloat(PBRMaterial._transmissionProp);
+  if (value === currentValue) return;
+
   if (!!this.shaderData.getFloat(PBRMaterial._transmissionProp) !== !!value) {
     if (value > 0) {
       this.shaderData.enableMacro(PBRMaterial._transmissionMacro);
       this.renderState.renderQueueType = RenderQueueType.Transparent;
     } else {
       this.shaderData.disableMacro(PBRMaterial._transmissionMacro);
     }
   }
   this.shaderData.setFloat(PBRMaterial._transmissionProp, value);
 }

457-463: Consider documenting the default refraction mode.

The constructor sets RefractionMode.Plane as the default mode, but this isn't documented in the class or property documentation.

Add a comment to document the default value:

 /**
  * Refraction switch.
  * @remarks Use refractionMode to set the refraction shape.
+ * @defaultValue `RefractionMode.Plane`
  */
 get refractionMode(): RefractionMode {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2928dcc and 26c7fd5.

📒 Files selected for processing (1)
  • packages/core/src/material/PBRMaterial.ts (6 hunks)
🔇 Additional comments (5)
packages/core/src/material/PBRMaterial.ts (5)

32-42: LGTM! Well-organized static property declarations.

The static properties for transmission, thickness, and absorption features are properly defined using ShaderMacro and ShaderProperty.


324-338: LGTM! Proper handling of transparency with transmission.

The overrides for isTransparent and alphaCutoff correctly ensure transparent rendering when transmission is enabled.


506-518: Improve refraction mode handling.

The _setRefractionMode method has two potential issues:

  1. It doesn't handle RefractionMode.None
  2. It doesn't disable the previously enabled macro before setting a new one

466-470: Consider using bind for event handlers.

The current implementation uses arrow functions for event handlers. Using bind would be more readable as suggested in the past review comments.

Also applies to: 483-494


317-322: ⚠️ Potential issue

Fix potential issues in refractionMode setter.

The current implementation doesn't handle the case when switching from a non-None mode to None mode, which could leave the render queue type in an incorrect state.

 set refractionMode(value: RefractionMode) {
   if (value !== this._refractionMode) {
+    if (value !== RefractionMode.None) {
+      this._lastRenderQueueType = this.renderState.renderQueueType;
+      this.renderState.renderQueueType = RenderQueueType.Transparent;
+    } else {
+      this.renderState.renderQueueType = this._lastRenderQueueType;
+    }
     this._refractionMode = value;
     this._setRefractionMode(value);
   }
 }

Likely invalid or redundant comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
packages/core/src/material/PBRMaterial.ts (5)

44-48: Consider initializing fields with default values in the constructor.

Private fields are currently scattered between property declarations and constructor initialization. Consider moving all initializations to the constructor for better maintainability.

-  private _refractionMode: RefractionMode;
-  private _anisotropyRotation: number = 0;
-  private _iridescenceRange = new Vector2(100, 400);
-  private _sheenEnabled = false;
-  private _absorptionEnabled = true;
+  private _refractionMode: RefractionMode;
+  private _anisotropyRotation: number;
+  private _iridescenceRange: Vector2;
+  private _sheenEnabled: boolean;
+  private _absorptionEnabled: boolean;

323-337: Consider consolidating duplicate queue type logic.

The same queue type logic is duplicated in both isTransparent and alphaCutoff setters.

+  private _updateQueueType(): void {
+    if (this.transmission > 0) {
+      // If transmission enabled, always use transparent queue to ensure get correct opaque texture
+      this.renderState.renderQueueType = RenderQueueType.Transparent;
+    }
+  }

   override set isTransparent(value: boolean) {
     super.isTransparent = value;
-    if (this.transmission > 0) {
-      // If transmission enabled, always use transparent queue to ensure get correct opaque texture
-      this.renderState.renderQueueType = RenderQueueType.Transparent;
-    }
+    this._updateQueueType();
   }

   override set alphaCutoff(value: number) {
     super.alphaCutoff = value;
-    if (this.transmission > 0) {
-      // If transmission enabled, always use transparent queue to ensure get correct opaque texture
-      this.renderState.renderQueueType = RenderQueueType.Transparent;
-    }
+    this._updateQueueType();
   }

347-358: Improve transmission value change detection.

The current implementation uses a double negation (!!) to compare boolean states. Consider using a more explicit comparison.

   set transmission(value: number) {
     value = MathUtil.clamp(value, 0, 1);
-    if (!!this.shaderData.getFloat(PBRMaterial._transmissionProp) !== !!value) {
+    const currentValue = this.shaderData.getFloat(PBRMaterial._transmissionProp);
+    const hasTransmission = value > 0;
+    const hadTransmission = currentValue > 0;
+    if (hasTransmission !== hadTransmission) {
       if (value > 0) {
         this.shaderData.enableMacro(PBRMaterial._transmissionMacro);
         this.renderState.renderQueueType = RenderQueueType.Transparent;
       } else {
         this.shaderData.disableMacro(PBRMaterial._transmissionMacro);
       }
     }
     this.shaderData.setFloat(PBRMaterial._transmissionProp, value);
   }

413-423: Similar improvement needed for thickness value change detection.

The same double negation pattern is used here. Consider using the same explicit comparison pattern as suggested for transmission.

   set thickness(value: number) {
     value = Math.max(0, value);
-    if (!!this.shaderData.getFloat(PBRMaterial._thicknessProp) !== !!value) {
+    const currentValue = this.shaderData.getFloat(PBRMaterial._thicknessProp);
+    const hasThickness = value > 0;
+    const hadThickness = currentValue > 0;
+    if (hasThickness !== hadThickness) {
       if (value > 0) {
         this.shaderData.enableMacro(PBRMaterial._thicknessMacro);
       } else {
         this.shaderData.disableMacro(PBRMaterial._thicknessMacro);
       }
     }
     this.shaderData.setFloat(PBRMaterial._thicknessProp, value);
   }

500-511: Consider using Color methods for color comparison.

Instead of manually adding color components, consider using Color's built-in methods for a more maintainable solution.

   private _attenuationColorChanged(): void {
     const attenuationColor = this.attenuationColor;
-    const enableAbsorption = attenuationColor.r + attenuationColor.g + attenuationColor.b > 0;
+    const enableAbsorption = !attenuationColor.equals(Color.BLACK);
     if (enableAbsorption !== this._absorptionEnabled) {
       this._absorptionEnabled = enableAbsorption;
       if (enableAbsorption) {
         this.shaderData.enableMacro(PBRMaterial._absorptionMacro);
       } else {
         this.shaderData.disableMacro(PBRMaterial._absorptionMacro);
       }
     }
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26c7fd5 and d12ff04.

⛔ Files ignored due to path filters (3)
  • packages/shader-shaderlab/src/shaders/shadingPBR/BRDF.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl is excluded by !**/*.glsl
📒 Files selected for processing (1)
  • packages/core/src/material/PBRMaterial.ts (5 hunks)
🔇 Additional comments (4)
packages/core/src/material/PBRMaterial.ts (4)

32-42: LGTM! Well-organized shader properties and macros.

The static properties are well-organized and follow a consistent naming pattern, making the code maintainable.


316-321: Fix potential issues in refractionMode setter.

The current implementation has two issues:

  1. It doesn't handle the case when value is RefractionMode.None
  2. It doesn't disable the previous mode's macro before setting a new one

456-463: LGTM! Constructor initialization is complete.

All required properties are properly initialized with appropriate default values.


513-525: ⚠️ Potential issue

Fix refraction mode handling.

The current implementation of _setRefractionMode has two issues that were previously identified:

  1. It doesn't handle RefractionMode.None
  2. It doesn't disable the previously enabled macro before setting a new one
   private _setRefractionMode(refractionMode: RefractionMode): void {
+    // Disable previous mode
+    this.shaderData.disableMacro("REFRACTION_MODE");
+
     switch (refractionMode) {
       case RefractionMode.Sphere:
         this.shaderData.enableMacro("REFRACTION_MODE", "SPHERE");
         break;
       case RefractionMode.Plane:
         this.shaderData.enableMacro("REFRACTION_MODE", "PLANE");
         break;
       case RefractionMode.Thin:
         this.shaderData.enableMacro("REFRACTION_MODE", "THIN");
         break;
+      case RefractionMode.None:
+        // No macro needed for None mode
+        break;
     }
   }

Likely invalid or redundant comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/core/src/material/PBRMaterial.ts (3)

45-50: Introduction of new private fields for refraction and absorption.
The fields _refractionMode, _sheenEnabled, and _absorptionEnabled enhance the material's customizable behavior. Just ensure these booleans remain in sync with the corresponding shader macros.


324-353: Overriding isTransparent and alphaCutoff for advanced transmission logic.

  1. Correctly forcing the render queue to Transparent if transmission > 0.
  2. Be cautious of performance implications if unintended transparency states are triggered often.

Would you like assistance with additional tests that confirm queue usage under different alpha cutoff and transmission conditions?


482-484: Attaching _onValueChanged callbacks for color and range fields.
Be sure these listeners are removed if the material is destroyed or cloned excessively, to prevent memory leaks.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d12ff04 and ce75450.

⛔ Files ignored due to path filters (3)
  • packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl is excluded by !**/*.glsl
  • packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl is excluded by !**/*.glsl
📒 Files selected for processing (2)
  • packages/core/src/material/BaseMaterial.ts (4 hunks)
  • packages/core/src/material/PBRMaterial.ts (5 hunks)
🔇 Additional comments (18)
packages/core/src/material/BaseMaterial.ts (6)

27-27: Changing _alphaCutoffProp to protected is appropriate for subclass flexibility.
Exposing this property allows derived materials (e.g., PBRMaterial) to override or refine alpha cutoff behavior. Good job!


31-31: Shifting _isTransparent from private to protected is sensible.
This enables subclasses to access and refine transparent logic in an object-oriented manner.


76-76: Setter now delegates to _seIsTransparent.
Refactoring the logic into a dedicated helper method enhances maintainability and consistency across different sections of the code.


105-105: Setter now delegates to _setAlphaCutoff.
This improves code readability by reducing inline complexity, making the alpha cutoff logic easier to maintain.


237-257: Scrutinize transparency logic to ensure consistent queue updates for shadows.

  1. The new _seIsTransparent method updates both the material's render queue and the shadow caster queue, which is good for consistent shading behavior.
  2. Consider verifying that any specialized blending modes for child classes also hook into this method if required.

259-289: Ensure alpha cutoff logic aligns with partial transparency.

  1. Good job toggling the _alphaCutoffMacro and adjusting the shadow caster queue.
  2. The loop (lines 275–286) correctly sets renderQueueType for each pass based on whether alpha cutoff or transparency is enabled.
  3. Verify that no concurrent macros or blending states remain active when switching from alpha-cut to fully opaque.
packages/core/src/material/PBRMaterial.ts (12)

1-9: New imports and references for advanced PBR capabilities.
The added imports for RefractionMode, Texture2D, and others lay the groundwork for the new PBR features. Ensure these are all used as expected without introducing circular dependencies.


33-44: Definition of transmission/thickness/absorption-related macros.
Expanding macros for new PBR properties is well-structured, but consider verifying that each macro is consistently enabled/disabled to avoid conflicting states during runtime.


309-322: Refraction mode getter and setter.

  1. The refractionMode setter calls _setRefractionMode, which is good for code clarity.
  2. Ensure the old macro (if any) is disabled before enabling a new one to avoid leftover macros from the previous mode.

354-373: Transmission factor handling.

  1. Clever usage of macros for toggling advanced PBR transmission.
  2. Great that you clamp the input [0..1].
  3. Confirm that the disable state reverts to non-transparent queue if no other property (e.g., isTransparent) forces transparency.

375-390: Transmission texture.
Enabling or disabling _transmissionTextureMacro based on the presence of a texture is straightforward. Consider thorough tests to ensure the red channel usage is correct.


392-406: Attenuation color property.

  1. The attenuationColor concept is critical for volumetric and absorption effects.
  2. Confirm possible edge cases if color channels are zero or negative.

407-419: Attenuation distance property.
Clamping to >= 0 prevents invalid negative distances. Ensure that an infinite value is handled gracefully in the shader.


420-438: Thickness property.

  1. Turning the _thicknessMacro on/off is good.
  2. Suggest verifying how zero thickness interacts with partial transmission or absorption in corner use-cases.

440-455: Thickness texture.
Uses the green channel for thickness. This is well-labeled in the docstring; it’s good that you multiply by the thickness factor.


471-478: Constructor initializes default PBR settings.

  1. Defaulting to RefractionMode.Plane ensures a known baseline.
  2. _absorptionMacro is always enabled initially. If attenuation color is black, the _absorptionEnabled eventually toggles off. Good pattern, just confirm it’s consistent.

495-513: Handling iridescence range changes.
Monitoring changes to _iridescenceRange is straightforward. Minimizing direct assignment in the property ensures correctness.


515-526: Absorption color callback.

  1. Solid approach for enabling or disabling _absorptionMacro.
  2. Recommend verifying the relationship between the attenuation color and _absorptionEnabled when color is near zero.

Comment on lines +528 to +540
private _setRefractionMode(refractionMode: RefractionMode): void {
switch (refractionMode) {
case RefractionMode.Sphere:
this.shaderData.enableMacro("REFRACTION_MODE", "SPHERE");
break;
case RefractionMode.Plane:
this.shaderData.enableMacro("REFRACTION_MODE", "PLANE");
break;
case RefractionMode.Thin:
this.shaderData.enableMacro("REFRACTION_MODE", "THIN");
break;
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refraction mode macro setting.

  1. Currently only enabling the new macro; consider disabling previously set macros when switching modes to avoid possible conflicts.
  2. A RefractionMode.None case (if it’s introduced later) would help handle disabling all macros.

Copy link

codecov bot commented Dec 26, 2024

Codecov Report

Attention: Patch coverage is 61.29944% with 137 lines in your changes missing coverage. Please review.

Project coverage is 68.38%. Comparing base (90c3228) to head (ce75450).
Report is 1 commits behind head on dev/1.4.

Files with missing lines Patch % Lines
packages/core/src/material/PBRMaterial.ts 62.11% 86 Missing ⚠️
...loader/src/gltf/extensions/KHR_materials_volume.ts 36.36% 21 Missing ⚠️
packages/core/src/material/BaseMaterial.ts 66.66% 18 Missing and 1 partial ⚠️
.../src/gltf/extensions/KHR_materials_transmission.ts 47.61% 11 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/1.4    #2478      +/-   ##
===========================================
- Coverage    68.43%   68.38%   -0.06%     
===========================================
  Files          922      923       +1     
  Lines        95661    95928     +267     
  Branches      8121     8137      +16     
===========================================
+ Hits         65466    65600     +134     
- Misses       29942    30074     +132     
- Partials       253      254       +1     
Flag Coverage Δ
unittests 68.38% <61.29%> (-0.06%) ⬇️

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

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

@GuoLei1990 GuoLei1990 merged commit ab48451 into galacean:dev/1.4 Dec 26, 2024
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Rendering Rendering related functions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants