ShaderToy using BufferA as input to Buffer A

I’m trying to port a Shader Toy example over to Babylon JS.
I’ve had a lot of success generally, but the ones that I fail with are where you have Buffer chaining AND the Buffer is used as an input to iteself

Example: Shader - Shadertoy BETA

glDrawElements: Source and destination textures of the draw are the same.

Questions: How in Babylon, can I use the output of a shader as input to itself? Do I have to write/copy to a different buffer each time?

Yes and this is a webgl limitation. You have to copy it first

Can you point me to some key functions or examples that might shed some light for me on this?

The overall idea would be to have 2 textures. One source and one destination. At the end of each frame you copy destination to source. You can then always render to destination and always read from source

I think you can avoid the copy by doing a ping pong between 2 buffers A1 and A2: first write to A2 and use A1 as input, next frame write to A1 and use A2 as input. Rinse and repeat.

Thanks for the feedback again.

Can someone just give me a finger hold here, how to gain access to a PostProcess 's output buffer and to bind it to a standalone buffer?

Do you use effect.setTextureFromPostProcess?
or
effect.bindUniformBuffer
?

You should use setTextureFromPostProcess.

Thanks for the help so far. I’m really flunking out however.
I’m trying the ping pong approach, but frequently still getting the same error
Source and destination textures of the draw are the same

Some questions about how I should have this setup:
Is this whats being recommended with two Post process shaders that I try and ping pong?

const shader1 = new BABYLON.PostProcess("BufferA", `fragment`, [], ['iChannel0'], ratio, camera)
const shader2 = new BABYLON.PostProcess("BufferA", `fragment`, [], ['iChannel0'], ratio, camera)

shader1.onApply = (effect) => {
    effect.setTextureFromPostProcess("iChannel0", shader2);
}

shader2.onApply = (effect) => {
    effect.setTextureFromPostProcess("iChannel0", shader1);
}

const final = new BABYLON.PostProcess("ImageA", `final`, [], ['iChannel0'], ratio, camera)
let index = 0
final.onApply = (effect) => {

    effect.setTextureFromPostProcess("iChannel0", index === 0 ? shader1 : shader2);
    index = index == 0 ? 1 : 0
}

or I’m wondering is an alternative is to use the BABYLON.PassPostProcess


const shader1 = new BABYLON.PostProcess("BufferA", `fragment`, [], ['iChannel0'], ratio, camera)
const shaderPassThru = new BABYLON.PassPostProcess("Passthrough", ratio, camera)

shader1.onApply = (effect) => {
    effect.setTextureFromPostProcess("iChannel0", shaderPassThru);
}

const final = new BABYLON.PostProcess("ImageA", `final`, [], ['iChannel0'], ratio, camera)
final.onApply = (effect) => {
    effect.setTextureFromPostProcess("iChannel0", shaderPassThru);
}

You don’t have to use post processes for the ping pong textures, you can use regular textures (RenderTargetTexture). See for eg:

2 Likes

Yummy!

I think I’m really close. Thanks for the help.
playground: https://playground.babylonjs.com/#4C900K#13
original: Shader - Shadertoy BETA

Its really dark (blue on black), but can see the cracks split and separate out. Not sure why the bright components aren’t showing through (I don’t actually understand this shader) but I’ve got some traction at least.

Thanks again.

ShaderToy is using float textures whereas by default RenderTargetTexture are unsigned byte textures. If you use float textures it does work:

3 Likes

Thats a huge unlock for me. Thanks for all your help @Evgeni_Popov :ninja:

1 Like