Issue with my spritesheet shader

I’ve made a spritesheet shader, which works fairly well except for with some number combinations.

For example, when:

m_SizeX = 7
m_SizeY = 7
m_Position = 14

Then I don’t see the “sprite” rendered. I think there’s some numeric or rounding issue but I can’t figure it out:

uniform mat4 g_WorldViewProjectionMatrix;
uniform float m_SizeX;
uniform float m_SizeY;
uniform float m_Position;
uniform float m_FlipHorizontal;

attribute vec3 inPosition;
attribute vec2 inTexCoord;
attribute float inTexCoord2;
attribute float inTexCoord3;

varying float vAlpha;
varying vec2 texCoord;

void main(){

    float t = m_Position;
    #ifdef HAS_VERTEXSHEETPOS
        t = inTexCoord2;
        vAlpha = inTexCoord3;
    #endif
    float tPointerY = 1.0 - ((floor(t / m_SizeX)) / m_SizeY) - 1.0 / m_SizeY;
    float tPointerYOffset = (floor(t / m_SizeX)) / m_SizeY;
    float tPointerX = (t - (tPointerYOffset * m_SizeX * m_SizeY)) / m_SizeX;
    if (m_FlipHorizontal == 1.0 ) {
        texCoord.x = ( 1.0 - inTexCoord.x ) / m_SizeX + tPointerX;
    }
    else {
        texCoord.x = inTexCoord.x / m_SizeX + tPointerX;
    }
    texCoord.y = inTexCoord.y / m_SizeY + tPointerY;

    gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);
}

The .j3md is here

and the fragment shader is here

1 Like

Could this possibly be related to the “power of two” size texture rule? The texture is 1807x1807

Wait, for real??? Need to check why this odd size…

I have a little trouble making sense of your math. Can you explain how you expect your atlas to be laid out?

1 Like

A square, going left to right and top to bottom:

* 0 * 1 *  2 * 3  *  4 * 5 * 6 *
* 7 * 8 *  9 * 10 * 11 * 12* 13*
...
*42 * 43* 44 * 45 * 46 * 47* 48*

Just seemed weird not to floor() your division of m_SizeY like you do for m_SizeX. I think it’s because you ultimately want it to be 0…1 anyway but it makes the tPointerX calculation feel weird to me. I haven’t unrolled it all to see if it’s a problem but I’ve gotten into similar issue myself where I was letting a fractional part slip through and it was making some cells blank (because my texture was clamped and I was outside 0…1).

It probably doesn’t hurt to break out the atlas location separately and make sure that’s correct before relative-sampling from it.

0,0 at bottom version:

yAtlas = floor(t / m_SizeY);
xAtlas = t - (yAtlas * m_SizeY);

This makes sure the fractional parts don’t bleed into the other equations.

Then I think texture coordinates are:

vec2 uv = vec2(xAtlas + inTexCoord.x, yAtlas + inTexCoord.y) / vec2(m_SizeX, m_SizeY);

In your case, flip the yAtlas value as needed. (m_SizeY - 1 - yAtlas or whatever)

1 Like

Ahem… this code don’t render anything at all. What did I miss?

    float t = m_Position;
    #ifdef HAS_VERTEXSHEETPOS
        t = inTexCoord2;
        vAlpha = inTexCoord3;
    #endif
    /*
    float tPointerY = 1.0 - ((floor(t / m_SizeX)) / m_SizeY) - 1.0 / m_SizeY;
    float tPointerYOffset = (floor(t / m_SizeX)) / m_SizeY;
    float tPointerX = (t - (tPointerYOffset * m_SizeX * m_SizeY)) / m_SizeX;
    if (m_FlipHorizontal == 1.0 ) {
        texCoord.x = ( 1.0 - inTexCoord.x ) / m_SizeX + tPointerX;
    }
    else {
        texCoord.x = inTexCoord.x / m_SizeX + tPointerX;
    }
    texCoord.y = inTexCoord.y / m_SizeY + tPointerY;
*/
    float yAtlas = floor(t / m_SizeY);
    float xAtlas = t - (yAtlas * m_SizeY);
    vec2 uv = vec2(xAtlas + inTexCoord.x, yAtlas + inTexCoord.y) / vec2(m_SizeX, m_SizeY);

    //gl_Position = (m_SizeY - 1.0 - yAtlas);
    gl_Position = g_WorldViewProjectionMatrix * vec4(uv, 1.0, 1.0);

Wait… why are you using the new texCoord (that I called ‘uv’ in my sample) for calculating the vertex position?

I think I need to put something into glPosition?

gl_Position = (uv, 1.0, 1.0);//g_WorldViewProjectionMatrix * vec4(uv, 1.0, 1.0);

Why not use what was there before?

You know… clearly we are speaking about totally different things if it wasn’t obvious that ‘uv’ was shorthand for texCoord.

texCoord = uv;

So I’m going to drop out until I have more time. Hopefully someone else can help.

1 Like

Ok thanks! Now the code look way cleaner, but works exactly like before.

If:

m_SizeX = 7
m_SizeY = 7
m_Position = 14

And the spritesheet is 1807x1807

Then I don’t see the “sprite” rendered.

Updated code:

uniform mat4 g_WorldViewProjectionMatrix;
uniform float m_SizeX;
uniform float m_SizeY;
uniform float m_Position;
uniform float m_FlipHorizontal;

attribute vec3 inPosition;
attribute vec2 inTexCoord;
attribute float inTexCoord2;
attribute float inTexCoord3;

varying float vAlpha;
varying vec2 texCoord;

void main(){

    float t = m_Position;
    #ifdef HAS_VERTEXSHEETPOS
        t = inTexCoord2;
        vAlpha = inTexCoord3;
    #endif
    float yAtlas = floor(t / m_SizeY);
    float xAtlas = t - (yAtlas * m_SizeY);

    texCoord = vec2(xAtlas + inTexCoord.x, (m_SizeY - 1.0 - yAtlas) + inTexCoord.y) / vec2(m_SizeX, m_SizeY);

    gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);
}

I’ve “solved” the issue by making the spritesheet a power of 2.

1 Like