Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@noname0310
Copy link
Contributor

@noname0310 noname0310 commented Dec 22, 2025

This PR rewrites the following Node Material implementation.

https://forum.babylonjs.com/t/selection-outliner-blender-style-outlines/61598

Below is how it works in my application. The sphere in the background is highlighted, and you can see the outline becoming dimmer in areas where occlusion occurs.
image

The current implementation is incomplete. It is not yet ready to be merged.

The remaining tasks are as follows:

  • Write WGSL shaders
  • Change to Rendering Pipeline (currently only the name is Rendering Pipeline)

Another consideration is that currently, the Mask render pass is implemented using ShaderMaterial and RenderTargetTexture, rather than being created as a separate renderer class (e.g. DepthRenderer).

While separating it into a distinct Renderer class would improve reusability, I'm concerned that having all binding code (isReady and bindToSubmesh) explicitly exposed might negatively impact maintainability.

Please let me know if there are any design considerations.
I'd especially appreciate it if it could be integrated with Frame Graph.
However, since I haven't used Frame Graph myself, supporting this would likely need to be requested from @Popov72 .

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 22, 2025

Please make sure to label your PR with "bug", "new feature" or "breaking change" label(s).
To prevent this PR from going to the changelog marked it with the "skip changelog" label.

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

Please make sure to label your PR with "bug", "new feature" or "breaking change" label(s).
To prevent this PR from going to the changelog marked it with the "skip changelog" label.

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

Snapshot stored with reference name:
refs/pull/17583/merge

Test environment:
https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/17583/merge/index.html

To test a playground add it to the URL, for example:

https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/17583/merge/index.html#WGZLGJ#4600

Links to test your changes to core in the published versions of the Babylon tools (does not contain changes you made to the tools themselves):

https://playground.babylonjs.com/?snapshot=refs/pull/17583/merge
https://sandbox.babylonjs.com/?snapshot=refs/pull/17583/merge
https://gui.babylonjs.com/?snapshot=refs/pull/17583/merge
https://nme.babylonjs.com/?snapshot=refs/pull/17583/merge

To test the snapshot in the playground with a playground ID add it after the snapshot query string:

https://playground.babylonjs.com/?snapshot=refs/pull/17583/merge#BCU1XR#0

If you made changes to the sandbox or playground in this PR, additional comments will be generated soon containing links to the dev versions of those tools.

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@Popov72
Copy link
Contributor

Popov72 commented Dec 23, 2025

Hey @noname0310.

Thanks for the PR!

We are going to review it asap, but because the team is mostly oof, it can take a little time.

In the meantime, can you provide a PG so that we can test it?

While separating it into a distinct Renderer class would improve reusability, I'm concerned that having all binding code (isReady and bindToSubmesh) explicitly exposed might negatively impact maintainability.

I don't know how we should handle the fact that depth rendering stores an additional identifier with the depth; it's something we need to think about...

I also wonder if it should be in the main package or in the addon/ repository... cc @sebavan (be patient, as he is currently on vacation).

Points to keep in mind:

  • it should work with thin instances
  • it should work for custom shaders that modify vertex positions => this probably means that the pre-pass renderer should be used to generate the depth map

You can have a look at how SSAO2 has been implemented, for an example on how to support both the regular code path and the frame graph path.

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 23, 2025

@noname0310
Copy link
Contributor Author

noname0310 commented Dec 23, 2025

https://playground.babylonjs.com/?snapshot=refs/pull/17583/merge#LA850M#2

As you may have already seen on the forum, I'm sharing the PG.

Currently, rendering the outline of a mesh with thin instances is supported, but rendering each individual thin instance separately is questionable.

This is because rendering only M selected thin instances out of N thin instances belonging to a single mesh requires discarding fragments in the shader or setting the mesh scale to 0 in the vertex transform, which looks quite unnatural.

I plan to understand the implementation using a pre-pass renderer and refactor it to the same level as the existing rendering pipeline. Relatedly, I estimate this might take up to a week. :)

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 24, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 26, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 26, 2025

