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

[WIP] Add CubeTexture blur #30165

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
Open

[WIP] Add CubeTexture blur #30165

wants to merge 12 commits into from

Conversation

elalish
Copy link
Contributor

@elalish elalish commented Dec 19, 2024

The idea here is to make the PMREM cubemap blur function available as a generic public blur method for a CubeTexture. So far I only have a sketch, but this being my first attempt at using TSL, I've run into some early problems that I'd like to ask @sunag about.

Copy link

github-actions bot commented Dec 19, 2024

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 339.44
79.06
339.44
79.06
+0 B
+0 B
WebGPU 488.86
135.68
489.66
135.89
+798 B
+212 B
WebGPU Nodes 488.33
135.55
489.1
135.77
+775 B
+220 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 465.3
112.11
465.3
112.11
+0 B
+0 B
WebGPU 558.8
151.3
559.79
151.53
+996 B
+232 B
WebGPU Nodes 514.87
141.07
515.87
141.29
+996 B
+224 B

const cubeUVsampler=Fn((envMap, sampleDirection)=>{
return bilinearCubeUV( envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP );
});
material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ), sampler: cubeUVsampler } );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the heart of the refactor I'm attempting - make the sampling function something that can be passed in so I can use different ones for a CubeUV texture vs an actual CubeTexture.

src/nodes/pmrem/PMREMUtils.js Show resolved Hide resolved
@sunag
Copy link
Collaborator

sunag commented Dec 19, 2024

I'd like to ask @sunag about.

I can help with whatever you need :)

@elalish
Copy link
Contributor Author

elalish commented Dec 19, 2024

Thanks @sunag - that got me unstuck for a bit. However, in my last commit I'm trying to pull in some of the #29900 changes but I hit a weird error, this.value is null in the function below:

getTransformedUV( uvNode ) {

		if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix );

I would guess this has something to do with my outputDirection node, but I don't think I've changed anything about it? In any case, fodder for a clearer error message. Any thoughts?

@sunag
Copy link
Collaborator

sunag commented Dec 19, 2024

that got me unstuck for a bit. However, in my last commit I'm trying to pull in some of the #29900 changes but I hit a weird error, this.value is null in the function below:

I pushed a commit to fix set uniform value, this happened because texture( null ) is uniform, you can change the value by changing the .value property. But I think we can improve this error message.

@elalish
Copy link
Contributor Author

elalish commented Dec 19, 2024

Ah, thank you again! I don't know how you manage to develop all this without TS. I have the actual blur function written now - I just need to test it.

@elalish
Copy link
Contributor Author

elalish commented Dec 23, 2024

Okay, I might have this close to working, and I updated the new API with feedback from @mrdoob. However, upon trying to test it, I realized that CubeRenderTarget is not exported to the public API - it inherits from WebGLCubeRenderTarget which is, but that doesn't have any of the new TSL stuff. Where should this function be exposed?

@@ -6,6 +6,7 @@ export { default as Lighting } from './renderers/common/Lighting.js';
export { default as BundleGroup } from './renderers/common/BundleGroup.js';
export { default as QuadMesh } from './renderers/common/QuadMesh.js';
export { default as PMREMGenerator } from './renderers/common/extras/PMREMGenerator.js';
export { default as CubeRenderTarget } from './renderers/common/CubeRenderTarget.js';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure why this wasn't exported before for WebGPU - hopefully this is okay?

return envMap.sample( sampleDirection );

} );
blurMaterial.fragmentNode = blur( { n, latitudinal: latitudinal.equal( 1 ), poleAxis: vec3( poleAxis ), outputDirection: positionWorldDirection, weights, samples, dTheta, sampler: cubeSampler } );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sunag thanks for getting the PMREM version of this blur working - now this one is giving me trouble. I'm getting a lot of exceptions like getOutputNode( builder ) where builder is undefined. Also this line device.queue.writeBuffer( bufferGPU, 0, buffer, 0 ); is giving me TypeError: Overload resolution failed. which sounds pretty bad. I'm going to try to make a simpler repro in a three.js example instead of MV.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I think this is just async issues with WebGPURenderer in MV.

