Skip to content

three-instanced-uniforms-mesh: add an ability to make varying non-interpolated (flat)#380

Open
upisfree wants to merge 2 commits intoprotectwise:mainfrom
upisfree:main
Open

three-instanced-uniforms-mesh: add an ability to make varying non-interpolated (flat)#380
upisfree wants to merge 2 commits intoprotectwise:mainfrom
upisfree:main

Conversation

@upisfree
Copy link

@upisfree upisfree commented Dec 23, 2025

I added an ability to make a varying non-interpolated, "flat".

Usage:

mesh.setUniformAt(uniformName, index, value, isFlat);

In my case I needed it to add 16 textures to the shader and have an ability to set the texture index.

@lojjic
Copy link
Collaborator

lojjic commented Dec 26, 2025

Nice addition! I wasn't aware of the flat varying glsl feature. 👍

Would you kindly add this to the documentation in the package's README.md?

@upisfree
Copy link
Author

Yes, I will add this to README 👌🏻

I thought, maybe it's better to pass options object instead of one variable in case we will add more options in future?
Something like this:

mesh.setUniformAt(uniformName, index, value, { isFlat: true });

@lojjic
Copy link
Collaborator

lojjic commented Dec 31, 2025

An options object is a good idea. 👍

I'm also wondering... should we make flat the default? That does seem like it's probably the usually expected behavior given that we're trying to mimic uniforms which wouldn't be interpolated. In that case we could still add an option {interpolate: true} just in case somebody was relying on that undocumented behavior.

@lojjic
Copy link
Collaborator

lojjic commented Jan 1, 2026

Thinking about this more... Can you give a concrete example of where interpolation would be occurring that is messing you up? It seems to me like all vertices within an instanced draw would be receiving the same attribute value, so any interpolation would be between the same number...? How would two vertices of a triangle receive different values?

@upisfree
Copy link
Author

upisfree commented Jan 7, 2026

should we make flat the default?

I think we should set flat: false (interpolate: true) by default because it's really rare when you don't need interpolation and my case is really niche. In my practice with shaders I needed flat: true only once.

Can you give a concrete example of where interpolation would be occurring that is messing you up?

So, usual case with interpolation looks like this: in vertex shader we determine vertex transform using attributes (where it stored in long buffer and glsl takes out correct transform for us), pass it to fragment shader using varying where glsl automatically interpolates values from in correct transform for each pixel inside out vertex. That's usual case looks like this (gradient is interpolated):
image

My niche case where I don't need interpolation looks like this: I wanted to render a lot of sprites with different textures using least amount of draw calls. I didn't want to use texture atlas because of high VRAM usage and inability to use pros of compressed textures. I knew that you can use up to 16 textures per shader program in webgl. So, my scheme is to use material with 16 texture slots. When it will fill up, spawn another material and add 1 draw call. I am managing texture slots, adding and removing material if they don't needed anymore.
So, I needed to pass 16 textures to material and choose right texture in fragment shader that's where interpolation breaks my code. I don't need texture indices to be interpolated, they must stay intact for each instance.

uniform sampler2D mapArray[16];
flat varying float mapIndex;

...

highp int mapIndexInt = int(mapIndex);

switch (mapIndexInt) {
    case 0:
        sampledDiffuseColor = texture2D(mapArray[0], flippedUv);
        break;
    case 1:
        sampledDiffuseColor = texture2D(mapArray[1], flippedUv);
        break;
    case 2:
        sampledDiffuseColor = texture2D(mapArray[2], flippedUv);
        break;
    case 3:
        sampledDiffuseColor = texture2D(mapArray[3], flippedUv);
        break;
    case 4:
        sampledDiffuseColor = texture2D(mapArray[4], flippedUv);
        break;
    case 5:
        sampledDiffuseColor = texture2D(mapArray[5], flippedUv);
        break;
    case 6:
        sampledDiffuseColor = texture2D(mapArray[6], flippedUv);
        break;
    case 7:
        sampledDiffuseColor = texture2D(mapArray[7], flippedUv);
        break;
    case 8:
        sampledDiffuseColor = texture2D(mapArray[8], flippedUv);
        break;
    case 9:
        sampledDiffuseColor = texture2D(mapArray[9], flippedUv);
        break;
    case 10:
        sampledDiffuseColor = texture2D(mapArray[10], flippedUv);
        break;
    case 11:
        sampledDiffuseColor = texture2D(mapArray[11], flippedUv);
        break;
    case 12:
        sampledDiffuseColor = texture2D(mapArray[12], flippedUv);
        break;
    case 13:
        sampledDiffuseColor = texture2D(mapArray[13], flippedUv);
        break;
    case 14:
        sampledDiffuseColor = texture2D(mapArray[14], flippedUv);
        break;
    case 15:
        sampledDiffuseColor = texture2D(mapArray[15], flippedUv);
        break;
}

If my explanations is not clear enough, I can provide more details.

@upisfree
Copy link
Author

upisfree commented Jan 7, 2026

By the way, now with uniform options it will be easy to add an ability to specify uniform type manually. Now, all uniforms are in Float32Array, but sometimes you need other types.

@upisfree
Copy link
Author

upisfree commented Jan 7, 2026

I added uniform options and info to README, but not sure is my explanations good enough...

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