AlexB

Updating A Shader Material Frag Shader

Recommended Posts

I think I'll be posting a lot as we port from ThreeJS over to Babylon, so apologies.

Our application allows user input to affect the appears of a 3D object. A user can change out a material on an object. Sometimes, this means that the uniforms should change. For instance, we may want to use a structure like:

 

  struct Graphic {
      vec2 flip;
      vec2 offset;
      float rotation;
      vec2 scale;
      sampler2D texture;
      sampler2D normal;
 };

However, if the graphic does not have a normal texture, we don't need that texture slot so I'll write the structure on the fly like this:

 

  struct Graphic {
      vec2 flip;
      vec2 offset;
      float rotation;
      vec2 scale;
      sampler2D texture;
      vec3 normal;
  };

So when I create a ShaderMaterial, it allows me to send in a frag shader and a vertex shader as string, like so:

 

const material: any = new BABYLON.ShaderMaterial(
          name,
          scene,
          {
            vertex: 'some vertex',
            fragment: 'some fragment',
          },
          {
            // options
          }
        );

But how can I later update that frag shader with new text?

Something like:
material.fragmentShader = newFrag;

 

Thanks!


EDIT: It also looks like I can't just set the frag and vertex code as a string. Does it have to be wrapped somehow?

Share this post


Link to post
Share on other sites

Hello, welcome and no need for apologies :)

Regarding your question: as the shaders (both) are linked into a program, you have to rebuild it entirely so this means you will have to dispose the current material and creates a new one (Also I encourage you using defines as babylon.js will be able to optimize and cache effects for you)

Share this post


Link to post
Share on other sites

Update: I have a shader loading using the ShadersStore array.

 

 BABYLON.Effect.ShadersStore[`${part.url}FragmentShader`] = `
            precision highp float;
            varying vec2 vUV;


            struct Color {
              vec3 color
            }

            Color myColor;

            void main(void) {
              gl_FragColor = vec4(1., 0., 0., 1.);
            }
        `;

This works, and I can update the fragment shader. But it appears that Babylon doesn't support GLSL structures? Is there a way to access the shader uniforms directly?

Share this post


Link to post
Share on other sites

So by defines, you mean having conditional code in the same shader, but omitting one by setting a flag?

#ifdef HAS_METALROUGHNESSMAP

uniform sampler2D u_MetallicRoughnessSampler;

#endif

 

Share this post


Link to post
Share on other sites
12 minutes ago, Deltakosh said:

we support all glsl data structure and we are even using struct internally. So it should work

If you can repro in the Playground I will be able to probably help

I was referring to this bit of code in ShaderMaterial where it lists all the uniform types:

 

private _textureArrays: { [name: string]: Texture[] } = {};

private _floats: { [name: string]: number } = {};

private _ints: { [name: string]: number } = {};

private _floatsArrays: { [name: string]: number[] } = {};

private _colors3: { [name: string]: Color3 } = {};

private _colors3Arrays: { [name: string]: number[] } = {};

private _colors4: { [name: string]: Color4 } = {};

private _vectors2: { [name: string]: Vector2 } = {};

private _vectors3: { [name: string]: Vector3 } = {};

private _vectors4: { [name: string]: Vector4 } = {};

private _matrices: { [name: string]: Matrix } = {};

private _matrices3x3: { [name: string]: Float32Array } = {};

private _matrices2x2: { [name: string]: Float32Array } = {};

private _vectors2Arrays: { [name: string]: number[] } = {};

private _vectors3Arrays: { [name: string]: number[] } = {};

It doesn't appear that I can set a Struct type, like so:

https://www.babylonjs-playground.com/#ATDL99#1

* Note that I'm trying to use a myColor.color vec3 instead of fogColor

Share this post


Link to post
Share on other sites
13 minutes ago, Deltakosh said:

oh ok understood.. we were not on the same page :)

It is not supported you are right as this is not a basic type..But happy to merge a PR if you want to add it

Gotcha. I'll look into adding support for that. Would it just affect ShaderMaterial and the _checkUniform method? I don't quite understand all your code yet. It's changed a lot since I last used it 🙂

Share this post


Link to post
Share on other sites
4 hours ago, Deltakosh said:

I hope it is better now ;D

It will affect shaderMaterial and probably the effect class (which is used internally to communicate with shaders)

It turns out this is a harder problem than I thought. There is no low level method on the GL object to set structures, so what the ThreeJS implementation is doing is looping through a structure and discovering each type in a recursive loop. Then it applies each struct property one by one. I'm not sure I have time to figure it out. I got a good start on it if anyone wants to give it a try. I can push up a branch.

Share this post


Link to post
Share on other sites
28 minutes ago, Deltakosh said:

Are you sure you want to stick with a struct then?

I was hoping that adding support for structures would be faster than re-wiring my shader, but I think it'll be faster to just use arrays. But I'd still love to have support for structs at some point. They make the shaders way more readable, IMO.

Thanks for your help! 

Share this post


Link to post
Share on other sites

@AlexB

sorry, i have to pass on this one. my sketch
https://www.babylonjs-playground.com/#CNE3P8 


Babylonjs have a new shader system (or something like wise) you have to bind the uniform to createEffect not createShader somehow. Ask a questions in this forum, i have no idea how to use it.
http://doc.babylonjs.com/api/classes/babylon.engine#createshaderprogram
http://doc.babylonjs.com/api/classes/babylon.engine#createEffect


Good Luck

@Sebavan
Yeah

Share this post


Link to post
Share on other sites
On 6/19/2018 at 7:47 AM, AlexB said:

Can you give an example of how to use a uniform buffer object with Babylon? Our user base will all be on WebGL2 browsers.


I think this might help, if a uniform buffer object is the same as a VBO.

If I can find my grass simulation, it covers a lot of this... let me see if I can find that this morning when things slow down at the office.

Share this post


Link to post
Share on other sites

Whoa, I need to learn this!  Thank you. --- there are so many things to learn still with webGL, this never gets old.

*UPDATE*
Oh my... I needed to of know this days ago, wow... smh.

Share this post


Link to post
Share on other sites

just to be complite

WebGL1:  https://www.babylonjs-playground.com/#CNE3P8#2

And the babylonjs createEffect is listening to PostProcess

var postProcess = new BABYLON.PostProcess("My custom post process", "custom", ["Block"], null, 0.25, camera);
   
    postProcess.onApply = function (effect) {
    

        effect.bindUniformBlock(effect.getProgram(),"Block")
  

    };

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.