Raised the occlusionThreshold constant from 0.0000001 to 1.0000001 in both GLSL and WGSL selection outline fragment shaders.
@bjsplat
Copy link
Collaborator

bjsplat commented Dec 26, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 26, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 26, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 26, 2025

@noname0310
Copy link
Contributor Author

The implementation is complete,

but I want to add an optimization that activates post-process and mask rendering only when one or more selections exist,
without applying post-process when there are no selections at all.
(Because when there are no selections, this post-process effectively has no effect.)

Is there a good example I can reference to implement this?

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 28, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 28, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 28, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 28, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

The addSelection and setSelection methods now return early if the meshes array is empty. The setSelection method also supports an optional disablePipeline parameter to dispose the pipeline when the selection is empty.
@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@bjsplat
Copy link
Collaborator

bjsplat commented Dec 30, 2025

@noname0310 noname0310 marked this pull request as ready for review December 30, 2025 07:01
@noname0310
Copy link
Contributor Author

noname0310 commented Dec 30, 2025

Ready for review :)

The SelectionOutlineRenderingPipeline is a rendering pipeline for DCC tools to represent selections.
To achieve this purpose, it is designed to operate with lightweight performance,
utilizing lazy build and deactivating when unnecessary (when no selection exists).

My proposed considerations are as follows:

  • Currently, there is no functionality to render outlines per thininstance, as proposed by @Popov72 .
  • The OutlineMaskRenderer is currently implemented using RTT and ShaderMaterial. However, refactoring it to implement methods like isReady and bindForSubmesh, similar to DepthRenderer, is recommended?.

Here is a test PG:

https://playground.babylonjs.com/?snapshot=refs/pull/17583/merge#LA850M#3

@sebavan
Copy link
Member

sebavan commented Dec 30, 2025

Looks really good in the playground !!!

I will have a detailed look later today, thanks for the patience.

@sebavan sebavan marked this pull request as draft December 30, 2025 21:11
@sebavan
Copy link
Member

sebavan commented Dec 30, 2025

Let me move to draft during our discussion time to prevent accidental merge.

The main point for me would be to see if we could use the geometry buffer to render the depth information as well as the selection info.

Currently we use this selection like shader in both outline and gpu picking and I guess other effects would benefit from this feature.

The feature could then be a simple postprocess or maybe an outline layer if we wanted the flood buffer approach for anti-aliased and sizable outlines.

What do you think ? If it sounds a bit much I could give it a stab on Friday ?

@noname0310
Copy link
Contributor Author

Let me move to draft during our discussion time to prevent accidental merge.

The main point for me would be to see if we could use the geometry buffer to render the depth information as well as the selection info.

Currently we use this selection like shader in both outline and gpu picking and I guess other effects would benefit from this feature.

The feature could then be a simple postprocess or maybe an outline layer if we wanted the flood buffer approach for anti-aliased and sizable outlines.

What do you think ? If it sounds a bit much I could give it a stab on Friday ?

For the GPUPicker, I don’t think rendering a selection ID mask as a postprocess or layer is a good fit. The key reason is that this task doesn’t run every frame. it only renders when the user requests a picking operation.
In other words, the rendering is very intermittent, not part of the normal frame pipeline.

That said, I agree that separating the pipeline for rendering the geometry buffer would be a good idea for reusability.
However, because of the intermittent nature above, I think it would be more appropriate to define it as a renderer rather than implementing it as a postprocess or a layer.

In particular, making it a postprocess doesn’t make sense, since rendering the mask is not a pixel-wise operation.

In my current implementation, I already separated the selection ID rendering into its own SelectionMaskRenderer.

My view is that the right direction is to slightly extend and refactor SelectionMaskRenderer so it becomes reusable for more general use cases as well.

Also, in the selection outline pipeline, I already considered future support for the jump flood(JFA) approach by adding a parameter to choose the method later on.

If making OutlineMaskRenderer more general aligns with what you’re aiming for,
I think I can take that on.
I can implement it by referencing the existing DepthRenderer approach, and also update GPUPicker to use the new code path.
If we go that route, I would plan to do it after this PR is merged.

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.

4 participants