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

preprocessor definitions inside a shadermaterial #2412

Closed
gero3 opened this issue Sep 12, 2012 · 7 comments
Closed

preprocessor definitions inside a shadermaterial #2412

gero3 opened this issue Sep 12, 2012 · 7 comments

Comments

@gero3
Copy link
Contributor

gero3 commented Sep 12, 2012

Introduction

This is a suggestion on how we could make use of preprocessor definitions inside a shadermaterial.

Why

I needed a shadermaterial that had more then 16 texture uniforms defined but depending on the configuration of my application only used 16 or less texture uniforms. So I needed the rebuild my shader sourcecode programmatically or I could make a definition system which used preprocessor definitions.

How

We add a new property to the object to define the preprocessor definitions called 'defines'. We also add another property to the uniforms called 'defined' which indicate by which preprocessor definitions they are defined.

Example

/*global THREE:true requestAnimationFrame:true shaders:true*/

var shaders = {
    splat:{
        defines : {"USE_DIFFUSE2" : true},
        uniforms:{
            "alpha1" : { type: "t", value: null },

            "diffuse1" : { type: "t", value: null },
            "multiplier1" : {type: "f", value: 16.0 },
            "offset1" : {type: "f", value: 0.5 },

            "diffuse2" : { type: "t", value: null, defined: "USE_DIFFUSE2"},
            "multiplier2" : {type: "f", value: 1.0, defined: "USE_DIFFUSE2" },
            "offset2" : {type: "f", value: 0, defined: "USE_DIFFUSE2"}

        },
        vertexShader:[
            "varying vec2 vUv;",
            "",
            "void main() {",
            "  ",
            "  vUv = uv;",
            "  vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
            "  gl_Position = projectionMatrix * mvPosition;",
            "  ",
            "}"
        ].join("\n"),
        fragmentShader:[
            "uniform sampler2D alpha1;",

            "uniform sampler2D diffuse1;",
            "uniform float multiplier1;",
            "uniform float offset1;",

            "#ifdef USE_DIFFUSE2",

            "  uniform sampler2D diffuse2;",
            "  uniform float multiplier2;",
            "  uniform float offset2;",
            "#endif",

            "varying vec2 vUv;",
            "",
            "void main() {",
            "  vec4 alphaBlend = texture2D( alpha1, vUv);",
            "  vec4 texel1 = texture2D( diffuse1, offset1 + vUv * multiplier1 );",
            "  #ifdef USE_DIFFUSE2",
            "    vec4 texel2 = texture2D( diffuse2, offset2 + vUv * multiplier2 );",
            "  #endif",
            "  gl_FragColor = texel1;",
            "}"
        ].join("\n")

    }

};

Consequence

  • When there are no defines, then the system stays the like it is now.
  • When a defines changes, then the program needs to be rebuild and the uniforms relocated.
  • There are 2 different kinds of defines: Boolean and Non-Boolean. Boolean defines are defined without value when true. Non-boolean are always defined with the value given.
@alteredq
Copy link
Contributor

I was already thinking about something like that, just it would be probably simpler, just passing in values for defines somehow, not any explicit interaction with uniforms.

Anyways unused uniforms should be detectable from GL API (we already use this quite a lot).

alteredq added a commit to alteredq/three.js that referenced this issue Sep 22, 2012
…Material.

For the moment tried to keep it as dumb as possible: one string for define label, another string for define value.

I'm not yet fully sure of all the details but that's something I wanted to do for a long time, to be able to have user-configurable way for baked-in parameters (for use cases like the convolution filter).

See mrdoob#2412
@gero3
Copy link
Contributor Author

gero3 commented Sep 24, 2012

I would love to have an update where it is possible to have preprocessor variables without a value.

function generateDefines ( defines ) {

  var chunk, chunks = [];
  for (var define in defines){
    if (defines[define] === true){
        chunks.push("#define " + define);
    } else if(defines[define] !== false && defines[define] != null){
        chunks.push("#define " + define + " " + defines[define]);
    }
  }

  return chunks.join("\n");
}

@mrdoob
Copy link
Owner

mrdoob commented Sep 24, 2012

@gero3 I think it's better as it's now. It's more explicit and easier to understand/learn as it currently is.

@alteredq
Copy link
Contributor

@gero3 So if I understood well your use case, what you would actually need is not to generate any #define when define[something] is false?

function generateDefines ( defines ) {

    var value, chunk, chunks = [];

    for ( var d in defines ) {

        value = defines[ d ];
        if ( value === false ) continue;

        chunk = "#define " + d + " " + value;
        chunks.push( chunk );

    }

    return chunks.join( "\n" );

};

@gero3
Copy link
Contributor Author

gero3 commented Sep 24, 2012

indeed as it makes more sense for boolean values

@alteredq
Copy link
Contributor

Yup, this should also work for true values.

So we would get this:

  • for false values there is no #define generated and code guarded by #ifdef SOMETHING would be excluded from the compiled shader
  • for true values we get #define SOMETHING true and code guarded by #ifdef SOMETHING would be included into the compiled shader

This would lead to nicer shader code than getting #define SOMETHING false and then needing to do #if defined(SOMETHING) && SOMETHING == true

@mrdoob
Copy link
Owner

mrdoob commented Sep 24, 2012

This would lead to nicer shader code than getting #define SOMETHING false and then needing to do #if defined(SOMETHING) && SOMETHING == true

Ah, I see. Makes sense.

alteredq added a commit to alteredq/three.js that referenced this issue Sep 25, 2012
@mrdoob mrdoob closed this as completed Sep 25, 2012
wvl pushed a commit to wvl/three.js that referenced this issue Nov 28, 2012
…ions to ShaderMaterial.

For the moment tried to keep it as dumb as possible: one string for define label, another string for define value.

I'm not yet fully sure of all the details but that's something I wanted to do for a long time, to be able to have user-configurable way for baked-in parameters (for use cases like the convolution filter).

See mrdoob#2412
wvl pushed a commit to wvl/three.js that referenced this issue Nov 28, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants