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

CamerasetReplacementShader support ReplacementFailureStrategy when failed #2163

Merged
merged 4 commits into from
Jul 13, 2024

Conversation

cptbtptpbcptdtptp
Copy link
Collaborator

@cptbtptpbcptdtptp cptbtptpbcptdtptp commented Jul 9, 2024

Demo:

/**
 * @title Shader Replacement
 * @category Material
 */
import {
  AmbientLight,
  AssetType,
  BackgroundMode,
  Camera,
  DirectLight,
  GLTFResource,
  Logger,
  MeshRenderer,
  PrimitiveMesh,
  Shader,
  SkyBoxMaterial,
  SubShader,
  Texture2D,
  UnlitMaterial,
  WebGLEngine,
} from "@galacean/engine";
import { OrbitControl } from "@galacean/engine-toolkit-controls";
import * as dat from "dat.gui";

/**
 * Main function.
 */
async function main() {
  Logger.enable();

  initShader();

  // Create engine
  const engine = await WebGLEngine.create({ canvas: "canvas" });
  engine.canvas.resizeByClientSize();

  // Get scene and create root entity
  const scene = engine.sceneManager.activeScene;
  const rootEntity = scene.createRootEntity();

  // Create directional light
  const directLightEntity = rootEntity.createChild("Directional Light");
  directLightEntity.addComponent(DirectLight);
  directLightEntity.transform.setRotation(30, 0, 0);

  const directLightEntity2 = rootEntity.createChild("Directional Light2");
  directLightEntity2.addComponent(DirectLight);
  directLightEntity2.transform.setRotation(-30, 180, 0);

  // Create camera
  const cameraEntity = rootEntity.createChild("Camera");
  cameraEntity.transform.setPosition(0, 0, 5);
  const camera = cameraEntity.addComponent(Camera);
  cameraEntity.addComponent(OrbitControl);

  // Create sky
  const background = scene.background;
  background.mode = BackgroundMode.Sky;

  const sky = background.sky;
  const skyMaterial = new SkyBoxMaterial(engine);
  sky.material = skyMaterial;
  sky.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);

  engine.resourceManager
    .load([
      {
        type: AssetType.Env,
        url: "https://gw.alipayobjects.com/os/bmw-prod/f369110c-0e33-47eb-8296-756e9c80f254.bin",
      },
      {
        url: "https://gw.alipayobjects.com/os/bmw-prod/150e44f6-7810-4c45-8029-3575d36aff30.gltf",
        type: AssetType.GLTF,
      },
      {
        url: "https://gw.alipayobjects.com/os/OasisHub/267000040/9994/%25E5%25BD%2592%25E6%25A1%25A3.gltf",
        type: AssetType.GLTF,
      },
      {
        url: "https://mdn.alipayobjects.com/huamei_b4l2if/afts/img/A*Q60vQ40ZERsAAAAAAAAAAAAADil6AQ/original",
        type: AssetType.Texture2D,
      },
    ])
    .then((resources) => {
      // Add ambient light
      const ambientLight = <AmbientLight>resources[0];
      scene.ambientLight = ambientLight;
      skyMaterial.texture = ambientLight.specularTexture;
      skyMaterial.textureDecodeRGBM = true;

      // Add duck model
      const glTFResourceDuck = <GLTFResource>resources[2];
      const duckEntity = glTFResourceDuck.defaultSceneRoot;
      duckEntity.transform.position.set(1, -1, 0);
      rootEntity.addChild(duckEntity);

      Shader.find("pbr").subShaders.forEach((subShader: SubShader) => {
        subShader.setTag("CanReplace", true);
      });

      // Add Ball
      const entity = rootEntity.createChild("Ball");
      entity.transform.setPosition(0, 1, 0);
      const renderer = entity.addComponent(MeshRenderer);
      renderer.mesh = PrimitiveMesh.createSphere(engine, 0.5);
      renderer.setMaterial(new UnlitMaterial(engine));

      // Apply uv check texture
      const uvCheckTexture = <Texture2D>resources[3];
      for (const material of glTFResourceDuck.materials!) {
        material.shaderData.setTexture("u_UVCheckTexture", uvCheckTexture);
      }

      // Run engine
      engine.run();

      // Add debug GUI to switch replacement shader
      addDebugGUI(camera);
    });
}
main();

