TSL: Using the output of `pass()` in `.colorNode` in screen space

I’m trying to do a screen space effect using a custom material. I want the logo on the sphere in screen space, not mapped to the UVs of the model. I can do a screen space effect with the material using the screenUV node (e.g. a vertical split) but I want to try and use the output of a render pass instead.

Here is a fiddle:

 material.colorNode = Fn(() => {
        // This works, a screen space effect
        // const maskVal = step(0.5, screenUV.x);

        // This doesn't work, why can't i use the texture in screen space?
        // const maskVal = maskScenePass.getTextureNode().sample(screenUV).r
        
        // Using the pass like this works, but its mapped to the geometry
        const maskVal = maskScenePass.r;
        return mix(color(1,0,0), color(0,1,0), maskVal);
    })()

Is it possible to do this sort of thing or is this just fundamentally the wrong way to do it? Should I be using postprocessing instead? The fact that I can get the texture data onto the material makes me feel like there is a way to do this?

@sunag, any insights here? Thanks!

I think that with viewportSharedTexture() it is easier and more performant because it does not need multiple passes, it will obtain the texture of what has already been rendered.

const material = new THREE.NodeMaterial();
const customUV = screenUV.add( .1 ); /* add here your distortion effect, simple .1 offset to test*/
material.colorNode = viewportSharedTexture( customUV ).rgb;
material.transparent = true; // important to render-order

Nice, that’s working, thanks. Although for my actual use case I’m working with a more complicated scene where I may not have so much control over render order of the scene and this neat solution may not always apply. I’m also sometimes wanting to render the mask separately and not display the output in the scene. Do you have any idea why I can’t do something like this inside of material.colorNode?

maskVal = maskScenePass.getTextureNode().sample(screenUV).r

You can contextualize the UV, we prefer not to define at this time that it would be the screenUV because pass() could be used in the texture of a TV, for example. Try use:

maskVal = maskScenePass.context( { getUV: () => screenUV } );

maskScenePass.getTextureNode().sample(screenUV).r It could be an alternative, I think the system should solve this, or could, but I need to check.

1 Like

Wow it works, thanks! I understand that the API is still not fully done and this might not be the way later on, but thanks again for giving me this little tip :wink:

1 Like

Updated fiddle:

It has been fixed here.
If you wish to use your original approach :slight_smile:

1 Like

This is cool, thanks! I’ll give it a go for r179 and maybe even submit an example PR making use of it :wink: