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
uniform sampler2D m_ColorMap;
uniform float g_Time;
uniform float m_HitTime;
uniform float m_AlphaValue;
uniform vec4 m_GlowColor;
uniform vec4 m_FogColor;
uniform float m_FogIntensity;
uniform float m_HueShift;
vec4 color;
varying vec2 texCoord;
varying float vAlpha;
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
This file has been truncated. show original
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…
pspeed
May 28, 2021, 10:21am
3
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*
pspeed
May 28, 2021, 11:27am
5
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);
pspeed
May 28, 2021, 11:59am
7
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);
pspeed
May 28, 2021, 12:09pm
9
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