/**
 * Init replacement shader.
 */
function initShader() {
  const normalVS = `
  #include <common>
  #include <common_vert>
  #include <blendShape_input>
  #include <normal_share>
  
  void main() {
  
      #include <begin_position_vert>
      #include <begin_normal_vert>
      #include <blendShape_vert>
      #include <skinning_vert>
      #include <normal_vert>
      #include <position_vert>
  }`;

  const normalFS = `
  #include <common>
  #include <normal_share>
  
  void main() {
   gl_FragColor = vec4(v_normal,1.0);
  }
  `;

  const uvCheckVS = `
  #include <common>
  #include <common_vert>
  #include <blendShape_input>
  #include <uv_share>
  
  void main() {
  
    #include <begin_position_vert>
    #include <blendShape_vert>
    #include <skinning_vert>
    #include <uv_vert>
    #include <position_vert>
  }`;

  const uvCheckFS = `
  #include <common>
  #include <uv_share>
  
  uniform sampler2D u_UVCheckTexture;
  
  void main() {
    vec4 textureColor = texture2D(u_UVCheckTexture, v_uv);
    gl_FragColor = textureColor;
  }
  `;

  // Create normal shader
  let shader = Shader.create("NormalShader", normalVS, normalFS);
  shader.subShaders.forEach((subShader: SubShader) => {
    subShader.setTag("CanReplace", true);
  });
  // Create uv check shader
  shader = Shader.create("UVCheckShader", uvCheckVS, uvCheckFS);
  Shader.find("UVCheckShader");
  shader.subShaders.forEach((subShader: SubShader) => {
    subShader.setTag("CanReplace", true);
  });
}

/**
 * Add debug GUI to switch replacement shader.
 * @param camera - Camera to render scene
 */
function addDebugGUI(camera: Camera): void {
  enum RenderMode {
    PBR = "PBR Shader(No replacement)",
    Normal = "Replacement normal Shader",
    UVCheck = "Replacement UVCheck Shader",
  }

  const debugGUI = new dat.GUI({
    width: 350,
  });

  const state = {
    "Render Mode": RenderMode.PBR,
  };
  debugGUI
    .add(state, "Render Mode", [
      RenderMode.PBR,
      RenderMode.Normal,
      RenderMode.UVCheck,
    ])
    .onChange((v: string) => {
      switch (v) {
        case RenderMode.PBR:
          camera.resetReplacementShader();
          break;
        case RenderMode.Normal:
          camera.setReplacementShader(
            Shader.find("NormalShader"),
            "CanReplace"
          );
          break;
        case RenderMode.UVCheck:
          camera.setReplacementShader(
            Shader.find("UVCheckShader"),
            "CanReplace"
          );
          break;
      }
    });
}

Summary by CodeRabbit

  • New Features

    • Introduced ReplacementFailureStrategy enum for handling shader replacement failures.
    • Enhanced Camera class with new shader replacement strategies.
  • Bug Fixes

    • Improved shader replacement logic in BasicRenderPipeline to handle tags and passes correctly.
  • Tests

    • Added tests to verify new shader replacement strategies in Camera functionality.
  • Chores

    • Reorganized and updated exports in core package for better asset management and rendering features.

@cptbtptpbcptdtptp cptbtptpbcptdtptp self-assigned this Jul 9, 2024
Copy link

coderabbitai bot commented Jul 9, 2024

Walkthrough

The recent changes focus on enhancing shader management within the rendering pipeline. A significant addition is the ReplacementFailureStrategy enum for handling shader replacement failures, integrated across various files including BasicRenderPipeline and Camera. New properties and methods have been added to support this strategy, and exports within the core package have been restructured to reflect these updates. Additionally, tests have been updated to ensure the new shader strategies are correctly implemented.

