Skip to content

NodeMaterial: Honor material.premultipliedAlpha in the shader #31166

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

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

WestLangley
Copy link
Collaborator

As the title says.

The alternative is to only add this code block in the built-in (node) materials -- as we do with WebGLRenderer's built-in materials.

@WestLangley WestLangley added this to the r177 milestone May 25, 2025
@WestLangley WestLangley changed the title NodeMaterial: Honor material.premultipliedAlpha in the shader NodeMaterial: Honor material.premultipliedAlpha in the shader May 25, 2025
Copy link

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 337.26
78.64
337.26
78.64
+0 B
+0 B
WebGPU 551.5
152.93
551.63
152.97
+129 B
+35 B
WebGPU Nodes 550.85
152.78
550.98
152.81
+129 B
+35 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 468.44
113.28
468.44
113.28
+0 B
+0 B
WebGPU 626.53
169.61
626.66
169.65
+129 B
+37 B
WebGPU Nodes 581.38
158.94
581.51
158.98
+129 B
+37 B

@Mugen87
Copy link
Collaborator

Mugen87 commented May 26, 2025

The E2E screenshot of webgpu_postprocessing_ssaa requires an update since SSAAPassNode already sets material.premultipliedAlpha to true (this has been adopted from the old SSAARenderPass).

@Mugen87
Copy link
Collaborator

Mugen87 commented May 27, 2025

The alternative is to only add this code block in the built-in (node) materials -- as we do with WebGLRenderer's built-in materials.

Since premultipliedAlpha is a Material property, I would expect it works with all materials. I prefer this new approach compared to support just for built-in materials.

@WestLangley
Copy link
Collaborator Author

Since premultipliedAlpha is a Material property, I would expect it works with all materials. I prefer this new approach compared to support just for built-in materials.

Well, yes, but maybe you misunderstand what its purpose is...

Material.premultipliedAlpha is a hint to the renderer that the output of the shader returns premultiplied color values. That way, the renderer will set the proper blending function. It works for all materials.

In the case of built-in materials, the shader itself must also be modified to return premultiplied values instead of non-premultiplied values.

So built-in materials and custom materials are different in this regard.

Unfortunately, Material.premultipliedAlpha is serving double-duty and affects both the blending function (for all materials), and the shader itself (for built-in materials only).

@mrdoob mrdoob modified the milestones: r177, r178 May 30, 2025
@Mugen87
Copy link
Collaborator

Mugen87 commented May 31, 2025

Yeah, the double purpose of premultipliedAlpha came along in the past multiple times. But why do you think is it unfortunate? If the blending assumes premultiplied colors, the materials should honor that setting and produce the correct output in their shaders. Regardless of built-in or custom materials (this distinction isn't that relevant for node materials anyway).

The node material seems a good opportunity to establish a policy that produce more consistent outputs no matter if you customize a material or not.

AFAICS, if the developer needs full control, it's always possible to use custom blending, don't change premultipliedAlpha and then apply a custom color transformation in the shader.

@WestLangley
Copy link
Collaborator Author

Material.premultipliedAlpha is serving double-duty

But why do you think it is unfortunate?

Consider this use case:

renderer.setRenderTarget( renderTarget ); 
renderer.render( scene, camera );

In such a case, renderTarget.texture will have RGB premultiplied by alpha.

Now, use the render target texture as a map:

const material = new THREE.MeshBasicMaterial( {

	map: rederTarget.texture

} );

The material shader will outut premultiplied colors, but the renderer will use the wrong blending function.

So, try this instead:

const material = new THREE.MeshBasicMaterial( {

	map: rederTarget.texture,

	premultipliedAlpha: true

} );

Now this is wrong because the shader will pre-multiply the colors a second time.

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.

3 participants