Copy link
Contributor Author

@elalish elalish left a comment

Choose a reason for hiding this comment

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

@mrdoob @sunag I got a bit further by hacking this function into an existing example, but I'm stuck again. I've gone ahead an put all my API feedback since this is my first venture into using WebGPURenderer and TSL.

@@ -72,6 +72,12 @@
cube2Texture.generateMipmaps = true;
cube2Texture.minFilter = THREE.LinearMipmapLinearFilter;

renderer = new THREE.WebGPURenderer( { antialias: true } );
await renderer.init();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was a quick fix to deal with an "uninitialized renderer" warning, which should maybe be an error since it just skips my shader entirely and makes a black texture? It also says I should use renderAsync, but i'm using camera.update, which doesn't seem to have an async version? Not sure why this hasn't been a problem for fromEquirectangularTexture...


import { WebGLCubeRenderTarget } from '../../renderers/WebGLCubeRenderTarget.js';
import { Scene } from '../../scenes/Scene.js';
import { CubeCamera } from '../../cameras/CubeCamera.js';
import { BoxGeometry } from '../../geometries/BoxGeometry.js';
import { Mesh } from '../../objects/Mesh.js';
import { BackSide, NoBlending, LinearFilter, LinearMipmapLinearFilter } from '../../constants.js';
import { cubeTexture as TSL_CubeTexture } from '../../nodes/accessors/CubeTextureNode.js';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is weird - when I tried to have a local variable named cubeTexture it didn't work - said it was a function instead (this one). Looks like it's getting properly renamed here, but apparently not? Is it somehow globally included somewhere?

return envMap.sample( sampleDirection );

} );
blurMaterial.fragmentNode = blur( { n, latitudinal: latitudinal.equal( 1 ), poleAxis: vec3( poleAxis ), outputDirection: positionWorldDirection, weights, samples, dTheta, sampler: cubeSampler } );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I think this is just async issues with WebGPURenderer in MV.


const camera = new CubeCamera( 1, 10, this );

const width = cubeTex.source.data[0].width;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've run into this issue before in Three (and complained about it) - this feels super fragile, but how am I supposed to find the size of a cubeTexture? Some have image, some have source, and I'm pretty sure if you generate one with a render target it has none? Seems like we're missing an API for this. Can we please just have a .size?

samples.value = blurParams2.samples;
dTheta.value = blurParams2.radiansPerPixel;

camera.update( renderer, scene );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now that this function is finally running I'm getting an exception that comes from here (oddly not the first camera.update call?): TypeError: Failed to execute 'writeBuffer' on 'GPUQueue': Overload resolution failed. No idea what to do with that.

await renderer.init();

const cube2Blur = new THREE.CubeRenderTarget(cube2Texture.source.data[0].width);
cube2Blur.fromCubeTexture(renderer, cube2Texture, 0.1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm throwing in a fixed-size blur for now to test - to have it hooked up to the backgroundBlur UI I believe we'll need some kind of cubeBlurNode that works a bit like pmremNode, automatically regenerating the texture as needed.

@elalish
Copy link
Contributor Author

elalish commented Dec 30, 2024

Since this is my last day at Google (and as a maintainer of MV, see google/model-viewer#4975) I don't think I'll get a chance to finish this PR. Hopefully it looks useful enough for someone else to pick up and push over the finish line. Thanks for all the help, @sunag! The TSL you've built is quite impressive, though hopefully by the time I play with it again it'll have a few more docs 😄.

@sunag
Copy link
Collaborator

sunag commented Dec 30, 2024

@elalish This news took me by surprise. You have done an incredible job over the years with MV and with all the improvements in physical-based materials, tone mapping, etc. I have always found your high level work and rich in detail, your work will certainly be missed by the community. I hope we can meet again on life's journey and I wish you all the best in your achievements.

@elalish
Copy link
Contributor Author

elalish commented Jan 5, 2025

Thanks a lot @sunag! If you ever find yourself in New Zealand, come visit.

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.

2 participants