Changes

File Path Change Summary
packages/core/src/.../BasicRenderPipeline.ts Adjusted shader replacement logic, added materialSubShaderTagValue handling, initialized passes variable, updated pushRenderDataWithShader method, added import.
packages/core/src/Camera.ts Added _replacementFailureStrategy property, modified setReplacementShader method to include failureStrategy parameter, and handled the new parameter.
packages/core/src/RenderPipeline/RenderContext.ts Added a new public entity replacementFailureStrategy for shader replacement strategies.
packages/core/src/enums/ReplacementFailureStrategy.ts Introduced a new enum ReplacementFailureStrategy defining strategies for handling shader replacement failures: KeepOriginalShader and DoNotRender.
packages/core/src/index.ts Reordered and added exports, replaced Canvas with Camera, restructured ComponentsDependencies, added ReplacementFailureStrategy to exports.
tests/src/core/Camera.test.ts Added ReplacementFailureStrategy and Shader imports, introduced shader-related operations, included tests for setting and resetting replacement shaders.

Poem

In the world of shaders, a change so bright,
Strategies now handle failures with might,
Keep the original or render no more,
Camera and pipeline, new features they store.
Code restructured, exports realigned,
In this update, solutions you'll find.
For the art of rendering, the future's refined. 🌟


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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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 as 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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.

@cptbtptpbcptdtptp cptbtptpbcptdtptp added the bug Something isn't working label Jul 9, 2024
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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ae79e6c and 454b0c4.

Files selected for processing (1)
  • packages/core/src/RenderPipeline/BasicRenderPipeline.ts (1 hunks)
Additional comments not posted (4)
packages/core/src/RenderPipeline/BasicRenderPipeline.ts (4)

214-214: Ensure the correctness of materialSubShaderTagValue.

The materialSubShaderTagValue is correctly obtained from the materialSubShader using the getTagValue method. This ensures that the tag value is properly fetched for comparison in subsequent logic.


215-215: Initialize passes variable to default shader passes.

The passes variable is initialized to the default shader passes from materialSubShader. This ensures that if no replacement shader matches, the default shader passes are used.


218-219: Update passes variable if replacement shader matches.

The loop iterates through the replacementSubShaders to find a matching tag value. If a match is found, the passes variable is updated to use the matching subshader's passes. This ensures that the correct shader passes are used based on the tag value.


223-223: Utilize the updated passes variable in pushRenderDataWithShader.

The passes variable, which may have been updated based on the replacement shader, is passed to the pushRenderDataWithShader method. This ensures that the correct shader passes are used during rendering.

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 454b0c4 and cc12936.

Files selected for processing (1)
  • packages/core/src/RenderPipeline/BasicRenderPipeline.ts (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/RenderPipeline/BasicRenderPipeline.ts

@GuoLei1990
Copy link
Member

GuoLei1990 commented Jul 12, 2024

API design to solve this need:

  /**
   * Set the replacement shader.
   * @param shader - Replacement shader
   * @param replacementTagName - Sub shader tag name
   * @param failureStrategy - Replacement failure strategy, @defaultValue `ReplacementFailureStrategy.KeepOriginalShader`
   *
   * @remarks
   * If replacementTagName is not specified, the first sub shader will be replaced.
   * If replacementTagName is specified, the replacement shader will find the first sub shader which has the same tag value get by replacementTagKey. If failed to find the sub shader, the strategy will be determined by failureStrategy.
   */
  setReplacementShader(shader: Shader, replacementTagName?: string, failureStrategy?: ReplacementFailureStrategy): void;

  /**
   * Set the replacement shader.
   * @param shader - Replacement shader
   * @param replacementTag - Sub shader tag
   * @param failureStrategy - Replacement failure strategy, @defaultValue `ReplacementFailureStrategy.KeepOriginalShader`
   *
   * @remarks
   * If replacementTag is not specified, the first sub shader will be replaced.
   * If replacementTag is specified, the replacement shader will find the first sub shader which has the same tag value get by replacementTagKey. If failed to find the sub shader, the strategy will be determined by failureStrategy.
   */
  setReplacementShader(shader: Shader, replacementTag?: ShaderTagKey, failureStrategy?: ReplacementFailureStrategy);

  setReplacementShader(
    shader: Shader,
    replacementTag?: string | ShaderTagKey,
    failureStrategy: ReplacementFailureStrategy = ReplacementFailureStrategy.KeepOriginalShader
  ): void {
    this._replacementShader = shader;
    this._replacementSubShaderTag =
      typeof replacementTag === "string" ? ShaderTagKey.getByName(replacementTag) : replacementTag;
    // @todo: failureStrategy
  }
/**
 * Replacement failure strategy.
 */
export enum ReplacementFailureStrategy {
  /** Keep the original shader. */
  KeepOriginalShader,
  /** Do not render. */
  DoNotRender
}

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between cc12936 and 07f7318.

Files selected for processing (6)
  • packages/core/src/Camera.ts (5 hunks)
  • packages/core/src/RenderPipeline/BasicRenderPipeline.ts (2 hunks)
  • packages/core/src/RenderPipeline/RenderContext.ts (2 hunks)
  • packages/core/src/enums/ReplacementFailureStrategy.ts (1 hunks)
  • packages/core/src/index.ts (1 hunks)
  • tests/src/core/Camera.test.ts (2 hunks)
Files skipped from review due to trivial changes (1)
  • packages/core/src/enums/ReplacementFailureStrategy.ts
Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/RenderPipeline/BasicRenderPipeline.ts
Additional comments not posted (10)
packages/core/src/RenderPipeline/RenderContext.ts (2)

4-4: Import statement added for ReplacementFailureStrategy.

The import statement is correctly added to bring in the ReplacementFailureStrategy enum.


32-32: New public property replacementFailureStrategy added.

The new property aligns with the changes to incorporate shader replacement failure strategies.

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

47-47: Export statement added for ReplacementFailureStrategy.

The export statement is correctly added to make the ReplacementFailureStrategy enum available for use in other parts of the application.

tests/src/core/Camera.test.ts (3)

1-1: Import statements added for ReplacementFailureStrategy and Shader.

The import statements are correctly added to bring in the necessary entities for the new test cases.


81-91: Test shaders defined for replacement shader tests.

The vertex and fragment shaders are defined correctly for use in the replacement shader tests.


92-108: Test cases added for setReplacementShader method.

The test cases correctly cover the scenarios for setting and resetting replacement shaders using the ReplacementFailureStrategy.

packages/core/src/Camera.ts (4)

18-18: Import statement added for ReplacementFailureStrategy.

The import statement is correctly added to bring in the ReplacementFailureStrategy enum.


107-107: New private property _replacementFailureStrategy added.

The new property aligns with the changes to incorporate shader replacement failure strategies.


623-651: Updated setReplacementShader method to handle failureStrategy parameter.

The method is correctly updated to handle the failureStrategy parameter and set the appropriate private properties.


660-660: Updated resetReplacementShader method to clear _replacementFailureStrategy.

The method is correctly updated to clear the _replacementFailureStrategy property.

@GuoLei1990 GuoLei1990 added enhancement New feature or request and removed bug Something isn't working labels Jul 13, 2024
@GuoLei1990 GuoLei1990 changed the title Fix camera.setReplacementShader specifies tag causing rendering exception CamerasetReplacementShader support ReplacementFailureStrategy when failed Jul 13, 2024
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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 07f7318 and 45a6d0e.

Files selected for processing (1)
  • packages/core/src/index.ts (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/index.ts

@GuoLei1990 GuoLei1990 merged commit 8ab2056 into galacean:main Jul 13, 2024
6 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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants